1 | #include "uart.h"
|
2 | #include <avr/io.h>
|
3 | #include <avr/pgmspace.h>
|
4 | #include <avr/interrupt.h>
|
5 |
|
6 | #define SEND_BUF_BITS 4
|
7 | #define SEND_BUF_SIZE (1<<SEND_BUF_BITS)
|
8 | #define SEND_BUF_MASK (SEND_BUF_SIZE-1)
|
9 | #define RECV_BUF_BITS 2
|
10 | #define RECV_BUF_SIZE (1<<RECV_BUF_BITS)
|
11 | #define RECV_BUF_MASK (RECV_BUF_SIZE-1)
|
12 |
|
13 |
|
14 | static volatile uint8_t send_buf_start;
|
15 | static uint8_t send_buf_end;
|
16 | static char send_buf[SEND_BUF_SIZE];
|
17 |
|
18 | static uint8_t recv_buf_start;
|
19 | static volatile uint8_t recv_buf_end;
|
20 | static char recv_buf[RECV_BUF_SIZE];
|
21 |
|
22 |
|
23 | void uart_init(uint16_t baud) {
|
24 | // ifdef ATTINY...
|
25 | UCSRA = _BV(U2X);
|
26 | UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE); //UART TX+RX einschalten
|
27 | UCSRC |= _BV(UCSZ0)|_BV(UCSZ1); //Asynchron 8N1
|
28 | UBRRH=(uint8_t)((baud)>>8);
|
29 | UBRRL=(uint8_t)(baud);
|
30 |
|
31 | send_buf_start=0;
|
32 | send_buf_end=0;
|
33 | recv_buf_start=0;
|
34 | recv_buf_end=0;
|
35 | }
|
36 | void uart_putc(char c)
|
37 | {
|
38 | uint8_t next_pos=(send_buf_end+1)&SEND_BUF_MASK;
|
39 |
|
40 | // wait till we got space in buffer
|
41 | while ((SREG & _BV(SREG_I)) && (next_pos == send_buf_start));
|
42 |
|
43 | if (next_pos == send_buf_start) {
|
44 | // Interrupts are disabled and buffer is full. we loose this char.
|
45 | return;
|
46 | }
|
47 |
|
48 | send_buf[send_buf_end]=c;
|
49 |
|
50 | send_buf_end=next_pos;
|
51 |
|
52 | // Enable UDR interrupt. will immediatly call ISR if UDRE is set.
|
53 | UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(UDRIE) | _BV(RXCIE);
|
54 | }
|
55 |
|
56 | void uart_write(const char * c) {
|
57 | while (*c) {
|
58 | uart_putc(*c++);
|
59 | }
|
60 | }
|
61 | void uart_write_P(const char * c) {
|
62 | char ch;
|
63 | do {
|
64 | ch=pgm_read_byte(c++);
|
65 | if (!ch) return;
|
66 | uart_putc(ch);
|
67 | } while(1);
|
68 | }
|
69 | char uart_getc(void) {
|
70 | // Wait till byte in buffer
|
71 | while(recv_buf_start == recv_buf_end);
|
72 | char x=recv_buf[recv_buf_start++];
|
73 | recv_buf_start &=RECV_BUF_MASK;
|
74 | return x;
|
75 | }
|
76 |
|
77 | uint8_t uart_recv_buf_size(void) {
|
78 | if (recv_buf_end >= recv_buf_start) {
|
79 | return recv_buf_end - recv_buf_start;
|
80 | }
|
81 | return recv_buf_end + RECV_BUF_SIZE - recv_buf_start;
|
82 | }
|
83 |
|
84 | uint8_t uart_send_buf_size(void) {
|
85 | if (send_buf_end >= send_buf_start) {
|
86 | return send_buf_end - send_buf_start;
|
87 | }
|
88 | return send_buf_end + SEND_BUF_SIZE - send_buf_start;
|
89 | }
|
90 | ISR(USART_RX_vect) {
|
91 | recv_buf[recv_buf_end]=UDR;
|
92 |
|
93 | recv_buf_end=(recv_buf_end+1)&RECV_BUF_MASK;
|
94 |
|
95 | if (recv_buf_end == recv_buf_start) {
|
96 | // Overflow! drop the first byte of the recv_buf.
|
97 | recv_buf_start=(recv_buf_start+1)&RECV_BUF_MASK;
|
98 | }
|
99 | }
|
100 |
|
101 | ISR(USART_UDRE_vect) {
|
102 | if (send_buf_end == send_buf_start) {
|
103 | // No data to send, disable ISR.
|
104 | UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE);
|
105 | } else {
|
106 | UDR=send_buf[send_buf_start++];
|
107 | send_buf_start &=SEND_BUF_MASK;
|
108 | }
|
109 | }
|