]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/serial.c
use env var 'baudrate'
[z180-stamp.git] / avr / serial.c
1 /*
2 */
3
4 #include <avr/io.h>
5 #include <avr/interrupt.h>
6 #include <util/atomic.h>
7 #include <errno.h>
8 #include <stdio.h>
9
10 #include "ring.h"
11 #include "serial.h"
12
13
14 static int _write(char c, FILE *stream);
15 static FILE mystdout = FDEV_SETUP_STREAM(_write,
16 NULL, _FDEV_SETUP_WRITE);
17
18
19
20 #define BUFFER_SIZE 64
21
22 #if ((BUFFER_SIZE-1) & BUFFER_SIZE)
23 # error: BUFFER_SIZE not power of 2
24 #endif
25
26 #if ((BUFFER_SIZE) > 256)
27 # error: BUFFER_SIZE
28 #endif
29
30 struct ring rx_ring;
31 struct ring tx_ring;
32 uint8_t rx_ring_buffer[BUFFER_SIZE];
33 uint8_t tx_ring_buffer[BUFFER_SIZE];
34
35
36
37 /* Initialize UART */
38
39 void usart0_setup(unsigned long baud) {
40
41 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
42
43 PRR0 &= ~_BV(PRUSART0);
44 UCSR0B = 0;
45
46 /* Initialize ring buffers. */
47 ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE);
48 ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE);
49
50 UCSR0A = 0;
51 UBRR0 = F_CPU / baud / 16 - 1;
52 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
53 UCSR0C = 3 << UCSZ00;
54 };
55 }
56
57 /*--------------------------------------------------------------------------*/
58
59 /* UART RXC interrupt */
60
61 ISR(USART0_RX_vect)
62 {
63 uint8_t d;
64
65 d = UDR0;
66 ring_write_ch(&rx_ring, d);
67 }
68
69 /* UART UDRE interrupt */
70
71 ISR(USART0_UDRE_vect)
72 {
73 int d = ring_read_ch(&tx_ring);
74
75 if (d < 0) {
76 /* Disable TX empty interrupt. */
77 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
78 } else {
79 UDR0 = d;
80 }
81 }
82
83 /*--------------------------------------------------------------------------*/
84
85 void serial_setup(unsigned long baud)
86 {
87 stdout = &mystdout;
88 usart0_setup(baud);
89 }
90
91 /*--------------------------------------------------------------------------*/
92
93 int _write(char c, FILE *stream)
94 {
95 (void) stream;
96
97 if (c == '\n')
98 serial_putc('\r');
99 serial_putc(c);
100
101 return 0;
102 }
103
104 int serial_getc(void)
105 {
106 return ring_read_ch(&rx_ring);
107 }
108
109 void serial_putc(char data)
110 {
111 while (ring_write_ch(&tx_ring, data) < 0)
112 ;
113
114 /* Enable the TXE interrupt. */
115 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0) | _BV(UDRIE0);
116 }
117
118 uint_fast8_t serial_tstc(void)
119 {
120 return !ring_is_empty(&rx_ring);
121 }
122
123