diff options
author | root <root@no.no.james.local> | 2014-12-08 18:39:07 +0000 |
---|---|---|
committer | root <root@no.no.james.local> | 2014-12-08 18:39:07 +0000 |
commit | 804820fe687affa38a52e302179e4a2293cb1ffb (patch) | |
tree | acb784fd60af24d8c389e366d74409c75802dfa0 /uart.c | |
download | rgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.tar.gz rgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.tar.bz2 rgb_ring-804820fe687affa38a52e302179e4a2293cb1ffb.zip |
fish
Diffstat (limited to 'uart.c')
-rw-r--r-- | uart.c | 686 |
1 files changed, 686 insertions, 0 deletions
@@ -0,0 +1,686 @@ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury +File: $Id: uart.c,v 1.10 2013/06/02 07:27:04 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*************************************************************************/ +#include "project.h" + + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ +#define AT90_UART +#define UART0_RECEIVE_INTERRUPT UART_RX_vect +#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect +#define UART0_STATUS USR +#define UART0_CONTROL UCR +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ +#define AT90_UART +#define UART0_RECEIVE_INTERRUPT UART_RX_vect +#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ +#define ATMEGA_USART +#define UART0_RECEIVE_INTERRUPT USART_RXC_vect +#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined (__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) +#define ATMEGA_USART +#define UART0_RECEIVE_INTERRUPT USART_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ +#define ATMEGA_UART +#define UART0_RECEIVE_INTERRUPT UART_RX_vect +#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ +#define ATMEGA_USART0 +#define ATMEGA_USART1 +#define UART0_RECEIVE_INTERRUPT USART0_RXC_vect +#define UART1_RECEIVE_INTERRUPT USART1_RXC_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#define UART1_STATUS UCSR1A +#define UART1_CONTROL UCSR1B +#define UART1_DATA UDR1 +#define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ +#define ATMEGA_USART0 +#define ATMEGA_USART1 +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART1_RECEIVE_INTERRUPT USART1_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#define UART1_STATUS UCSR1A +#define UART1_CONTROL UCSR1B +#define UART1_DATA UDR1 +#define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ +#error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ +#define ATMEGA_USART +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) \ + || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3290__) ||defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__) + /* ATmega with one USART */ +#define ATMEGA_USART0 +#define UART0_RECEIVE_INTERRUPT USART_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) +#define ATMEGA_USART +#define UART0_RECEIVE_INTERRUPT USART_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect +#define UART0_STATUS UCSRA +#define UART0_CONTROL UCSRB +#define UART0_DATA UDR +#define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) || \ + defined(__AVR_ATmega649__) || \ + defined(__AVR_ATmega325__) || \ + defined(__AVR_ATmega645__) + /* ATmega with one USART */ +#define ATMEGA_USART0 +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ +#define ATMEGA_USART0 +#define ATMEGA_USART1 +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART1_RECEIVE_INTERRUPT USART1_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#define UART1_STATUS UCSR1A +#define UART1_CONTROL UCSR1B +#define UART1_DATA UDR1 +#define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ +#define ATMEGA_USART0 +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) + /* ATmega with two USART */ +#define ATMEGA_USART0 +#define ATMEGA_USART1 +#define UART0_RECEIVE_INTERRUPT USART0_RX_vect +#define UART1_RECEIVE_INTERRUPT USART1_RX_vect +#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect +#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect +#define UART0_STATUS UCSR0A +#define UART0_CONTROL UCSR0B +#define UART0_DATA UDR0 +#define UART0_UDRIE UDRIE0 +#define UART1_STATUS UCSR1A +#define UART1_CONTROL UCSR1B +#define UART1_DATA UDR1 +#define UART1_UDRIE UDRIE1 +#else +#error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +ISR (NOPROTO UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV (FE) | _BV (DOR))); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV (FE) | _BV (DOR))); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV (FE0) | _BV (DOR0))); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV (FE) | _BV (DOR))); +#endif + + /* calculate buffer index */ + tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if (tmphead == UART_RxTail) + { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + } + else + { + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError |= lastRxError; +} + + +ISR (NOPROTO UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if (UART_TxHead != UART_TxTail) + { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + } + else + { + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV (UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void +uart_init (unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char) baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV (RXCIE) | _BV (RXEN) | _BV (TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if (baudrate & 0x8000) + { + UART0_STATUS = (1 << U2X); //Enable 2x speed + baudrate &= ~0x8000; + } + UBRRH = (unsigned char) (baudrate >> 8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV (RXCIE) | (1 << RXEN) | (1 << TXEN); + + /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ +#ifdef URSEL + UCSRC = (1 << URSEL) | (3 << UCSZ0); +#else + UCSRC = (3 << UCSZ0); +#endif + +#elif defined (ATMEGA_USART0 ) + /* Set baud rate */ + if (baudrate & 0x8000) + { + UART0_STATUS = (1 << U2X0); //Enable 2x speed + baudrate &= ~0x8000; + } + UBRR0H = (unsigned char) (baudrate >> 8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV (RXCIE0) | (1 << RXEN0) | (1 << TXEN0); + + /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ +#ifdef URSEL0 + UCSR0C = (1 << URSEL0) | (3 << UCSZ00); +#else + UCSR0C = (3 << UCSZ00); +#endif + +#elif defined ( ATMEGA_UART ) + /* set baud rate */ + if (baudrate & 0x8000) + { + UART0_STATUS = (1 << U2X); //Enable 2x speed + baudrate &= ~0x8000; + } + UBRRHI = (unsigned char) (baudrate >> 8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV (RXCIE) | (1 << RXEN) | (1 << TXEN); + +#endif + +} /* uart_init */ + + +/************************************************************************* +Function: uart_getc() +Purpose: return byte from ringbuffer +Returns: lower byte: received byte from ringbuffer + higher byte: last receive error +**************************************************************************/ +unsigned int +uart_getc (void) +{ + unsigned char tmptail; + unsigned char data; + + + if (UART_RxHead == UART_RxTail) + { + return UART_NO_DATA; /* no data available */ + } + + /* calculate /store buffer index */ + tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK; + UART_RxTail = tmptail; + + /* get data from receive buffer */ + data = UART_RxBuf[tmptail]; + + data = (UART_LastRxError << 8) + data; + UART_LastRxError = 0; + return data; + +} /* uart_getc */ + + +/************************************************************************* +Function: uart_putc() +Purpose: write byte to ringbuffer for transmitting via UART +Input: byte to be transmitted +Returns: none +**************************************************************************/ +void +uart_putc (unsigned char data) +{ + unsigned char tmphead; + + + tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK; + + while (tmphead == UART_TxTail) + { + ; /* wait for free space in buffer */ + } + + UART_TxBuf[tmphead] = data; + UART_TxHead = tmphead; + + /* enable UDRE interrupt */ + UART0_CONTROL |= _BV (UART0_UDRIE); + +} /* uart_putc */ + + +/************************************************************************* +Function: uart_puts() +Purpose: transmit string to UART +Input: string to be transmitted +Returns: none +**************************************************************************/ +void +uart_puts (const char *s) +{ + while (*s) + uart_putc (*s++); + +} /* uart_puts */ + + +/************************************************************************* +Function: uart_puts_p() +Purpose: transmit string from program memory to UART +Input: program memory string to be transmitted +Returns: none +**************************************************************************/ +void +uart_puts_p (const char *progmem_s) +{ + register char c; + + while ((c = pgm_read_byte (progmem_s++))) + uart_putc (c); + +} /* uart_puts_p */ + + +/* + * these functions are only for ATmegas with two USART + */ +#if defined( ATMEGA_USART1 ) + +ISR (NOPROTO UART1_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART1 Receive Complete interrupt +Purpose: called when the UART1 has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART1_STATUS; + data = UART1_DATA; + + /* */ + lastRxError = (usr & (_BV (FE1) | _BV (DOR1))); + + /* calculate buffer index */ + tmphead = (UART1_RxHead + 1) & UART_RX_BUFFER_MASK; + + if (tmphead == UART1_RxTail) + { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + } + else + { + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError |= lastRxError; +} + + +ISR (NOPROTO UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if (UART1_TxHead != UART1_TxTail) + { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + } + else + { + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV (UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void +uart1_init (unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if (baudrate & 0x8000) + { + UART1_STATUS = (1 << U2X1); //Enable 2x speed + baudrate &= ~0x8000; + } + UBRR1H = (unsigned char) (baudrate >> 8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV (RXCIE1) | (1 << RXEN1) | (1 << TXEN1); + + /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ +#ifdef URSEL1 + UCSR1C = (1 << URSEL1) | (3 << UCSZ10); +#else + UCSR1C = (3 << UCSZ10); +#endif +} /* uart_init */ + + +/************************************************************************* +Function: uart1_getc() +Purpose: return byte from ringbuffer +Returns: lower byte: received byte from ringbuffer + higher byte: last receive error +**************************************************************************/ +unsigned int +uart1_getc (void) +{ + unsigned char tmptail; + unsigned char data; + + + if (UART1_RxHead == UART1_RxTail) + { + return UART_NO_DATA; /* no data available */ + } + + /* calculate /store buffer index */ + tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK; + UART1_RxTail = tmptail; + + /* get data from receive buffer */ + data = UART1_RxBuf[tmptail]; + + data = (UART1_LastRxError << 8) + data; + UART1_LastRxError = 0; + return data; + +} /* uart1_getc */ + + +/************************************************************************* +Function: uart1_putc() +Purpose: write byte to ringbuffer for transmitting via UART +Input: byte to be transmitted +Returns: none +**************************************************************************/ +void +uart1_putc (unsigned char data) +{ + unsigned char tmphead; + + + tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK; + + while (tmphead == UART1_TxTail) + { + ; /* wait for free space in buffer */ + } + + UART1_TxBuf[tmphead] = data; + UART1_TxHead = tmphead; + + /* enable UDRE interrupt */ + UART1_CONTROL |= _BV (UART1_UDRIE); + +} /* uart1_putc */ + + +/************************************************************************* +Function: uart1_puts() +Purpose: transmit string to UART1 +Input: string to be transmitted +Returns: none +**************************************************************************/ +void +uart1_puts (const char *s) +{ + while (*s) + uart1_putc (*s++); + +} /* uart1_puts */ + + +/************************************************************************* +Function: uart1_puts_p() +Purpose: transmit string from program memory to UART1 +Input: program memory string to be transmitted +Returns: none +**************************************************************************/ +void +uart1_puts_p (const char *progmem_s) +{ + register char c; + + while ((c = pgm_read_byte (progmem_s++))) + uart1_putc (c); + +} /* uart1_puts_p */ + + +#endif |