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