/* * Minimalistic TX-only compile-time configured asynchronous buffered * UART communication for Arduino Nano (Atmega 88/168/328). */ #include #include #include #include // user settable parameters start #define UART_BAUD 115200 #define TX_BUFFER (1 << 4) // this has to be a power of two // user settable parameters end #define TX_BUFFER_MASK (TX_BUFFER-1) #if (TX_BUFFER & TX_BUFFER_MASK) #error TX buffer size TX_BUFFER must be a power of two #endif #ifndef F_CPU #error F_CPU not defined, set it in Makefile #endif #define UBRR_VAL ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1) static volatile unsigned char buffer[TX_BUFFER]; static volatile unsigned char b_head, b_tail, b_overrun; /* * b_head == b_tail: empty queue * b_head + 1 == b_tail: full queue * b_overrun is set but not currently handled in any way */ void uart_init() { UBRR0H = (unsigned char)(UBRR_VAL >> 8); UBRR0L = (unsigned char)(UBRR_VAL & 0xFF); UCSR0C = _BV(USBS0) | _BV(UCSZ00) | _BV(UCSZ01); UCSR0B = _BV(TXEN0); // enable TX only b_head = 0; b_tail = 0; b_overrun = 0; } ISR(USART_UDRE_vect) // tx end irq { // maybe handle overrun here? if (b_head == b_tail) { // queue empty UCSR0B &= ~_BV(UDRIE0); // disable IRQ } else { UDR0 = buffer[b_tail]; b_tail = (b_tail + 1) & TX_BUFFER_MASK; } } // low-level byte sending unsigned char uart_tx_byte(unsigned char byte, unsigned char wait) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { retry: if (((b_head + 1) & TX_BUFFER_MASK) == b_tail) { if (wait) { NONATOMIC_BLOCK(NONATOMIC_FORCEOFF) { while (((b_head + 1) & TX_BUFFER_MASK) == b_tail) ; } goto retry; } b_overrun = 1; return 0; } buffer[b_head] = byte; b_head = (b_head + 1) & TX_BUFFER_MASK; UCSR0B |= _BV(UDRIE0); } return 1; } // ASCII hex bytes, for debugging purposes #define hex_nibble(x) ((x) < 10 ? '0' + (x) : 'A' + (x) - 10) unsigned char uart_tx_hex(unsigned char byte, unsigned char wait) { if ( uart_tx_byte(hex_nibble(byte >> 4), wait) && uart_tx_byte(hex_nibble(byte & 0xF), wait) ) return 1; else return 0; } unsigned char uart_tx_hex2(unsigned short word, unsigned char wait) { if ( uart_tx_byte(hex_nibble((word >> 12) & 0xF), wait) && uart_tx_byte(hex_nibble((word >> 8) & 0xF), wait) && uart_tx_byte(hex_nibble((word >> 4) & 0xF), wait) && uart_tx_byte(hex_nibble( word & 0xF), wait) ) return 1; else return 0; }