2 * Loosely modelled after AVR-RS485 by Yoshinori Kohyama (http://algobit.jp/),
3 * available at https://github.com/kohyama/AVR-RS485/
5 * All bugs by Jan "Yenya" Kasprzak <kas@fi.muni.cz> :-)
9 #include <avr/interrupt.h>
10 #include <util/delay.h>
12 #define BUFSIZE 128 // must be a power of two
14 // configure the control pin
15 #define ctl_pin_setup() do { DDRD |= _BV(PD2); } while (0)
16 #define ctl_pin_on() do { PORTD |= _BV(PD2); } while (0)
17 #define ctl_pin_off() do { PORTD &= ~_BV(PD2); } while (0)
19 #define BUFMASK (BUFSIZE-1)
20 #if (BUFSIZE & BUFMASK)
21 #error BUFSIZE must be a power of two
25 typedef uint16_t bufptr_t;
27 typedef uint8_t bufptr_t;
30 #define bufptr_inc(x) ((x + 1) & BUFMASK)
32 static volatile bufptr_t rx_head, rx_tail, tx_head, tx_tail;
33 static volatile char rxbuf[BUFSIZE], txbuf[BUFSIZE];
35 #define UART_BAUD 9600
36 #define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
40 rx_head = rx_tail = 0;
41 tx_head = tx_tail = 0;
48 UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
49 UCSR0C = _BV(UCSZ01)|_BV(UCSZ00);
52 void rs485_send(char *p)
61 next = bufptr_inc(tx_head);
62 while (next != tx_tail && *p != '\0') {
63 txbuf[tx_head] = *p++;
65 next = bufptr_inc(tx_head);
68 UCSR0B |= _BV(UDRIE0);
72 bufptr_t rs485_readln(char *buf, bufptr_t size)
78 while (rx_head != rx_tail && n + 1 < size) {
79 buf[n++] = rxbuf[rx_tail];
80 rx_tail = bufptr_inc(rx_tail);
83 } while (n == 0 || buf[n - 1] != 0x0a);
94 next = bufptr_inc(rx_head);
95 rxbuf[rx_head] = UDR0;
103 UCSR0B &= ~_BV(TXCIE0); // disable further IRQs
110 if (tx_head == tx_tail) {
111 UCSR0B |= _BV(TXCIE0); // enable xmit complete irq
112 UCSR0B &= ~_BV(UDRIE0);
114 UDR0 = txbuf[tx_tail];
115 tx_tail = bufptr_inc(tx_tail);