root / toolbox / serial.c @ e8960789
History | View | Annotate | Download (1.45 KB)
1 |
#include <stdint.h> |
---|---|
2 |
#include <avr/io.h> |
3 |
#include <avr/interrupt.h> |
4 |
#include "serial.h" |
5 |
|
6 |
static int rx_start = 0, rx_end = 0; |
7 |
static uint8_t rx_buffer[RX_BUFFER_SIZE];
|
8 |
|
9 |
ISR(USART1_RX_vect) { |
10 |
uint8_t data = UDR1; |
11 |
int new_end = rx_end+1; |
12 |
if (new_end == RX_BUFFER_SIZE) {
|
13 |
new_end = 0;
|
14 |
} |
15 |
if (new_end == rx_start) {
|
16 |
// TODO warn of buffer overflow?
|
17 |
} else {
|
18 |
rx_buffer[rx_end] = data; |
19 |
rx_end = new_end; |
20 |
} |
21 |
} |
22 |
|
23 |
void serial_init() {
|
24 |
// baud = F_CPU / (div (UBRR + 1))
|
25 |
// where div = 16 if U2X = 0, or 8 otherwise
|
26 |
uint16_t ubrr = F_CPU / 8 / BAUD_RATE - 1; |
27 |
UBRR1H = ubrr >> 8;
|
28 |
UBRR1L = ubrr; |
29 |
// UMSEL = 0, asynchronous usart
|
30 |
// UPM = 0, parity check disabled
|
31 |
// USBS = 0, 1 stop bit
|
32 |
// UCSZ = 3, 8-bit
|
33 |
// U2X = 1, use 8 prescale instead of 16 for a more accurate baud rate
|
34 |
UCSR1A = _BV(U2X1); |
35 |
UCSR1B = _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1); |
36 |
UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); |
37 |
} |
38 |
|
39 |
int serial_read() {
|
40 |
int ret;
|
41 |
cli(); |
42 |
if (rx_start == rx_end) {
|
43 |
ret = -1;
|
44 |
} else {
|
45 |
ret = rx_buffer[rx_start]; |
46 |
rx_start++; |
47 |
if (rx_start == RX_BUFFER_SIZE) {
|
48 |
rx_start = 0;
|
49 |
} |
50 |
} |
51 |
sei(); |
52 |
return ret;
|
53 |
} |
54 |
|
55 |
void serial_flush() {
|
56 |
cli(); |
57 |
rx_start = 0;
|
58 |
rx_end = 0;
|
59 |
sei(); |
60 |
} |
61 |
|
62 |
uint8_t serial_read_blocking() { |
63 |
int c;
|
64 |
do {
|
65 |
c = serial_read(); |
66 |
} while (c < 0); |
67 |
return c;
|
68 |
} |
69 |
|
70 |
void serial_write(uint8_t* data, int length) { |
71 |
int i;
|
72 |
for (i = 0; i < length; i++) { |
73 |
while (!(UCSR1A & _BV(UDRE1)));
|
74 |
UDR1 = data[i]; |
75 |
} |
76 |
} |