]> www.fi.muni.cz Git - scxreader.git/blob - uart.c
scxreader.sch: schematics in gschem
[scxreader.git] / uart.c
1 /*
2  * Minimalistic TX-only compile-time configured asynchronous buffered
3  * UART communication for Arduino Nano (Atmega 88/168/328).
4  */
5 #include <avr/io.h>
6 #include <avr/interrupt.h>
7 #include <util/atomic.h>
8 #include <util/delay.h>
9
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
14
15 #define TX_BUFFER_MASK  (TX_BUFFER-1)
16
17 #if (TX_BUFFER & TX_BUFFER_MASK)
18 #error TX buffer size TX_BUFFER must be a power of two
19 #endif
20
21 #ifndef F_CPU
22 #error F_CPU not defined, set it in Makefile
23 #endif
24
25 #define UBRR_VAL        ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
26
27 static volatile unsigned char buffer[TX_BUFFER];
28 static volatile unsigned char b_head, b_tail, b_overrun;
29 /*
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
33  */
34
35 void uart_init()
36 {
37         UBRR0H = (unsigned char)(UBRR_VAL >> 8);
38         UBRR0L = (unsigned char)(UBRR_VAL & 0xFF);
39
40         UCSR0C = _BV(USBS0) | _BV(UCSZ00) | _BV(UCSZ01);
41         UCSR0B = _BV(TXEN0); // enable TX only
42
43         b_head = 0;
44         b_tail = 0;
45         b_overrun = 0;
46 }
47
48 ISR(USART_UDRE_vect) // tx end irq
49 {
50         // maybe handle overrun here?
51         if (b_head == b_tail) { // queue empty
52                 UCSR0B &= ~_BV(UDRIE0); // disable IRQ
53         } else {
54                 UDR0 = buffer[b_tail];
55                 b_tail = (b_tail + 1) & TX_BUFFER_MASK;
56         }
57 }
58
59 // low-level byte sending
60 unsigned char uart_tx_byte(unsigned char byte, unsigned char wait)
61 {
62         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
63         retry:
64                 if (((b_head + 1) & TX_BUFFER_MASK) == b_tail) {
65                         if (wait) {
66                                 NONATOMIC_BLOCK(NONATOMIC_FORCEOFF) {
67                                         while (((b_head + 1) & TX_BUFFER_MASK)
68                                                 == b_tail)
69                                                 ;
70                                 }
71                                 goto retry;
72                         }
73
74                         b_overrun = 1;
75                         return 0;
76                 }
77
78                 buffer[b_head] = byte;
79                 b_head = (b_head + 1) & TX_BUFFER_MASK;
80
81                 UCSR0B |= _BV(UDRIE0);
82         }
83         return 1;
84 }
85
86 // ASCII hex bytes, for debugging purposes
87
88 #define hex_nibble(x) ((x) < 10 ? '0' + (x) : 'A' + (x) - 10)
89
90 unsigned char uart_tx_hex(unsigned char byte, unsigned char wait)
91 {
92         if (
93                    uart_tx_byte(hex_nibble(byte >> 4), wait)
94                 && uart_tx_byte(hex_nibble(byte & 0xF), wait)
95         )
96                 return 1;
97         else
98                 return 0;
99 }
100
101 unsigned char uart_tx_hex2(unsigned short word, unsigned char wait)
102 {
103         if (
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)
108         )
109                 return 1;
110         else
111                 return 0;
112 }
113