4008-04-07 Release
[avr_bc100.git] / BaseMegaFirmware / GCC / uart.c
diff --git a/BaseMegaFirmware/GCC/uart.c b/BaseMegaFirmware/GCC/uart.c
new file mode 100644 (file)
index 0000000..48d2c9a
--- /dev/null
@@ -0,0 +1,585 @@
+/*************************************************************************\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