renamed to emurom
[romdev] / fw / src / serial.c
1 #ifndef F_CPU
2 #ifdef XTAL
3 #define F_CPU   XTAL
4 #else
5 #warning "compiled for 1mhz internal rc osc. serial comms won't work"
6 #define F_CPU   1000000
7 #endif
8 #endif
9
10 #include <stdio.h>
11 #include <avr/io.h>
12 #include <avr/interrupt.h>
13 #include <util/delay.h>
14 #include <avr/power.h>
15
16 static int uart_send_char(char c, FILE *fp);
17 static int uart_get_char(FILE *fp);
18
19 #define BUF_SZ  16
20 #define BUF_IDX_MASK    (BUF_SZ - 1)
21 #define NEXT_IDX(x)     (((x) + 1) & BUF_IDX_MASK)
22 static char outbuf[BUF_SZ];
23 static volatile unsigned char out_rd, out_wr;
24 static char inbuf[BUF_SZ];
25 static volatile unsigned char in_rd, in_wr;
26
27 static FILE std_stream = FDEV_SETUP_STREAM(uart_send_char, uart_get_char, _FDEV_SETUP_RW);
28
29
30
31 void init_serial(long baud)
32 {
33         unsigned int ubrr_val = F_CPU / 16 / baud - 1;
34
35         power_usart0_enable();
36
37         /* set baud generator timer reset value */
38         UBRR0H = (unsigned char)(ubrr_val >> 8);
39         UBRR0L = (unsigned char)ubrr_val;
40
41         /* enable rx/tx and recv interrupt */
42         UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
43         /* set frame format: 8n1 */
44         UCSR0C = 3 << UCSZ00;
45
46         stdin = stdout = stderr = &std_stream;
47 }
48
49 int have_input(void)
50 {
51         return in_wr != in_rd;
52 }
53
54 static int uart_send_char(char c, FILE *fp)
55 {
56         /*int next;*/
57         if(c == '\n') uart_send_char('\r', fp);
58
59         while((UCSR0A & (1 << UDRE0)) == 0);
60         UDR0 = (unsigned char)c;
61 #if 0
62         next = NEXT_IDX(out_wr);
63         while(next == out_rd);
64
65         outbuf[out_wr] = c;
66         out_wr = next;
67
68         /* enable the Tx data register empty interrupt */
69         UCSR0B |= 1 << UDRIE0;
70 #endif
71         return 0;
72 }
73
74 static int uart_get_char(FILE *fp)
75 {
76         char c;
77
78         while(in_rd == in_wr);
79
80         c = inbuf[in_rd];
81         in_rd = NEXT_IDX(in_rd);
82         return c;
83 }
84
85 ISR(USART_RX_vect)
86 {
87         char c = UDR0;
88
89         inbuf[in_wr] = c;
90         in_wr = NEXT_IDX(in_wr);
91 }
92
93 /* USART Tx data register empty (can send more data) */
94 ISR(USART_UDRE_vect)
95 {
96         if(out_rd != out_wr) {
97                 UDR0 = outbuf[out_rd];
98                 out_rd = NEXT_IDX(out_rd);
99         } else {
100                 /* no more data to send for now, disable the interrupt */
101                 UCSR0B &= ~(1 << UDRIE0);
102         }
103 }