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/atomic.h>
11 #include <util/delay.h>
13 #define BUFSIZE 128 // must be a power of two
15 // configure the control pin
16 #define ctl_pin_setup() do { DDRD |= _BV(PD2); } while (0)
17 #define ctl_pin_on() do { PORTD |= _BV(PD2); } while (0)
18 #define ctl_pin_off() do { PORTD &= ~_BV(PD2); } while (0)
20 #define BUFMASK (BUFSIZE-1)
21 #if (BUFSIZE & BUFMASK)
22 #error BUFSIZE must be a power of two
26 typedef uint16_t bufptr_t;
28 typedef uint8_t bufptr_t;
31 #define bufptr_inc(x) ((x + 1) & BUFMASK)
33 static volatile bufptr_t rx_bytes, tx_head, tx_tail;
34 static volatile uint8_t rxbuf[BUFSIZE], txbuf[BUFSIZE];
35 static volatile uint16_t last_rx;
36 static volatile uint8_t unit_id;
38 #define UART_BAUD 9600
39 #define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
40 #define wait_one_byte() _delay_us(10*1000000/UART_BAUD)
42 #define get_clock() (TCNT1)
43 #define CLOCK_SPEED (F_CPU/1024)
45 * According to Wikipedia, it is indeed 28 bits = 3.5 bytes without
46 * start- and stopbits.
48 #define TIMEOUT (28*CLOCK_SPEED/UART_BAUD)
53 tx_head = tx_tail = 0;
62 UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
63 UCSR0C = _BV(UCSZ01)|_BV(UCSZ00);
66 void rs485_send(char *p)
73 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
74 next = bufptr_inc(tx_head);
75 while (next != tx_tail && *p != '\0') {
76 txbuf[tx_head] = *p++;
78 next = bufptr_inc(tx_head);
81 UCSR0B |= _BV(UDRIE0);
85 static uint16_t compute_crc(volatile uint8_t *buf, bufptr_t len)
88 uint16_t crc = 0xFFFF;
90 for (i = 0; i < len; i++) {
92 crc ^= (uint16_t)(buf[i]);
93 for(j = 0; j < 8; j++) {
106 static void make_exception(uint8_t func, uint8_t code)
108 txbuf[tx_head++] = unit_id;
109 txbuf[tx_head++] = func | 0x80;
110 txbuf[tx_head++] = code;
118 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
119 if (rx_bytes == 0) // nothing received yet
122 if (get_clock() - last_rx < TIMEOUT) // still receiving
125 if (rx_bytes < 4) { // too short
130 if (rxbuf[0] != unit_id) { // not for myself
135 if (tx_tail) { // still sending?
140 packet_len = rx_bytes; // make a copy
143 crc = compute_crc(rxbuf, packet_len - 2);
145 if ((crc & 0xFF) != rxbuf[packet_len-2]
146 || (crc >> 8) != rxbuf[packet_len-1]) // bad crc
151 switch (rxbuf[1]) { // function
153 make_exception(rxbuf[1], 1); // illegal function
158 crc = compute_crc(txbuf, tx_head);
159 txbuf[tx_head++] = crc & 0xFF;
160 txbuf[tx_head++] = crc >> 8;
165 UCSR0B |= _BV(UDRIE0);
168 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
175 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
176 rxbuf[rx_bytes] = UDR0;
177 if (rx_bytes + 1 < BUFSIZE) // ignore overruns
179 last_rx = get_clock();
185 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
186 if (tx_head == tx_tail) {
187 UCSR0B &= ~_BV(UDRIE0);
188 tx_tail = tx_head = 0;
189 wait_one_byte(); // FIXME: too long busy-wait
192 UDR0 = txbuf[tx_tail];
193 tx_tail = bufptr_inc(tx_tail);