MicroAPRS/bertos/cpu/avr/drv/ser_xmega.c

737 lines
22 KiB
C
Raw Normal View History

2014-04-03 14:21:37 -06:00
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos 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
* (at your option) 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2003, 2004, 2010 Develer S.r.l. (http://www.develer.com/)
* Copyright 2011 Onno <developer@gorgoz.org>
*
* -->
*
* \brief AVR XMEGA USART driver (Implementation)
*
* This file is heavily inspired by the AVR implementation for BeRTOS,
* but uses a different approach for implementing the different debug
* ports, by using the USART_t structs.
*
* \author Onno <developer@gorgoz.org>
* notest:all
*/
#include "hw/hw_ser.h" /* Required for bus macros overrides */
#include <hw/hw_cpufreq.h> /* CPU_FREQ */
#include "cfg/cfg_ser.h" /* Serialport configuration settings */
#include <cfg/macros.h> /* DIV_ROUND */
#include <cfg/debug.h> /* debug configuration */
#include <drv/ser.h>
#include <drv/ser_p.h>
#include <drv/timer.h>
#include <struct/fifobuf.h>
#include <avr/io.h> /* AVR IO ports and structures */
#include <avr/interrupt.h> /* AVR Interrupt methods */
/*
* Scalefactor to use for computing the baudrate
* this scalefactor should be an integer value between -7
* and 7
*/
#ifndef USART_SCALE_FACTOR
#define USART_SCALE_FACTOR (-7)
#else
#if USART_SCALE_FACTOR > 7 || USART_SCALE_FACTOR < -7
#error USART_SCALE_FACTOR should be an integer between -7 and 7
#endif
#endif
/* Helper macros, mostly taken from the Atmel Examples
* Slightly alterd to match the BeRTOS naming convention
*/
/* \brief Set USART baud rate.
*
* Sets the USART's baud rate register.
*
* UBRR_Value : Value written to UBRR
* ScaleFactor : Time Base Generator Scale Factor
*
* Equation for calculation of BSEL value in asynchronous normal speed mode:
* If ScaleFactor >= 0
* BSEL = ((I/O clock frequency)/(2^(ScaleFactor)*16*Baudrate))-1
* If ScaleFactor < 0
* BSEL = (1/(2^(ScaleFactor)*16))*(((I/O clock frequency)/Baudrate)-1)
*
* \note See XMEGA manual for equations for calculation of BSEL value in other
* modes.
*
* \param _usart Pointer to the USART module.
* \param _bselValue Value to write to BSEL part of Baud control register.
* Use uint16_t type.
* \param _bScaleFactor USART baud rate scale factor.
* Use uint8_t type
*/
#define USART_SET_BAUDRATE(_usart, _bselValue, _bScaleFactor) \
(_usart)->BAUDCTRLA =(uint8_t)_bselValue; \
(_usart)->BAUDCTRLB =(_bScaleFactor << USART_BSCALE0_bp)|(_bselValue >> 8)
/* \brief Enable USART receiver.
*
* \param _usart Pointer to the USART module
*/
#define USART_RX_ENABLE(_usart) ((_usart)->CTRLB |= USART_RXEN_bm)
/* \brief Disable USART receiver.
*
* \param _usart Pointer to the USART module.
*/
#define USART_RX_DISABLE(_usart) ((_usart)->CTRLB &= ~USART_RXEN_bm)
/* \brief Enable USART transmitter.
*
* \param _usart Pointer to the USART module.
*/
#define USART_TX_ENABLE(_usart) ((_usart)->CTRLB |= USART_TXEN_bm)
/* \brief Disable USART transmitter.
*
* \param _usart Pointer to the USART module.
*/
#define USART_TX_DISABLE(_usart) ((_usart)->CTRLB &= ~USART_TXEN_bm)
/* \brief Set USART RXD interrupt level.
*
* Sets the interrupt level on RX Complete interrupt.
*
* \param _usart Pointer to the USART module.
* \param _rxdIntLevel Interrupt level of the RXD interrupt.
* Use USART_RXCINTLVL_t type.
*/
#define USART_SET_RX_INTERRUPT_LEVEL(_usart, _rxdIntLevel) \
((_usart)->CTRLA = ((_usart)->CTRLA & ~USART_RXCINTLVL_gm) | _rxdIntLevel)
/* \brief Set USART TXD interrupt level.
*
* Sets the interrupt level on TX Complete interrupt.
*
* \param _usart Pointer to the USART module.
* \param _txdIntLevel Interrupt level of the TXD interrupt.
* Use USART_TXCINTLVL_t type.
*/
#define USART_SET_TX_INTERRUPT_LEVEL(_usart, _txdIntLevel) \
(_usart)->CTRLA = ((_usart)->CTRLA & ~USART_TXCINTLVL_gm) | _txdIntLevel
/* \brief Set USART DRE interrupt level.
*
* Sets the interrupt level on Data Register interrupt.
*
* \param _usart Pointer to the USART module.
* \param _dreIntLevel Interrupt level of the DRE interrupt.
* Use USART_DREINTLVL_t type.
*/
#define USART_SET_DRE_INTERRUPT_LEVEL(_usart, _dreIntLevel) \
(_usart)->CTRLA = ((_usart)->CTRLA & ~USART_DREINTLVL_gm) | _dreIntLevel
/* \brief Set the mode the USART run in.
*
* Set the mode the USART run in. The default mode is asynchronous mode.
*
* \param _usart Pointer to the USART module register section.
* \param _usartMode Selects the USART mode. Use USART_CMODE_t type.
*
* USART modes:
* - 0x0 : Asynchronous mode.
* - 0x1 : Synchronous mode.
* - 0x2 : IrDA mode.
* - 0x3 : Master SPI mode.
*/
#define USART_SET_MODE(_usart, _usartMode) \
((_usart)->CTRLC = ((_usart)->CTRLC & (~USART_CMODE_gm)) | _usartMode)
/* \brief Check if data register empty flag is set.
*
* \param _usart The USART module.
*/
#define USART_IS_TX_DATA_REGISTER_EMPTY(_usart) (((_usart)->STATUS & USART_DREIF_bm) != 0)
/* \brief Put data (5-8 bit character).
*
* Use the macro USART_IsTXDataRegisterEmpty before using this function to
* put data to the TX register.
*
* \param _usart The USART module.
* \param _data The data to send.
*/
#define USART_PUT_CHAR(_usart, _data) ((_usart)->DATA = _data)
/* \brief Checks if the RX complete interrupt flag is set.
*
* Checks if the RX complete interrupt flag is set.
*
* \param _usart The USART module.
*/
#define USART_IS_RX_COMPLETE(_usart) (((_usart)->STATUS & USART_RXCIF_bm) != 0)
/* \brief Get received data (5-8 bit character).
*
* This macro reads out the RX register.
* Use the macro USART_RX_Complete to check if anything is received.
*
* \param _usart The USART module.
*
* \retval Received data.
*/
#define USART_GET_CHAR(_usart) ((_usart)->DATA)
/* configurable macros */
#if !CONFIG_SER_HWHANDSHAKE
/**
* \name Hardware handshake (RTS/CTS).
* \{
*/
#define RTS_ON do {} while (0)
#define RTS_OFF do {} while (0)
#define IS_CTS_ON true
#define EIMSKF_CTS 0 /**< Dummy value, must be overridden */
/*\}*/
#endif
/*
* \name Overridable serial bus hooks
*
* These can be redefined in hw.h to implement
* special bus policies such as half-duplex, 485, etc.
*
*
* \code
* TXBEGIN TXCHAR TXEND TXOFF
* | __________|__________ | |
* | | | | | | | | |
* v v v v v v v v v
* ______ __ __ __ __ __ __ ________________
* \/ \/ \/ \/ \/ \/ \/
* ______/\__/\__/\__/\__/\__/\__/
*
* \endcode
*
* \{
*/
#ifndef SER_UART_BUS_TXINIT
/*
* Default TXINIT macro - invoked in uart_init()
*
* - Enable both the receiver and the transmitter
* - Enable only the RX complete interrupt
*/
#define SER_UART_BUS_TXINIT(_usart) do { \
USART_RX_ENABLE(_usart); \
USART_TX_ENABLE(_usart); \
USART_SET_RX_INTERRUPT_LEVEL(_usart, USART_RXCINTLVL_MED_gc); \
} while (0)
#endif
#ifndef SER_UART_BUS_TXBEGIN
/*
* Invoked before starting a transmission
*
* - Enable both the receiver and the transmitter
* - Enable both the RX complete and UDR empty interrupts
*/
#define SER_UART_BUS_TXBEGIN(_usart) do { \
USART_SET_RX_INTERRUPT_LEVEL(_usart, USART_RXCINTLVL_MED_gc); \
USART_SET_DRE_INTERRUPT_LEVEL(_usart, USART_DREINTLVL_MED_gc);\
} while (0)
#endif
#ifndef SER_UART_BUS_TXCHAR
/*
* Invoked to send one character.
*/
#define SER_UART_BUS_TXCHAR(_usart, c) do { \
USART_PUT_CHAR(_usart, c); \
} while (0)
#endif
#ifndef SER_UART_BUS_TXEND
/*
* Invoked as soon as the txfifo becomes empty
*
* - Keep both the receiver and the transmitter enabled
* - Keep the RX complete interrupt enabled
* - Disable the UDR empty interrupt
*/
#define SER_UART_BUS_TXEND(_usart) do { \
USART_SET_DRE_INTERRUPT_LEVEL(_usart, USART_DREINTLVL_OFF_gc); \
} while (0)
#endif
#ifndef SER_UART_BUS_TXOFF
/*
* \def SER_UART_BUS_TXOFF
*
* Invoked after the last character has been transmitted
*
* The default is no action.
*/
#ifdef __doxygen__
#define SER_UART_BUS_TXOFF(_usart)
#endif
#endif
/*\}*/
/* From the high-level serial driver */
extern struct Serial *ser_handles[SER_CNT];
/* TX and RX buffers */
static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
#ifdef CPU_AVR_XMEGA_A
static unsigned char uart2_txbuffer[CONFIG_UART2_TXBUFSIZE];
static unsigned char uart2_rxbuffer[CONFIG_UART2_RXBUFSIZE];
static unsigned char uart3_txbuffer[CONFIG_UART3_TXBUFSIZE];
static unsigned char uart3_rxbuffer[CONFIG_UART3_RXBUFSIZE];
static unsigned char uart4_txbuffer[CONFIG_UART4_TXBUFSIZE];
static unsigned char uart4_rxbuffer[CONFIG_UART4_RXBUFSIZE];
#endif
/*
* Internal hardware state structure
*
* The \a sending variable is true while the transmission
* interrupt is retriggering itself.
*
* the \a usart variable will point to the USART_t structure
* that should be used.
*
* the \a port variable will point to the PORT_t structure
* that should be modified to set the tx pin as an output and the
* rx pin as an input
*
* the \a txpin variable will hold the pinnumber of the pin to use
* as the tx output
*
* the \a rxpin variable will hold the pinnumber of the pin to use
* as the rx input
*
* For the USARTs the \a sending flag is useful for taking specific
* actions before sending a burst of data, at the start of a trasmission
* but not before every char sent.
*
* For the SPI, this flag is necessary because the SPI sends and receives
* bytes at the same time and the SPI IRQ is unique for send/receive.
* The only way to start transmission is to write data in SPDR (this
* is done by spi_starttx()). We do this *only* if a transfer is
* not already started.
*/
struct AvrxmegaSerial
{
struct SerialHardware hw;
volatile bool sending;
volatile USART_t* usart;
volatile PORT_t* port;
uint8_t txpin;
uint8_t rxpin;
};
/*
* Callbacks
* The same callbacks are used for all USARTS.
* By casting the SerialHardware structure to the AvrxmegaSerial
* structure a pointer to the USART_t structure can be obtained,
* to perform the callback for the specific USART.
* This methode might cost some more cpu time, but saves on
* code duplication and code size.
*/
/*
* \brief Initializes the uart
*
* The TX pin of the uart will be set as an outputpin
* The RX pin of the uart will be set as an inputpin
* The usart will be initialized
* \see SER_UART_BUS_TXINIT
*
* \param _hw struct AvrxmegaSerial
* \param ser Unused
*/
static void uart_init(struct SerialHardware * _hw, UNUSED_ARG(struct Serial *, ser))
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
//set transmit pin as output
hw->port->DIRSET = BV(hw->txpin);
hw->port->OUTCLR = BV(hw->txpin);
//set receive pin as input
hw->port->DIRCLR = BV(hw->rxpin);
//initialize the USART
SER_UART_BUS_TXINIT(hw->usart);
RTS_ON;
SER_STROBE_INIT;
}
/*
* \brief Cleans up / Disables the uart
*
* \param _hw struct AvrxmegaSerial
*/
static void uart_cleanup(struct SerialHardware * _hw)
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
hw->usart->CTRLA = 0;
hw->usart->CTRLB = 0;
}
/*
* \brief Enableds the TX interrupt
*
* \param _hw struct AvrxmegaSerial
*/
static void uart_enabletxirq(struct SerialHardware *_hw)
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
/*
* WARNING: racy code here! The tx interrupt sets hw->sending to false
* when it runs with an empty fifo. The order of statements in the
* if-block matters.
*/
if (!hw->sending)
{
hw->sending = true;
SER_UART_BUS_TXBEGIN(hw->usart);
}
}
/*
* \brief sets the uart to the provided baudrate
*
* For setting the baudrate an scale factor (bscale) and a period
* setting (BSEL) is required.
*
* The scale factor should be privided by defining USART_SCALE_FACTOR
*
* Atmel specifies BSEL for normal speed mode and bscale >= 0 as:
* BSEL = (cpu_freq / ((2^bscale) * 16 * rate)) - 1
* To allow BSEL to be calculated with an power function this can be
* rewriten to:
* BSEL = BSEL = (cpu_freq / ((1 << bscale) * 16 * rate)) - 1
*
* Atmel specifies BSEL for normal speed mode and bscale < 0 as:
* BSEL = (1 / (2^bscale)) * ( (cpu_freq / (16 * rate)) - 1)
* To calculte this float atheritmic is required as the second product will be smaller
* than zero in a lot of cases.
* To allow BSEL to be calculated with interger devision and no power function
* this can be rewriten by folowing simple math rules to:
* BSEL = ((1 << -bscale) * (cpu_freq - (16 * rate)) / (16 * rate)
*
* \param _hw struct AvrxmegaSerial
* \param _rate the required baudrate
*
*/
static void uart_setbaudrate(struct SerialHardware * _hw, unsigned long _rate)
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
/* Compute baud-rate period, this requires a valid USART_SCALE_FACTOR */
#if USART_SCALE_FACTOR < 0
uint16_t bsel = DIV_ROUND((1 << (-(USART_SCALE_FACTOR))) * (CPU_FREQ - (16 * _rate)), 16 * _rate);
#else
uint16_t bsel = DIV_ROUND(CPU_FREQ, (1 << (USART_SCALE_FACTOR)) * 16 * _rate) - 1;
#endif
USART_SET_BAUDRATE(hw->usart, bsel, USART_SCALE_FACTOR);
}
/*
* \brief Sets the parity of the uart
*
* \param _hw struct AvrxmegaSerial
* \param _parity the parity to set
*/
static void uart_setparity(struct SerialHardware * _hw, int _parity)
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
USART_SET_MODE(hw->usart, _parity);
}
/*
* \brief Returns true if Transmitter is sending
*
* \param _hw struct AvrxmegaSerial
* \return true if transmitter is sending
*/
static bool tx_sending(struct SerialHardware* _hw)
{
struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
return hw->sending;
}
// FIXME: move into compiler.h? Ditch?
#if COMPILER_C99
#define C99INIT(name,val) .name = val
#elif defined(__GNUC__)
#define C99INIT(name,val) name: val
#else
#warning No designated initializers, double check your code
#define C99INIT(name,val) (val)
#endif
/*
* High-level interface data structures
*/
static const struct SerialHardwareVT UART_VT =
{
C99INIT(init, uart_init),
C99INIT(cleanup, uart_cleanup),
C99INIT(setBaudrate, uart_setbaudrate),
C99INIT(setParity, uart_setparity),
C99INIT(txStart, uart_enabletxirq),
C99INIT(txSending, tx_sending)
};
static struct AvrxmegaSerial UARTDescs[SER_CNT] =
{
{
C99INIT(hw, /**/) {
C99INIT(table, &UART_VT),
C99INIT(txbuffer, uart0_txbuffer),
C99INIT(rxbuffer, uart0_rxbuffer),
C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
},
C99INIT(sending, false),
C99INIT(usart, &USARTC0),
C99INIT(port, &PORTC),
C99INIT(txpin, PIN3_bp),
C99INIT(rxpin, PIN2_bp),
},
{
C99INIT(hw, /**/) {
C99INIT(table, &UART_VT),
C99INIT(txbuffer, uart1_txbuffer),
C99INIT(rxbuffer, uart1_rxbuffer),
C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
},
C99INIT(sending, false),
C99INIT(usart, &USARTD0),
C99INIT(port, &PORTD),
C99INIT(txpin, PIN3_bp),
C99INIT(rxpin, PIN2_bp),
},
#ifdef CPU_AVR_XMEGA_A
{
C99INIT(hw, /**/) {
C99INIT(table, &UART_VT),
C99INIT(txbuffer, uart2_txbuffer),
C99INIT(rxbuffer, uart2_rxbuffer),
C99INIT(txbuffer_size, sizeof(uart2_txbuffer)),
C99INIT(rxbuffer_size, sizeof(uart2_rxbuffer)),
},
C99INIT(sending, false),
C99INIT(usart, &USARTC1),
C99INIT(port, &PORTC),
C99INIT(txpin, PIN7_bp),
C99INIT(rxpin, PIN6_bp),
},
{
C99INIT(hw, /**/) {
C99INIT(table, &UART_VT),
C99INIT(txbuffer, uart3_txbuffer),
C99INIT(rxbuffer, uart3_rxbuffer),
C99INIT(txbuffer_size, sizeof(uart3_txbuffer)),
C99INIT(rxbuffer_size, sizeof(uart3_rxbuffer)),
},
C99INIT(sending, false),
C99INIT(usart, &USARTD1),
C99INIT(port, &PORTD),
C99INIT(txpin, PIN7_bp),
C99INIT(rxpin, PIN6_bp),
},
{
C99INIT(hw, /**/) {
C99INIT(table, &UART_VT),
C99INIT(txbuffer, uart4_txbuffer),
C99INIT(rxbuffer, uart4_rxbuffer),
C99INIT(txbuffer_size, sizeof(uart4_txbuffer)),
C99INIT(rxbuffer_size, sizeof(uart4_rxbuffer)),
},
C99INIT(sending, false),
C99INIT(usart, &USARTE0),
C99INIT(port, &PORTE),
C99INIT(txpin, PIN3_bp),
C99INIT(rxpin, PIN2_bp),
},
#endif //CPU_AVR_XMEGA_A
};
struct SerialHardware *ser_hw_getdesc(int unit)
{
ASSERT(unit < SER_CNT);
return &UARTDescs[unit].hw;
}
/*
* Interrupt handlers
*/
static inline void usart_handleDreInterrupt(uint8_t usartNumber)
{
SER_STROBE_ON;
struct FIFOBuffer * const txfifo = &ser_handles[usartNumber]->txfifo;
if (fifo_isempty(txfifo))
{
SER_UART_BUS_TXEND(UARTDescs[usartNumber].usart);
#ifndef SER_UART_BUS_TXOFF
UARTDescs[usartNumber].sending = false;
#endif
}
else
{
char c = fifo_pop(txfifo);
SER_UART_BUS_TXCHAR(UARTDescs[usartNumber].usart, c);
}
SER_STROBE_OFF;
}
#define USART_DRE_INTERRUPT_VECTOR(_vector, _usart) \
DECLARE_ISR(_vector) \
{ \
usart_handleDreInterrupt( _usart ); \
}
USART_DRE_INTERRUPT_VECTOR(USARTC0_DRE_vect, SER_UART0)
USART_DRE_INTERRUPT_VECTOR(USARTD0_DRE_vect, SER_UART1)
#ifdef CPU_AVR_XMEGA_A
USART_DRE_INTERRUPT_VECTOR(USARTC1_DRE_vect, SER_UART2)
USART_DRE_INTERRUPT_VECTOR(USARTD1_DRE_VECT, SER_UART3)
USART_DRE_INTERRUPT_VECTOR(USARTE0_DRE_vect, SER_UART4)
#endif
#ifdef SER_UART_BUS_TXOFF
static inline void USART_handleTXCInterrupt(uint8_t usartNumber)
{
SER_STROBE_ON;
struct FIFOBuffer * const txfifo = &ser_handles[usartNumber]->txfifo;
if (fifo_isempty(txfifo))
{
SER_UART_BUS_TXOFF(UARTDescs[usartNumber].usart);
UARTDescs[usartNumber].sending = false;
}
else
{
SER_UART_BUS_TXBEGIN(UARTDescs[usartNumber].usart);
}
SER_STROBE_OFF;
}
/*
* Serial port 0 TX complete interrupt handler.
*
* This IRQ is usually disabled. The UDR-empty interrupt
* enables it when there's no more data to transmit.
* We need to wait until the last character has been
* transmitted before switching the 485 transceiver to
* receive mode.
*
* The txfifo might have been refilled by putchar() while
* we were waiting for the transmission complete interrupt.
* In this case, we must restart the UDR empty interrupt,
* otherwise we'd stop the serial port with some data
* still pending in the buffer.
*/
#define USART_TXC_INTERRUPT_VECTOR(_vector, _usart) \
DECLARE_ISR(_vector) \
{ \
USART_handleTXCInterrupt( _usart ); \
}
USART_TXC_INTERRUPT_VECTOR(USARTC0_TXC_vect, SER_UART0)
USART_TXC_INTERRUPT_VECTOR(USARTD0_TXC_vect, SER_UART1)
#ifdef CPU_AVR_XMEGA_A
USART_TXC_INTERRUPT_VECTOR(USARTC1_TXC_vect, SER_UART2)
USART_TXC_INTERRUPT_VECTOR(USARTD1_TXC_vect, SER_UART3)
USART_TXC_INTERRUPT_VECTOR(USARTE0_TXC_vect, SER_UART4)
#endif /* CPU_AVR_XMEGA_A */
#endif /* SER_UART_BUS_TXOFF */
/*
* Serial RX complete interrupt handler.
*
* This handler is interruptible.
* Interrupt are reenabled as soon as recv complete interrupt is
* disabled. Using INTERRUPT() is troublesome when the serial
* is heavily loaded, because an interrupt could be retriggered
* when executing the handler prologue before RXCIE is disabled.
*/
static inline void USART_handleRXCInterrupt(uint8_t usartNumber)
{
SER_STROBE_ON;
/* read status */
ser_handles[usartNumber]->status |= (UARTDescs[usartNumber].usart)->STATUS & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
/* To clear the RXC flag we must _always_ read the UDR even when we're
* not going to accept the incoming data, otherwise a new interrupt
* will occur once the handler terminates.
*/
char c = (UARTDescs[usartNumber].usart)->DATA;
struct FIFOBuffer * const rxfifo = &ser_handles[usartNumber]->rxfifo;
if (fifo_isfull(rxfifo))
{
ser_handles[usartNumber]->status |= SERRF_RXFIFOOVERRUN;
}
else
{
fifo_push(rxfifo, c);
#if CONFIG_SER_HWHANDSHAKE
if (fifo_isfull(rxfifo))
{
RTS_OFF(UARTDescs[usartNumber].usart);
}
#endif
}
SER_STROBE_OFF;
}
#define USART_RXC_INTERRUPT_VECTOR(_vector, _usart) \
DECLARE_ISR(_vector) \
{ \
USART_handleRXCInterrupt( _usart ); \
}
USART_RXC_INTERRUPT_VECTOR(USARTC0_RXC_vect, SER_UART0)
USART_RXC_INTERRUPT_VECTOR(USARTD0_RXC_vect, SER_UART1)
#ifdef CPU_AVR_XMEGA_A
USART_RXC_INTERRUPT_VECTOR(USARTC1_RXC_vect, SER_UART2)
USART_RXC_INTERRUPT_VECTOR(USARTD1_RXC_vect, SER_UART3)
USART_RXC_INTERRUPT_VECTOR(USARTE0_RXC_vect, SER_UART4)
#endif