+/*************************************************************************\r
+Title: Interrupt UART library with receive/transmit circular buffers\r
+Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury\r
+File: $Id: uart.c,v 1.5.2.10 2005/11/15 19:49:12 peter Exp $\r
+Software: AVR-GCC 3.3 \r
+Hardware: any AVR with built-in UART, \r
+ tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz\r
+\r
+DESCRIPTION:\r
+ An interrupt is generated when the UART has finished transmitting or\r
+ receiving a byte. The interrupt handling routines use circular buffers\r
+ for buffering received and transmitted data.\r
+ \r
+ The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define\r
+ the buffer size in bytes. Note that these variables must be a \r
+ power of 2.\r
+ \r
+USAGE:\r
+ Refere to the header file uart.h for a description of the routines. \r
+ See also example test_uart.c.\r
+\r
+NOTES:\r
+ Based on Atmel Application Note AVR306\r
+ \r
+*************************************************************************/\r
+#include <avr/io.h>\r
+#include <avr/interrupt.h>\r
+// #include <avr/signal.h>\r
+#include <avr/pgmspace.h>\r
+#include "uart.h"\r
+\r
+\r
+/*\r
+ * constants and macros\r
+ */\r
+\r
+/* size of RX/TX buffers */\r
+#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)\r
+#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)\r
+\r
+#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )\r
+#error RX buffer size is not a power of 2\r
+#endif\r
+#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )\r
+#error TX buffer size is not a power of 2\r
+#endif\r
+\r
+#if defined(__AVR_AT90S2313__) \\r
+ || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \\r
+ || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \\r
+ || defined(__AVR_ATmega103__)\r
+ /* old AVR classic or ATmega103 with one UART */\r
+ #define AT90_UART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA\r
+ #define UART0_STATUS USR\r
+ #define UART0_CONTROL UCR\r
+ #define UART0_DATA UDR \r
+ #define UART0_UDRIE UDRIE\r
+#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)\r
+ /* old AVR classic with one UART */\r
+ #define AT90_UART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA\r
+ #define UART0_STATUS UCSRA\r
+ #define UART0_CONTROL UCSRB\r
+ #define UART0_DATA UDR \r
+ #define UART0_UDRIE UDRIE\r
+#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \\r
+ || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \\r
+ || defined(__AVR_ATmega323__)\r
+ /* ATmega with one USART */\r
+ #define ATMEGA_USART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA\r
+ #define UART0_STATUS UCSRA\r
+ #define UART0_CONTROL UCSRB\r
+ #define UART0_DATA UDR\r
+ #define UART0_UDRIE UDRIE\r
+#elif defined(__AVR_ATmega163__) \r
+ /* ATmega163 with one UART */\r
+ #define ATMEGA_UART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA\r
+ #define UART0_STATUS UCSRA\r
+ #define UART0_CONTROL UCSRB\r
+ #define UART0_DATA UDR\r
+ #define UART0_UDRIE UDRIE\r
+#elif defined(__AVR_ATmega162__)\r
+ /* ATmega with two USART */\r
+ #define ATMEGA_USART0\r
+ #define ATMEGA_USART1\r
+ #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV\r
+ #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA\r
+ #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA\r
+ #define UART0_STATUS UCSR0A\r
+ #define UART0_CONTROL UCSR0B\r
+ #define UART0_DATA UDR0\r
+ #define UART0_UDRIE UDRIE0\r
+ #define UART1_STATUS UCSR1A\r
+ #define UART1_CONTROL UCSR1B\r
+ #define UART1_DATA UDR1\r
+ #define UART1_UDRIE UDRIE1\r
+#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \r
+ /* ATmega with two USART */\r
+ #define ATMEGA_USART0\r
+ #define ATMEGA_USART1\r
+ #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV\r
+ #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA\r
+ #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA\r
+ #define UART0_STATUS UCSR0A\r
+ #define UART0_CONTROL UCSR0B\r
+ #define UART0_DATA UDR0\r
+ #define UART0_UDRIE UDRIE0\r
+ #define UART1_STATUS UCSR1A\r
+ #define UART1_CONTROL UCSR1B\r
+ #define UART1_DATA UDR1\r
+ #define UART1_UDRIE UDRIE1\r
+#elif defined(__AVR_ATmega161__)\r
+ /* ATmega with UART */\r
+ #error "AVR ATmega161 currently not supported by this libaray !"\r
+#elif defined(__AVR_ATmega169__) \r
+ /* ATmega with one USART */\r
+ #define ATMEGA_USART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA\r
+ #define UART0_STATUS UCSRA\r
+ #define UART0_CONTROL UCSRB\r
+ #define UART0_DATA UDR\r
+ #define UART0_UDRIE UDRIE\r
+#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega644__)\r
+ #define ATMEGA_USART0\r
+ #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV\r
+ #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA\r
+ #define UART0_STATUS UCSR0A\r
+ #define UART0_CONTROL UCSR0B\r
+ #define UART0_DATA UDR0\r
+ #define UART0_UDRIE UDRIE0\r
+#elif defined(__AVR_ATtiny2313__)\r
+ #define ATMEGA_USART\r
+ #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX \r
+ #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE\r
+ #define UART0_STATUS UCSRA\r
+ #define UART0_CONTROL UCSRB\r
+ #define UART0_DATA UDR\r
+ #define UART0_UDRIE UDRIE\r
+#else\r
+ #error "no UART definition for MCU available"\r
+#endif\r
+\r
+\r
+/*\r
+ * module global variables\r
+ */\r
+static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];\r
+static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];\r
+static volatile unsigned char UART_TxHead;\r
+static volatile unsigned char UART_TxTail;\r
+static volatile unsigned char UART_RxHead;\r
+static volatile unsigned char UART_RxTail;\r
+static volatile unsigned char UART_LastRxError;\r
+\r
+#if defined( ATMEGA_USART1 )\r
+static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];\r
+static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];\r
+static volatile unsigned char UART1_TxHead;\r
+static volatile unsigned char UART1_TxTail;\r
+static volatile unsigned char UART1_RxHead;\r
+static volatile unsigned char UART1_RxTail;\r
+static volatile unsigned char UART1_LastRxError;\r
+#endif\r
+\r
+\r
+\r
+SIGNAL(UART0_RECEIVE_INTERRUPT)\r
+/*************************************************************************\r
+Function: UART Receive Complete interrupt\r
+Purpose: called when the UART has received a character\r
+**************************************************************************/\r
+{\r
+ unsigned char tmphead;\r
+ unsigned char data;\r
+ unsigned char usr;\r
+ unsigned char lastRxError;\r
+ \r
+ \r
+ /* read UART status register and UART data register */ \r
+ usr = UART0_STATUS;\r
+ data = UART0_DATA;\r
+ \r
+ /* */\r
+#if defined( AT90_UART )\r
+ lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
+#elif defined( ATMEGA_USART )\r
+ lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
+#elif defined( ATMEGA_USART0 )\r
+ lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );\r
+#elif defined ( ATMEGA_UART )\r
+ lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
+#endif\r
+ \r
+ /* calculate buffer index */ \r
+ tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;\r
+ \r
+ if ( tmphead == UART_RxTail ) {\r
+ /* error: receive buffer overflow */\r
+ lastRxError = UART_BUFFER_OVERFLOW >> 8;\r
+ }else{\r
+ /* store new index */\r
+ UART_RxHead = tmphead;\r
+ /* store received data in buffer */\r
+ UART_RxBuf[tmphead] = data;\r
+ }\r
+ UART_LastRxError = lastRxError; \r
+}\r
+\r
+\r
+SIGNAL(UART0_TRANSMIT_INTERRUPT)\r
+/*************************************************************************\r
+Function: UART Data Register Empty interrupt\r
+Purpose: called when the UART is ready to transmit the next byte\r
+**************************************************************************/\r
+{\r
+ unsigned char tmptail;\r
+\r
+ \r
+ if ( UART_TxHead != UART_TxTail) {\r
+ /* calculate and store new buffer index */\r
+ tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;\r
+ UART_TxTail = tmptail;\r
+ /* get one byte from buffer and write it to UART */\r
+ UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */\r
+ }else{\r
+ /* tx buffer empty, disable UDRE interrupt */\r
+ UART0_CONTROL &= ~_BV(UART0_UDRIE);\r
+ }\r
+}\r
+\r
+\r
+/*************************************************************************\r
+Function: uart_init()\r
+Purpose: initialize UART and set baudrate\r
+Input: baudrate using macro UART_BAUD_SELECT()\r
+Returns: none\r
+**************************************************************************/\r
+void uart_init(unsigned int baudrate)\r
+{\r
+ UART_TxHead = 0;\r
+ UART_TxTail = 0;\r
+ UART_RxHead = 0;\r
+ UART_RxTail = 0;\r
+ \r
+#if defined( AT90_UART )\r
+ /* set baud rate */\r
+ UBRR = (unsigned char)baudrate; \r
+\r
+ /* enable UART receiver and transmmitter and receive complete interrupt */\r
+ UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);\r
+\r
+#elif defined (ATMEGA_USART)\r
+ /* Set baud rate */\r
+ if ( baudrate & 0x8000 )\r
+ {\r
+ UART0_STATUS = (1<<U2X); //Enable 2x speed \r
+ baudrate &= ~0x8000;\r
+ }\r
+ UBRRH = (unsigned char)(baudrate>>8);\r
+ UBRRL = (unsigned char) baudrate;\r
+ \r
+ /* Enable USART receiver and transmitter and receive complete interrupt */\r
+ UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);\r
+ \r
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */\r
+ #ifdef URSEL\r
+ UCSRC = (1<<URSEL)|(3<<UCSZ0);\r
+ #else\r
+ UCSRC = (3<<UCSZ0);\r
+ #endif \r
+ \r
+#elif defined (ATMEGA_USART0 )\r
+ /* Set baud rate */\r
+ if ( baudrate & 0x8000 ) \r
+ {\r
+ UART0_STATUS = (1<<U2X0); //Enable 2x speed \r
+ baudrate &= ~0x8000;\r
+ }\r
+ UBRR0H = (unsigned char)(baudrate>>8);\r
+ UBRR0L = (unsigned char) baudrate;\r
+\r
+ /* Enable USART receiver and transmitter and receive complete interrupt */\r
+ UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);\r
+ \r
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */\r
+ #ifdef URSEL0\r
+ UCSR0C = (1<<URSEL0)|(3<<UCSZ00);\r
+ #else\r
+ UCSR0C = (3<<UCSZ00);\r
+ #endif \r
+\r
+#elif defined ( ATMEGA_UART )\r
+ /* set baud rate */\r
+ if ( baudrate & 0x8000 ) \r
+ {\r
+ UART0_STATUS = (1<<U2X); //Enable 2x speed \r
+ baudrate &= ~0x8000;\r
+ }\r
+ UBRRHI = (unsigned char)(baudrate>>8);\r
+ UBRR = (unsigned char) baudrate;\r
+\r
+ /* Enable UART receiver and transmitter and receive complete interrupt */\r
+ UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);\r
+\r
+#endif\r
+\r
+}/* uart_init */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart_getc()\r
+Purpose: return byte from ringbuffer \r
+Returns: lower byte: received byte from ringbuffer\r
+ higher byte: last receive error\r
+**************************************************************************/\r
+unsigned int uart_getc(void)\r
+{ \r
+ unsigned char tmptail;\r
+ unsigned char data;\r
+\r
+\r
+ if ( UART_RxHead == UART_RxTail ) {\r
+ return UART_NO_DATA; /* no data available */\r
+ }\r
+ \r
+ /* calculate /store buffer index */\r
+ tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;\r
+ UART_RxTail = tmptail; \r
+ \r
+ /* get data from receive buffer */\r
+ data = UART_RxBuf[tmptail];\r
+ \r
+ return (UART_LastRxError << 8) + data;\r
+\r
+}/* uart_getc */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart_putc()\r
+Purpose: write byte to ringbuffer for transmitting via UART\r
+Input: byte to be transmitted\r
+Returns: none \r
+**************************************************************************/\r
+void uart_putc(unsigned char data)\r
+{\r
+ unsigned char tmphead;\r
+\r
+ \r
+ tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;\r
+ \r
+ while ( tmphead == UART_TxTail ){\r
+ ;/* wait for free space in buffer */\r
+ }\r
+ \r
+ UART_TxBuf[tmphead] = data;\r
+ UART_TxHead = tmphead;\r
+\r
+ /* enable UDRE interrupt */\r
+ UART0_CONTROL |= _BV(UART0_UDRIE);\r
+\r
+}/* uart_putc */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart_puts()\r
+Purpose: transmit string to UART\r
+Input: string to be transmitted\r
+Returns: none \r
+**************************************************************************/\r
+void uart_puts(const char *s )\r
+{\r
+ while (*s) \r
+ uart_putc(*s++);\r
+\r
+}/* uart_puts */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart_puts_p()\r
+Purpose: transmit string from program memory to UART\r
+Input: program memory string to be transmitted\r
+Returns: none\r
+**************************************************************************/\r
+void uart_puts_p(const char *progmem_s )\r
+{\r
+ register char c;\r
+ \r
+ while ( (c = pgm_read_byte(progmem_s++)) ) \r
+ uart_putc(c);\r
+\r
+}/* uart_puts_p */\r
+\r
+\r
+/*\r
+ * these functions are only for ATmegas with two USART\r
+ */\r
+#if defined( ATMEGA_USART1 )\r
+\r
+SIGNAL(UART1_RECEIVE_INTERRUPT)\r
+/*************************************************************************\r
+Function: UART1 Receive Complete interrupt\r
+Purpose: called when the UART1 has received a character\r
+**************************************************************************/\r
+{\r
+ unsigned char tmphead;\r
+ unsigned char data;\r
+ unsigned char usr;\r
+ unsigned char lastRxError;\r
+ \r
+ \r
+ /* read UART status register and UART data register */ \r
+ usr = UART1_STATUS;\r
+ data = UART1_DATA;\r
+ \r
+ /* */\r
+ lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) );\r
+ \r
+ /* calculate buffer index */ \r
+ tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;\r
+ \r
+ if ( tmphead == UART1_RxTail ) {\r
+ /* error: receive buffer overflow */\r
+ lastRxError = UART_BUFFER_OVERFLOW >> 8;\r
+ }else{\r
+ /* store new index */\r
+ UART1_RxHead = tmphead;\r
+ /* store received data in buffer */\r
+ UART1_RxBuf[tmphead] = data;\r
+ }\r
+ UART1_LastRxError = lastRxError; \r
+}\r
+\r
+\r
+SIGNAL(UART1_TRANSMIT_INTERRUPT)\r
+/*************************************************************************\r
+Function: UART1 Data Register Empty interrupt\r
+Purpose: called when the UART1 is ready to transmit the next byte\r
+**************************************************************************/\r
+{\r
+ unsigned char tmptail;\r
+\r
+ \r
+ if ( UART1_TxHead != UART1_TxTail) {\r
+ /* calculate and store new buffer index */\r
+ tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;\r
+ UART1_TxTail = tmptail;\r
+ /* get one byte from buffer and write it to UART */\r
+ UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */\r
+ }else{\r
+ /* tx buffer empty, disable UDRE interrupt */\r
+ UART1_CONTROL &= ~_BV(UART1_UDRIE);\r
+ }\r
+}\r
+\r
+\r
+/*************************************************************************\r
+Function: uart1_init()\r
+Purpose: initialize UART1 and set baudrate\r
+Input: baudrate using macro UART_BAUD_SELECT()\r
+Returns: none\r
+**************************************************************************/\r
+void uart1_init(unsigned int baudrate)\r
+{\r
+ UART1_TxHead = 0;\r
+ UART1_TxTail = 0;\r
+ UART1_RxHead = 0;\r
+ UART1_RxTail = 0;\r
+ \r
+\r
+ /* Set baud rate */\r
+ if ( baudrate & 0x8000 ) \r
+ {\r
+ UART1_STATUS = (1<<U2X1); //Enable 2x speed \r
+ baudrate &= ~0x8000;\r
+ }\r
+ UBRR1H = (unsigned char)(baudrate>>8);\r
+ UBRR1L = (unsigned char) baudrate;\r
+\r
+ /* Enable USART receiver and transmitter and receive complete interrupt */\r
+ UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1);\r
+ \r
+ /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ \r
+ #ifdef URSEL1\r
+ UCSR1C = (1<<URSEL1)|(3<<UCSZ10);\r
+ #else\r
+ UCSR1C = (3<<UCSZ10);\r
+ #endif \r
+}/* uart_init */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart1_getc()\r
+Purpose: return byte from ringbuffer \r
+Returns: lower byte: received byte from ringbuffer\r
+ higher byte: last receive error\r
+**************************************************************************/\r
+unsigned int uart1_getc(void)\r
+{ \r
+ unsigned char tmptail;\r
+ unsigned char data;\r
+\r
+\r
+ if ( UART1_RxHead == UART1_RxTail ) {\r
+ return UART_NO_DATA; /* no data available */\r
+ }\r
+ \r
+ /* calculate /store buffer index */\r
+ tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;\r
+ UART1_RxTail = tmptail; \r
+ \r
+ /* get data from receive buffer */\r
+ data = UART1_RxBuf[tmptail];\r
+ \r
+ return (UART1_LastRxError << 8) + data;\r
+\r
+}/* uart1_getc */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart1_putc()\r
+Purpose: write byte to ringbuffer for transmitting via UART\r
+Input: byte to be transmitted\r
+Returns: none \r
+**************************************************************************/\r
+void uart1_putc(unsigned char data)\r
+{\r
+ unsigned char tmphead;\r
+\r
+ \r
+ tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;\r
+ \r
+ while ( tmphead == UART1_TxTail ){\r
+ ;/* wait for free space in buffer */\r
+ }\r
+ \r
+ UART1_TxBuf[tmphead] = data;\r
+ UART1_TxHead = tmphead;\r
+\r
+ /* enable UDRE interrupt */\r
+ UART1_CONTROL |= _BV(UART1_UDRIE);\r
+\r
+}/* uart1_putc */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart1_puts()\r
+Purpose: transmit string to UART1\r
+Input: string to be transmitted\r
+Returns: none \r
+**************************************************************************/\r
+void uart1_puts(const char *s )\r
+{\r
+ while (*s) \r
+ uart1_putc(*s++);\r
+\r
+}/* uart1_puts */\r
+\r
+\r
+/*************************************************************************\r
+Function: uart1_puts_p()\r
+Purpose: transmit string from program memory to UART1\r
+Input: program memory string to be transmitted\r
+Returns: none\r
+**************************************************************************/\r
+void uart1_puts_p(const char *progmem_s )\r
+{\r
+ register char c;\r
+ \r
+ while ( (c = pgm_read_byte(progmem_s++)) ) \r
+ uart1_putc(c);\r
+\r
+}/* uart1_puts_p */\r
+\r
+\r
+#endif\r