aboutsummaryrefslogtreecommitdiff
path: root/drivers/avr/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/avr/uart.c')
-rw-r--r--drivers/avr/uart.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/drivers/avr/uart.c b/drivers/avr/uart.c
new file mode 100644
index 000000000..e866a9e4f
--- /dev/null
+++ b/drivers/avr/uart.c
@@ -0,0 +1,170 @@
1/* UART Example for Teensy USB Development Board
2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2009 PJRC.COM, LLC
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24// Version 1.0: Initial Release
25// Version 1.1: Add support for Teensy 2.0, minor optimizations
26
27#include <avr/io.h>
28#include <avr/interrupt.h>
29
30#include "uart.h"
31
32#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
33# define UDRn UDR1
34# define UBRRnL UBRR1L
35# define UCSRnA UCSR1A
36# define UCSRnB UCSR1B
37# define UCSRnC UCSR1C
38# define U2Xn U2X1
39# define RXENn RXEN1
40# define TXENn TXEN1
41# define RXCIEn RXCIE1
42# define UCSZn1 UCSZ11
43# define UCSZn0 UCSZ10
44# define UDRIEn UDRIE1
45# define USARTn_UDRE_vect USART1_UDRE_vect
46# define USARTn_RX_vect USART1_RX_vect
47#elif defined(__AVR_ATmega32A__)
48# define UDRn UDR
49# define UBRRnL UBRRL
50# define UCSRnA UCSRA
51# define UCSRnB UCSRB
52# define UCSRnC UCSRC
53# define U2Xn U2X
54# define RXENn RXEN
55# define TXENn TXEN
56# define RXCIEn RXCIE
57# define UCSZn1 UCSZ1
58# define UCSZn0 UCSZ0
59# define UDRIEn UDRIE
60# define USARTn_UDRE_vect USART_UDRE_vect
61# define USARTn_RX_vect USART_RX_vect
62#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
63# define UDRn UDR0
64# define UBRRnL UBRR0L
65# define UCSRnA UCSR0A
66# define UCSRnB UCSR0B
67# define UCSRnC UCSR0C
68# define U2Xn U2X0
69# define RXENn RXEN0
70# define TXENn TXEN0
71# define RXCIEn RXCIE0
72# define UCSZn1 UCSZ01
73# define UCSZn0 UCSZ00
74# define UDRIEn UDRIE0
75# define USARTn_UDRE_vect USART_UDRE_vect
76# define USARTn_RX_vect USART_RX_vect
77#endif
78
79// These buffers may be any size from 2 to 256 bytes.
80#define RX_BUFFER_SIZE 64
81#define TX_BUFFER_SIZE 256
82
83static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];
84static volatile uint8_t tx_buffer_head;
85static volatile uint8_t tx_buffer_tail;
86static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
87static volatile uint8_t rx_buffer_head;
88static volatile uint8_t rx_buffer_tail;
89
90// Initialize the UART
91void uart_init(uint32_t baud) {
92 cli();
93 UBRRnL = (F_CPU / 4 / baud - 1) / 2;
94 UCSRnA = (1 << U2Xn);
95 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn);
96 UCSRnC = (1 << UCSZn1) | (1 << UCSZn0);
97 tx_buffer_head = tx_buffer_tail = 0;
98 rx_buffer_head = rx_buffer_tail = 0;
99 sei();
100}
101
102// Transmit a byte
103void uart_putchar(uint8_t c) {
104 uint8_t i;
105
106 i = tx_buffer_head + 1;
107 if (i >= TX_BUFFER_SIZE) i = 0;
108 // return immediately to avoid deadlock when interrupt is disabled(called from ISR)
109 if (tx_buffer_tail == i && (SREG & (1 << SREG_I)) == 0) return;
110 while (tx_buffer_tail == i)
111 ; // wait until space in buffer
112 // cli();
113 tx_buffer[i] = c;
114 tx_buffer_head = i;
115 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn);
116 // sei();
117}
118
119// Receive a byte
120uint8_t uart_getchar(void) {
121 uint8_t c, i;
122
123 while (rx_buffer_head == rx_buffer_tail)
124 ; // wait for character
125 i = rx_buffer_tail + 1;
126 if (i >= RX_BUFFER_SIZE) i = 0;
127 c = rx_buffer[i];
128 rx_buffer_tail = i;
129 return c;
130}
131
132// Return whether the number of bytes waiting in the receive buffer is nonzero.
133// Call this before uart_getchar() to check if it will need
134// to wait for a byte to arrive.
135bool uart_available(void) {
136 uint8_t head, tail;
137
138 head = rx_buffer_head;
139 tail = rx_buffer_tail;
140 if (head >= tail) return (head - tail) > 0;
141 return (RX_BUFFER_SIZE + head - tail) > 0;
142}
143
144// Transmit Interrupt
145ISR(USARTn_UDRE_vect) {
146 uint8_t i;
147
148 if (tx_buffer_head == tx_buffer_tail) {
149 // buffer is empty, disable transmit interrupt
150 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn);
151 } else {
152 i = tx_buffer_tail + 1;
153 if (i >= TX_BUFFER_SIZE) i = 0;
154 UDRn = tx_buffer[i];
155 tx_buffer_tail = i;
156 }
157}
158
159// Receive Interrupt
160ISR(USARTn_RX_vect) {
161 uint8_t c, i;
162
163 c = UDRn;
164 i = rx_buffer_head + 1;
165 if (i >= RX_BUFFER_SIZE) i = 0;
166 if (i != rx_buffer_tail) {
167 rx_buffer[i] = c;
168 rx_buffer_head = i;
169 }
170}