2 * Minimalistic TX-only compile-time configured asynchronous buffered
3 * UART communication for Arduino Nano (Atmega 88/168/328).
6 #include <avr/interrupt.h>
7 #include <util/atomic.h>
8 #include <util/delay.h>
10 // user settable parameters start
11 #define UART_BAUD 115200
12 #define TX_BUFFER (1 << 4) // this has to be a power of two
13 // user settable parameters end
15 #define TX_BUFFER_MASK (TX_BUFFER-1)
17 #if (TX_BUFFER & TX_BUFFER_MASK)
18 #error TX buffer size TX_BUFFER must be a power of two
22 #error F_CPU not defined, set it in Makefile
25 #define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
27 static volatile unsigned char buffer[TX_BUFFER];
28 static volatile unsigned char b_head, b_tail, b_overrun;
30 * b_head == b_tail: empty queue
31 * b_head + 1 == b_tail: full queue
32 * b_overrun is set but not currently handled in any way
37 UBRR0H = (unsigned char)(UBRR_VAL >> 8);
38 UBRR0L = (unsigned char)(UBRR_VAL & 0xFF);
40 UCSR0C = _BV(USBS0) | _BV(UCSZ00) | _BV(UCSZ01);
41 UCSR0B = _BV(TXEN0); // enable TX only
48 ISR(USART_UDRE_vect) // tx end irq
50 // maybe handle overrun here?
51 if (b_head == b_tail) { // queue empty
52 UCSR0B &= ~_BV(UDRIE0); // disable IRQ
54 UDR0 = buffer[b_tail];
55 b_tail = (b_tail + 1) & TX_BUFFER_MASK;
59 // low-level byte sending
60 unsigned char uart_tx_byte(unsigned char byte, unsigned char wait)
62 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
64 if (((b_head + 1) & TX_BUFFER_MASK) == b_tail) {
66 NONATOMIC_BLOCK(NONATOMIC_FORCEOFF) {
67 while (((b_head + 1) & TX_BUFFER_MASK)
78 buffer[b_head] = byte;
79 b_head = (b_head + 1) & TX_BUFFER_MASK;
81 UCSR0B |= _BV(UDRIE0);
86 // ASCII hex bytes, for debugging purposes
88 #define hex_nibble(x) ((x) < 10 ? '0' + (x) : 'A' + (x) - 10)
90 unsigned char uart_tx_hex(unsigned char byte, unsigned char wait)
93 uart_tx_byte(hex_nibble(byte >> 4), wait)
94 && uart_tx_byte(hex_nibble(byte & 0xF), wait)
101 unsigned char uart_tx_hex2(unsigned short word, unsigned char wait)
104 uart_tx_byte(hex_nibble((word >> 12) & 0xF), wait)
105 && uart_tx_byte(hex_nibble((word >> 8) & 0xF), wait)
106 && uart_tx_byte(hex_nibble((word >> 4) & 0xF), wait)
107 && uart_tx_byte(hex_nibble( word & 0xF), wait)