1 /*************************************************************************
\r
2 Title: Interrupt UART library with receive/transmit circular buffers
\r
3 Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
\r
4 File: $Id: uart.c,v 1.5.2.10 2005/11/15 19:49:12 peter Exp $
\r
5 Software: AVR-GCC 3.3
\r
6 Hardware: any AVR with built-in UART,
\r
7 tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz
\r
10 An interrupt is generated when the UART has finished transmitting or
\r
11 receiving a byte. The interrupt handling routines use circular buffers
\r
12 for buffering received and transmitted data.
\r
14 The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define
\r
15 the buffer size in bytes. Note that these variables must be a
\r
19 Refere to the header file uart.h for a description of the routines.
\r
20 See also example test_uart.c.
\r
23 Based on Atmel Application Note AVR306
\r
25 *************************************************************************/
\r
27 #include <avr/interrupt.h>
\r
28 // #include <avr/signal.h>
\r
29 #include <avr/pgmspace.h>
\r
34 * constants and macros
\r
37 /* size of RX/TX buffers */
\r
38 #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)
\r
39 #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
\r
41 #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
\r
42 #error RX buffer size is not a power of 2
\r
44 #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
\r
45 #error TX buffer size is not a power of 2
\r
48 #if defined(__AVR_AT90S2313__) \
\r
49 || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \
\r
50 || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \
\r
51 || defined(__AVR_ATmega103__)
\r
52 /* old AVR classic or ATmega103 with one UART */
\r
54 #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
\r
55 #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
\r
56 #define UART0_STATUS USR
\r
57 #define UART0_CONTROL UCR
\r
58 #define UART0_DATA UDR
\r
59 #define UART0_UDRIE UDRIE
\r
60 #elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
\r
61 /* old AVR classic with one UART */
\r
63 #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
\r
64 #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
\r
65 #define UART0_STATUS UCSRA
\r
66 #define UART0_CONTROL UCSRB
\r
67 #define UART0_DATA UDR
\r
68 #define UART0_UDRIE UDRIE
\r
69 #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
\r
70 || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \
\r
71 || defined(__AVR_ATmega323__)
\r
72 /* ATmega with one USART */
\r
73 #define ATMEGA_USART
\r
74 #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
\r
75 #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
\r
76 #define UART0_STATUS UCSRA
\r
77 #define UART0_CONTROL UCSRB
\r
78 #define UART0_DATA UDR
\r
79 #define UART0_UDRIE UDRIE
\r
80 #elif defined(__AVR_ATmega163__)
\r
81 /* ATmega163 with one UART */
\r
83 #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
\r
84 #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
\r
85 #define UART0_STATUS UCSRA
\r
86 #define UART0_CONTROL UCSRB
\r
87 #define UART0_DATA UDR
\r
88 #define UART0_UDRIE UDRIE
\r
89 #elif defined(__AVR_ATmega162__)
\r
90 /* ATmega with two USART */
\r
91 #define ATMEGA_USART0
\r
92 #define ATMEGA_USART1
\r
93 #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV
\r
94 #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV
\r
95 #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA
\r
96 #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA
\r
97 #define UART0_STATUS UCSR0A
\r
98 #define UART0_CONTROL UCSR0B
\r
99 #define UART0_DATA UDR0
\r
100 #define UART0_UDRIE UDRIE0
\r
101 #define UART1_STATUS UCSR1A
\r
102 #define UART1_CONTROL UCSR1B
\r
103 #define UART1_DATA UDR1
\r
104 #define UART1_UDRIE UDRIE1
\r
105 #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
\r
106 /* ATmega with two USART */
\r
107 #define ATMEGA_USART0
\r
108 #define ATMEGA_USART1
\r
109 #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV
\r
110 #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV
\r
111 #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA
\r
112 #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA
\r
113 #define UART0_STATUS UCSR0A
\r
114 #define UART0_CONTROL UCSR0B
\r
115 #define UART0_DATA UDR0
\r
116 #define UART0_UDRIE UDRIE0
\r
117 #define UART1_STATUS UCSR1A
\r
118 #define UART1_CONTROL UCSR1B
\r
119 #define UART1_DATA UDR1
\r
120 #define UART1_UDRIE UDRIE1
\r
121 #elif defined(__AVR_ATmega161__)
\r
122 /* ATmega with UART */
\r
123 #error "AVR ATmega161 currently not supported by this libaray !"
\r
124 #elif defined(__AVR_ATmega169__)
\r
125 /* ATmega with one USART */
\r
126 #define ATMEGA_USART
\r
127 #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV
\r
128 #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA
\r
129 #define UART0_STATUS UCSRA
\r
130 #define UART0_CONTROL UCSRB
\r
131 #define UART0_DATA UDR
\r
132 #define UART0_UDRIE UDRIE
\r
133 #elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega644__)
\r
134 #define ATMEGA_USART0
\r
135 #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV
\r
136 #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA
\r
137 #define UART0_STATUS UCSR0A
\r
138 #define UART0_CONTROL UCSR0B
\r
139 #define UART0_DATA UDR0
\r
140 #define UART0_UDRIE UDRIE0
\r
141 #elif defined(__AVR_ATtiny2313__)
\r
142 #define ATMEGA_USART
\r
143 #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX
\r
144 #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE
\r
145 #define UART0_STATUS UCSRA
\r
146 #define UART0_CONTROL UCSRB
\r
147 #define UART0_DATA UDR
\r
148 #define UART0_UDRIE UDRIE
\r
150 #error "no UART definition for MCU available"
\r
155 * module global variables
\r
157 static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
\r
158 static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
\r
159 static volatile unsigned char UART_TxHead;
\r
160 static volatile unsigned char UART_TxTail;
\r
161 static volatile unsigned char UART_RxHead;
\r
162 static volatile unsigned char UART_RxTail;
\r
163 static volatile unsigned char UART_LastRxError;
\r
165 #if defined( ATMEGA_USART1 )
\r
166 static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];
\r
167 static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];
\r
168 static volatile unsigned char UART1_TxHead;
\r
169 static volatile unsigned char UART1_TxTail;
\r
170 static volatile unsigned char UART1_RxHead;
\r
171 static volatile unsigned char UART1_RxTail;
\r
172 static volatile unsigned char UART1_LastRxError;
\r
177 SIGNAL(UART0_RECEIVE_INTERRUPT)
\r
178 /*************************************************************************
\r
179 Function: UART Receive Complete interrupt
\r
180 Purpose: called when the UART has received a character
\r
181 **************************************************************************/
\r
183 unsigned char tmphead;
\r
184 unsigned char data;
\r
186 unsigned char lastRxError;
\r
189 /* read UART status register and UART data register */
\r
190 usr = UART0_STATUS;
\r
194 #if defined( AT90_UART )
\r
195 lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
\r
196 #elif defined( ATMEGA_USART )
\r
197 lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
\r
198 #elif defined( ATMEGA_USART0 )
\r
199 lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
\r
200 #elif defined ( ATMEGA_UART )
\r
201 lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
\r
204 /* calculate buffer index */
\r
205 tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
\r
207 if ( tmphead == UART_RxTail ) {
\r
208 /* error: receive buffer overflow */
\r
209 lastRxError = UART_BUFFER_OVERFLOW >> 8;
\r
211 /* store new index */
\r
212 UART_RxHead = tmphead;
\r
213 /* store received data in buffer */
\r
214 UART_RxBuf[tmphead] = data;
\r
216 UART_LastRxError = lastRxError;
\r
220 SIGNAL(UART0_TRANSMIT_INTERRUPT)
\r
221 /*************************************************************************
\r
222 Function: UART Data Register Empty interrupt
\r
223 Purpose: called when the UART is ready to transmit the next byte
\r
224 **************************************************************************/
\r
226 unsigned char tmptail;
\r
229 if ( UART_TxHead != UART_TxTail) {
\r
230 /* calculate and store new buffer index */
\r
231 tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
\r
232 UART_TxTail = tmptail;
\r
233 /* get one byte from buffer and write it to UART */
\r
234 UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */
\r
236 /* tx buffer empty, disable UDRE interrupt */
\r
237 UART0_CONTROL &= ~_BV(UART0_UDRIE);
\r
242 /*************************************************************************
\r
243 Function: uart_init()
\r
244 Purpose: initialize UART and set baudrate
\r
245 Input: baudrate using macro UART_BAUD_SELECT()
\r
247 **************************************************************************/
\r
248 void uart_init(unsigned int baudrate)
\r
255 #if defined( AT90_UART )
\r
256 /* set baud rate */
\r
257 UBRR = (unsigned char)baudrate;
\r
259 /* enable UART receiver and transmmitter and receive complete interrupt */
\r
260 UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);
\r
262 #elif defined (ATMEGA_USART)
\r
263 /* Set baud rate */
\r
264 if ( baudrate & 0x8000 )
\r
266 UART0_STATUS = (1<<U2X); //Enable 2x speed
\r
267 baudrate &= ~0x8000;
\r
269 UBRRH = (unsigned char)(baudrate>>8);
\r
270 UBRRL = (unsigned char) baudrate;
\r
272 /* Enable USART receiver and transmitter and receive complete interrupt */
\r
273 UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
\r
275 /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
\r
277 UCSRC = (1<<URSEL)|(3<<UCSZ0);
\r
279 UCSRC = (3<<UCSZ0);
\r
282 #elif defined (ATMEGA_USART0 )
\r
283 /* Set baud rate */
\r
284 if ( baudrate & 0x8000 )
\r
286 UART0_STATUS = (1<<U2X0); //Enable 2x speed
\r
287 baudrate &= ~0x8000;
\r
289 UBRR0H = (unsigned char)(baudrate>>8);
\r
290 UBRR0L = (unsigned char) baudrate;
\r
292 /* Enable USART receiver and transmitter and receive complete interrupt */
\r
293 UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
\r
295 /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
\r
297 UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
\r
299 UCSR0C = (3<<UCSZ00);
\r
302 #elif defined ( ATMEGA_UART )
\r
303 /* set baud rate */
\r
304 if ( baudrate & 0x8000 )
\r
306 UART0_STATUS = (1<<U2X); //Enable 2x speed
\r
307 baudrate &= ~0x8000;
\r
309 UBRRHI = (unsigned char)(baudrate>>8);
\r
310 UBRR = (unsigned char) baudrate;
\r
312 /* Enable UART receiver and transmitter and receive complete interrupt */
\r
313 UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
\r
320 /*************************************************************************
\r
321 Function: uart_getc()
\r
322 Purpose: return byte from ringbuffer
\r
323 Returns: lower byte: received byte from ringbuffer
\r
324 higher byte: last receive error
\r
325 **************************************************************************/
\r
326 unsigned int uart_getc(void)
\r
328 unsigned char tmptail;
\r
329 unsigned char data;
\r
332 if ( UART_RxHead == UART_RxTail ) {
\r
333 return UART_NO_DATA; /* no data available */
\r
336 /* calculate /store buffer index */
\r
337 tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
\r
338 UART_RxTail = tmptail;
\r
340 /* get data from receive buffer */
\r
341 data = UART_RxBuf[tmptail];
\r
343 return (UART_LastRxError << 8) + data;
\r
348 /*************************************************************************
\r
349 Function: uart_putc()
\r
350 Purpose: write byte to ringbuffer for transmitting via UART
\r
351 Input: byte to be transmitted
\r
353 **************************************************************************/
\r
354 void uart_putc(unsigned char data)
\r
356 unsigned char tmphead;
\r
359 tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
\r
361 while ( tmphead == UART_TxTail ){
\r
362 ;/* wait for free space in buffer */
\r
365 UART_TxBuf[tmphead] = data;
\r
366 UART_TxHead = tmphead;
\r
368 /* enable UDRE interrupt */
\r
369 UART0_CONTROL |= _BV(UART0_UDRIE);
\r
374 /*************************************************************************
\r
375 Function: uart_puts()
\r
376 Purpose: transmit string to UART
\r
377 Input: string to be transmitted
\r
379 **************************************************************************/
\r
380 void uart_puts(const char *s )
\r
388 /*************************************************************************
\r
389 Function: uart_puts_p()
\r
390 Purpose: transmit string from program memory to UART
\r
391 Input: program memory string to be transmitted
\r
393 **************************************************************************/
\r
394 void uart_puts_p(const char *progmem_s )
\r
398 while ( (c = pgm_read_byte(progmem_s++)) )
\r
405 * these functions are only for ATmegas with two USART
\r
407 #if defined( ATMEGA_USART1 )
\r
409 SIGNAL(UART1_RECEIVE_INTERRUPT)
\r
410 /*************************************************************************
\r
411 Function: UART1 Receive Complete interrupt
\r
412 Purpose: called when the UART1 has received a character
\r
413 **************************************************************************/
\r
415 unsigned char tmphead;
\r
416 unsigned char data;
\r
418 unsigned char lastRxError;
\r
421 /* read UART status register and UART data register */
\r
422 usr = UART1_STATUS;
\r
426 lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) );
\r
428 /* calculate buffer index */
\r
429 tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;
\r
431 if ( tmphead == UART1_RxTail ) {
\r
432 /* error: receive buffer overflow */
\r
433 lastRxError = UART_BUFFER_OVERFLOW >> 8;
\r
435 /* store new index */
\r
436 UART1_RxHead = tmphead;
\r
437 /* store received data in buffer */
\r
438 UART1_RxBuf[tmphead] = data;
\r
440 UART1_LastRxError = lastRxError;
\r
444 SIGNAL(UART1_TRANSMIT_INTERRUPT)
\r
445 /*************************************************************************
\r
446 Function: UART1 Data Register Empty interrupt
\r
447 Purpose: called when the UART1 is ready to transmit the next byte
\r
448 **************************************************************************/
\r
450 unsigned char tmptail;
\r
453 if ( UART1_TxHead != UART1_TxTail) {
\r
454 /* calculate and store new buffer index */
\r
455 tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;
\r
456 UART1_TxTail = tmptail;
\r
457 /* get one byte from buffer and write it to UART */
\r
458 UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */
\r
460 /* tx buffer empty, disable UDRE interrupt */
\r
461 UART1_CONTROL &= ~_BV(UART1_UDRIE);
\r
466 /*************************************************************************
\r
467 Function: uart1_init()
\r
468 Purpose: initialize UART1 and set baudrate
\r
469 Input: baudrate using macro UART_BAUD_SELECT()
\r
471 **************************************************************************/
\r
472 void uart1_init(unsigned int baudrate)
\r
480 /* Set baud rate */
\r
481 if ( baudrate & 0x8000 )
\r
483 UART1_STATUS = (1<<U2X1); //Enable 2x speed
\r
484 baudrate &= ~0x8000;
\r
486 UBRR1H = (unsigned char)(baudrate>>8);
\r
487 UBRR1L = (unsigned char) baudrate;
\r
489 /* Enable USART receiver and transmitter and receive complete interrupt */
\r
490 UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1);
\r
492 /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
\r
494 UCSR1C = (1<<URSEL1)|(3<<UCSZ10);
\r
496 UCSR1C = (3<<UCSZ10);
\r
501 /*************************************************************************
\r
502 Function: uart1_getc()
\r
503 Purpose: return byte from ringbuffer
\r
504 Returns: lower byte: received byte from ringbuffer
\r
505 higher byte: last receive error
\r
506 **************************************************************************/
\r
507 unsigned int uart1_getc(void)
\r
509 unsigned char tmptail;
\r
510 unsigned char data;
\r
513 if ( UART1_RxHead == UART1_RxTail ) {
\r
514 return UART_NO_DATA; /* no data available */
\r
517 /* calculate /store buffer index */
\r
518 tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;
\r
519 UART1_RxTail = tmptail;
\r
521 /* get data from receive buffer */
\r
522 data = UART1_RxBuf[tmptail];
\r
524 return (UART1_LastRxError << 8) + data;
\r
529 /*************************************************************************
\r
530 Function: uart1_putc()
\r
531 Purpose: write byte to ringbuffer for transmitting via UART
\r
532 Input: byte to be transmitted
\r
534 **************************************************************************/
\r
535 void uart1_putc(unsigned char data)
\r
537 unsigned char tmphead;
\r
540 tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;
\r
542 while ( tmphead == UART1_TxTail ){
\r
543 ;/* wait for free space in buffer */
\r
546 UART1_TxBuf[tmphead] = data;
\r
547 UART1_TxHead = tmphead;
\r
549 /* enable UDRE interrupt */
\r
550 UART1_CONTROL |= _BV(UART1_UDRIE);
\r
555 /*************************************************************************
\r
556 Function: uart1_puts()
\r
557 Purpose: transmit string to UART1
\r
558 Input: string to be transmitted
\r
560 **************************************************************************/
\r
561 void uart1_puts(const char *s )
\r
569 /*************************************************************************
\r
570 Function: uart1_puts_p()
\r
571 Purpose: transmit string from program memory to UART1
\r
572 Input: program memory string to be transmitted
\r
574 **************************************************************************/
\r
575 void uart1_puts_p(const char *progmem_s )
\r
579 while ( (c = pgm_read_byte(progmem_s++)) )
\r
582 }/* uart1_puts_p */
\r