* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
- * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2003, 2004, 2010 Develer S.r.l. (http://www.develer.com/)
* Copyright 2000 Bernie Innocenti <bernie@codewiz.org>
*
* -->
*
* \brief AVR UART and SPI I/O driver (Implementation)
*
- * \version $Id$
- *
* \author Bernie Innocenti <bernie@codewiz.org>
* \author Stefano Fedrigo <aleph@develer.com>
+ * \author Luca Ottaviano <lottaviano@develer.com>
*/
#include "hw/hw_ser.h" /* Required for bus macros overrides */
/*\}*/
#endif
-#if CPU_AVR_ATMEGA1281
+#if CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
#define BIT_RXCIE0 RXCIE0
#define BIT_RXEN0 RXEN0
#define BIT_TXEN0 TXEN0
#define BIT_RXEN1 RXEN1
#define BIT_TXEN1 TXEN1
#define BIT_UDRIE1 UDRIE1
+ #if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
+ #define BIT_RXCIE2 RXCIE2
+ #define BIT_RXEN2 RXEN2
+ #define BIT_TXEN2 TXEN2
+ #define BIT_UDRIE2 UDRIE2
+
+ #define BIT_RXCIE3 RXCIE3
+ #define BIT_RXEN3 RXEN3
+ #define BIT_TXEN3 TXEN3
+ #define BIT_UDRIE3 UDRIE3
+ #endif
+#elif CPU_AVR_ATMEGA168 || CPU_AVR_ATMEGA328P
+ #define BIT_RXCIE0 RXCIE0
+ #define BIT_RXEN0 RXEN0
+ #define BIT_TXEN0 TXEN0
+ #define BIT_UDRIE0 UDRIE0
+
+ #define BIT_RXCIE1 RXCIE0
+ #define BIT_RXEN1 RXEN0
+ #define BIT_TXEN1 TXEN0
+ #define BIT_UDRIE1 UDRIE0
#else
#define BIT_RXCIE0 RXCIE
#define BIT_RXEN0 RXEN
#define SER_UART1_BUS_TXOFF
#endif
#endif
+
+#ifndef SER_UART2_BUS_TXINIT
+ /** \sa SER_UART0_BUS_TXINIT */
+ #define SER_UART2_BUS_TXINIT do { \
+ UCSR2B = BV(BIT_RXCIE2) | BV(BIT_RXEN2) | BV(BIT_TXEN2); \
+ } while (0)
+#endif
+#ifndef SER_UART2_BUS_TXBEGIN
+ /** \sa SER_UART0_BUS_TXBEGIN */
+ #define SER_UART2_BUS_TXBEGIN do { \
+ UCSR2B = BV(BIT_RXCIE2) | BV(BIT_UDRIE2) | BV(BIT_RXEN2) | BV(BIT_TXEN2); \
+ } while (0)
+#endif
+#ifndef SER_UART2_BUS_TXCHAR
+ /** \sa SER_UART0_BUS_TXCHAR */
+ #define SER_UART2_BUS_TXCHAR(c) do { \
+ UDR2 = (c); \
+ } while (0)
+#endif
+#ifndef SER_UART2_BUS_TXEND
+ /** \sa SER_UART0_BUS_TXEND */
+ #define SER_UART2_BUS_TXEND do { \
+ UCSR2B = BV(BIT_RXCIE2) | BV(BIT_RXEN2) | BV(BIT_TXEN2); \
+ } while (0)
+#endif
+#ifndef SER_UART2_BUS_TXOFF
+ /**
+ * \def SER_UART2_BUS_TXOFF
+ *
+ * \see SER_UART0_BUS_TXOFF
+ */
+ #ifdef __doxygen__
+ #define SER_UART2_BUS_TXOFF
+ #endif
+#endif
+
+#ifndef SER_UART3_BUS_TXINIT
+ /** \sa SER_UART0_BUS_TXINIT */
+ #define SER_UART3_BUS_TXINIT do { \
+ UCSR3B = BV(BIT_RXCIE3) | BV(BIT_RXEN3) | BV(BIT_TXEN3); \
+ } while (0)
+#endif
+#ifndef SER_UART3_BUS_TXBEGIN
+ /** \sa SER_UART0_BUS_TXBEGIN */
+ #define SER_UART3_BUS_TXBEGIN do { \
+ UCSR3B = BV(BIT_RXCIE3) | BV(BIT_UDRIE3) | BV(BIT_RXEN3) | BV(BIT_TXEN3); \
+ } while (0)
+#endif
+#ifndef SER_UART3_BUS_TXCHAR
+ /** \sa SER_UART0_BUS_TXCHAR */
+ #define SER_UART3_BUS_TXCHAR(c) do { \
+ UDR3 = (c); \
+ } while (0)
+#endif
+#ifndef SER_UART3_BUS_TXEND
+ /** \sa SER_UART0_BUS_TXEND */
+ #define SER_UART3_BUS_TXEND do { \
+ UCSR3B = BV(BIT_RXCIE3) | BV(BIT_RXEN3) | BV(BIT_TXEN3); \
+ } while (0)
+#endif
+#ifndef SER_UART3_BUS_TXOFF
+ /**
+ * \def SER_UART3_BUS_TXOFF
+ *
+ * \see SER_UART0_BUS_TXOFF
+ */
+ #ifdef __doxygen__
+ #define SER_UART3_BUS_TXOFF
+ #endif
+#endif
/*\}*/
/* SPI port and pin configuration */
-#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA103 || CPU_AVR_ATMEGA1281
+#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA103 || CPU_AVR_ATMEGA1281 \
+ || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_SS_BIT PB0
#define SPI_SCK_BIT PB1
#define SPI_MOSI_BIT PB2
#define SPI_MISO_BIT PB3
-#elif CPU_AVR_ATMEGA8
+// TODO: these bits are the same as ATMEGA8 but the defines in avr-gcc are different.
+// They should be the same!
+#elif CPU_AVR_ATMEGA328P
+ #define SPI_PORT PORTB
+ #define SPI_DDR DDRB
+ #define SPI_SS_BIT PORTB2
+ #define SPI_SCK_BIT PORTB5
+ #define SPI_MOSI_BIT PORTB3
+ #define SPI_MISO_BIT PORTB4
+#elif CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA168
#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_SS_BIT PB2
#define SPI_SCK_BIT PB5
#define SPI_MOSI_BIT PB3
#define SPI_MISO_BIT PB4
+#elif CPU_AVR_ATMEGA32
+ #define SPI_PORT PORTB
+ #define SPI_DDR DDRB
+ #define SPI_SS_BIT PB4
+ #define SPI_SCK_BIT PB7
+ #define SPI_MOSI_BIT PB5
+ #define SPI_MISO_BIT PB6
#else
#error Unknown architecture
#endif
/* USART register definitions */
-#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281
+#if CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
#define AVR_HAS_UART1 1
-#elif CPU_AVR_ATMEGA8
+ #define AVR_HAS_UART2 1
+ #define AVR_HAS_UART3 1
+#elif CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281
+ #define AVR_HAS_UART1 1
+ #define AVR_HAS_UART2 0
+ #define AVR_HAS_UART3 0
+#elif CPU_AVR_ATMEGA168 || CPU_AVR_ATMEGA328P
+ #define AVR_HAS_UART1 0
+ #define AVR_HAS_UART2 0
+ #define AVR_HAS_UART3 0
+ #define USART0_UDRE_vect USART_UDRE_vect
+ #define USART0_RX_vect USART_RX_vect
+ #define USART0_TX_vect USART_TX_vect
+#elif CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA32
#define AVR_HAS_UART1 0
+ #define AVR_HAS_UART2 0
+ #define AVR_HAS_UART3 0
#define UCSR0A UCSRA
#define UCSR0B UCSRB
#define UCSR0C UCSRC
#define UDR0 UDR
#define UBRR0L UBRRL
#define UBRR0H UBRRH
- #define SIG_UART0_DATA SIG_UART_DATA
- #define SIG_UART0_RECV SIG_UART_RECV
- #define SIG_UART0_TRANS SIG_UART_TRANS
+ #define UPM01 UPM1
+ #define UPM00 UPM0
+ #define USART0_UDRE_vect USART_UDRE_vect
+ #define USART0_RX_vect USART_RXC_vect
+ #define USART0_TX_vect USART_TXC_vect
#elif CPU_AVR_ATMEGA103
#define AVR_HAS_UART1 0
+ #define AVR_HAS_UART2 0
+ #define AVR_HAS_UART3 0
#define UCSR0B UCR
#define UDR0 UDR
#define UCSR0A USR
#define UBRR0L UBRR
- #define SIG_UART0_DATA SIG_UART_DATA
- #define SIG_UART0_RECV SIG_UART_RECV
- #define SIG_UART0_TRANS SIG_UART_TRANS
+ #define USART0_UDRE_vect USART_UDRE_vect
+ #define USART0_RX_vect USART_RX_vect
+ #define USART0_TX_vect USART_TX_vect
#else
#error Unknown architecture
#endif
static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
#endif
+#if AVR_HAS_UART2
+ static unsigned char uart2_txbuffer[CONFIG_UART2_TXBUFSIZE];
+ static unsigned char uart2_rxbuffer[CONFIG_UART2_RXBUFSIZE];
+#endif
+#if AVR_HAS_UART3
+ static unsigned char uart3_txbuffer[CONFIG_UART3_TXBUFSIZE];
+ static unsigned char uart3_rxbuffer[CONFIG_UART3_RXBUFSIZE];
+#endif
static unsigned char spi_txbuffer[CONFIG_SPI_TXBUFSIZE];
static unsigned char spi_rxbuffer[CONFIG_SPI_RXBUFSIZE];
#endif // AVR_HAS_UART1
+#if AVR_HAS_UART2
+
+static void uart2_init(
+ UNUSED_ARG(struct SerialHardware *, _hw),
+ UNUSED_ARG(struct Serial *, ser))
+{
+ SER_UART2_BUS_TXINIT;
+ RTS_ON;
+ SER_STROBE_INIT;
+}
+
+static void uart2_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
+{
+ UCSR2B = 0;
+}
+
+static void uart2_enabletxirq(struct SerialHardware *_hw)
+{
+ struct AvrSerial *hw = (struct AvrSerial *)_hw;
+
+ /*
+ * WARNING: racy code here! The tx interrupt
+ * sets hw->sending to false when it runs with
+ * an empty fifo. The order of the statements
+ * in the if-block matters.
+ */
+ if (!hw->sending)
+ {
+ hw->sending = true;
+ SER_UART2_BUS_TXBEGIN;
+ }
+}
+
+static void uart2_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
+{
+ /* Compute baud-rate period */
+ uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1;
+
+ UBRR2H = (period) >> 8;
+ UBRR2L = (period);
+
+ //DB(kprintf("uart2_setbaudrate(rate=%ld): period=%d\n", rate, period);)
+}
+
+static void uart2_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
+{
+ UCSR2C = (UCSR2C & ~(BV(UPM21) | BV(UPM20))) | ((parity) << UPM20);
+}
+
+#endif // AVR_HAS_UART2
+
+#if AVR_HAS_UART3
+
+static void uart3_init(
+ UNUSED_ARG(struct SerialHardware *, _hw),
+ UNUSED_ARG(struct Serial *, ser))
+{
+ SER_UART3_BUS_TXINIT;
+ RTS_ON;
+ SER_STROBE_INIT;
+}
+
+static void uart3_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
+{
+ UCSR3B = 0;
+}
+
+static void uart3_enabletxirq(struct SerialHardware *_hw)
+{
+ struct AvrSerial *hw = (struct AvrSerial *)_hw;
+
+ /*
+ * WARNING: racy code here! The tx interrupt
+ * sets hw->sending to false when it runs with
+ * an empty fifo. The order of the statements
+ * in the if-block matters.
+ */
+ if (!hw->sending)
+ {
+ hw->sending = true;
+ SER_UART3_BUS_TXBEGIN;
+ }
+}
+
+static void uart3_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
+{
+ /* Compute baud-rate period */
+ uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1;
+
+ UBRR3H = (period) >> 8;
+ UBRR3L = (period);
+
+ //DB(kprintf("uart3_setbaudrate(rate=%ld): period=%d\n", rate, period);)
+}
+
+static void uart3_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
+{
+ UCSR3C = (UCSR3C & ~(BV(UPM31) | BV(UPM30))) | ((parity) << UPM30);
+}
+
+#endif // AVR_HAS_UART3
+
+
static void spi_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
{
/*
};
#endif // AVR_HAS_UART1
+#if AVR_HAS_UART2
+static const struct SerialHardwareVT UART2_VT =
+{
+ C99INIT(init, uart2_init),
+ C99INIT(cleanup, uart2_cleanup),
+ C99INIT(setBaudrate, uart2_setbaudrate),
+ C99INIT(setParity, uart2_setparity),
+ C99INIT(txStart, uart2_enabletxirq),
+ C99INIT(txSending, tx_sending),
+};
+#endif // AVR_HAS_UART2
+
+#if AVR_HAS_UART3
+static const struct SerialHardwareVT UART3_VT =
+{
+ C99INIT(init, uart3_init),
+ C99INIT(cleanup, uart3_cleanup),
+ C99INIT(setBaudrate, uart3_setbaudrate),
+ C99INIT(setParity, uart3_setparity),
+ C99INIT(txStart, uart3_enabletxirq),
+ C99INIT(txSending, tx_sending),
+};
+#endif // AVR_HAS_UART3
+
static const struct SerialHardwareVT SPI_VT =
{
C99INIT(init, spi_init),
},
C99INIT(sending, false),
},
+#endif
+#if AVR_HAS_UART2
+ {
+ C99INIT(hw, /**/) {
+ C99INIT(table, &UART2_VT),
+ C99INIT(txbuffer, uart2_txbuffer),
+ C99INIT(rxbuffer, uart2_rxbuffer),
+ C99INIT(txbuffer_size, sizeof(uart2_txbuffer)),
+ C99INIT(rxbuffer_size, sizeof(uart2_rxbuffer)),
+ },
+ C99INIT(sending, false),
+ },
+#endif
+#if AVR_HAS_UART3
+ {
+ C99INIT(hw, /**/) {
+ C99INIT(table, &UART3_VT),
+ C99INIT(txbuffer, uart3_txbuffer),
+ C99INIT(rxbuffer, uart3_rxbuffer),
+ C99INIT(txbuffer_size, sizeof(uart3_txbuffer)),
+ C99INIT(rxbuffer_size, sizeof(uart3_rxbuffer)),
+ },
+ C99INIT(sending, false),
+ },
#endif
{
C99INIT(hw, /**/) {
* otherwise we'd stop the serial port with some data
* still pending in the buffer.
*/
-DECLARE_ISR(SIG_UART0_TRANS)
+DECLARE_ISR(USART0_TX_vect)
{
SER_STROBE_ON;
#endif // AVR_HAS_UART1
+#if AVR_HAS_UART2
+
+/**
+ * Serial 2 TX interrupt handler
+ */
+DECLARE_ISR(USART2_UDRE_vect)
+{
+ SER_STROBE_ON;
+
+ struct FIFOBuffer * const txfifo = &ser_handles[SER_UART2]->txfifo;
+
+ if (fifo_isempty(txfifo))
+ {
+ SER_UART2_BUS_TXEND;
+#ifndef SER_UART2_BUS_TXOFF
+ UARTDescs[SER_UART2].sending = false;
+#endif
+ }
+ else
+ {
+ char c = fifo_pop(txfifo);
+ SER_UART2_BUS_TXCHAR(c);
+ }
+
+ SER_STROBE_OFF;
+}
+
+#ifdef SER_UART2_BUS_TXOFF
+/**
+ * Serial port 2 TX complete interrupt handler.
+ *
+ * \sa port 0 TX complete handler.
+ */
+DECLARE_ISR(USART2_TX_vect)
+{
+ SER_STROBE_ON;
+
+ struct FIFOBuffer * const txfifo = &ser_handles[SER_UART2]->txfifo;
+ if (fifo_isempty(txfifo))
+ {
+ SER_UART2_BUS_TXOFF;
+ UARTDescs[SER_UART2].sending = false;
+ }
+ else
+ UCSR2B = BV(BIT_RXCIE2) | BV(BIT_UDRIE2) | BV(BIT_RXEN2) | BV(BIT_TXEN2);
+
+ SER_STROBE_OFF;
+}
+#endif /* SER_UART2_BUS_TXOFF */
+
+#endif // AVR_HAS_UART2
+
+#if AVR_HAS_UART3
+
+/**
+ * Serial 3 TX interrupt handler
+ */
+DECLARE_ISR(USART3_UDRE_vect)
+{
+ SER_STROBE_ON;
+
+ struct FIFOBuffer * const txfifo = &ser_handles[SER_UART3]->txfifo;
+
+ if (fifo_isempty(txfifo))
+ {
+ SER_UART3_BUS_TXEND;
+#ifndef SER_UART3_BUS_TXOFF
+ UARTDescs[SER_UART3].sending = false;
+#endif
+ }
+ else
+ {
+ char c = fifo_pop(txfifo);
+ SER_UART3_BUS_TXCHAR(c);
+ }
+
+ SER_STROBE_OFF;
+}
+
+#ifdef SER_UART3_BUS_TXOFF
+/**
+ * Serial port 3 TX complete interrupt handler.
+ *
+ * \sa port 0 TX complete handler.
+ */
+DECLARE_ISR(USART3_TX_vect)
+{
+ SER_STROBE_ON;
+
+ struct FIFOBuffer * const txfifo = &ser_handles[SER_UART3]->txfifo;
+ if (fifo_isempty(txfifo))
+ {
+ SER_UART3_BUS_TXOFF;
+ UARTDescs[SER_UART3].sending = false;
+ }
+ else
+ UCSR3B = BV(BIT_RXCIE3) | BV(BIT_UDRIE3) | BV(BIT_RXEN3) | BV(BIT_TXEN3);
+
+ SER_STROBE_OFF;
+}
+#endif /* SER_UART3_BUS_TXOFF */
+
+#endif // AVR_HAS_UART3
+
/**
* Serial 0 RX complete interrupt handler.
#endif // AVR_HAS_UART1
+#if AVR_HAS_UART2
+
+/**
+ * Serial 2 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.
+ *
+ * \see DECLARE_ISR(USART2_RX_vect)
+ */
+DECLARE_ISR(USART2_RX_vect)
+{
+ SER_STROBE_ON;
+
+ /* Disable Recv complete IRQ */
+ //UCSR1B &= ~BV(RXCIE);
+ //IRQ_ENABLE;
+
+ /* Should be read before UDR */
+ ser_handles[SER_UART2]->status |= UCSR2A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+
+ /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
+ * not going to accept the incoming data
+ */
+ char c = UDR2;
+ struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART2]->rxfifo;
+ //ASSERT_VALID_FIFO(rxfifo);
+
+ if (UNLIKELY(fifo_isfull(rxfifo)))
+ ser_handles[SER_UART2]->status |= SERRF_RXFIFOOVERRUN;
+ else
+ {
+ fifo_push(rxfifo, c);
+#if CONFIG_SER_HWHANDSHAKE
+ if (fifo_isfull(rxfifo))
+ RTS_OFF;
+#endif
+ }
+ /* Re-enable receive complete int */
+ //IRQ_DISABLE;
+ //UCSR1B |= BV(RXCIE);
+
+ SER_STROBE_OFF;
+}
+
+#endif // AVR_HAS_UART2
+
+#if AVR_HAS_UART3
+
+/**
+ * Serial 3 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.
+ *
+ * \see DECLARE_ISR(USART3_RX_vect)
+ */
+DECLARE_ISR(USART3_RX_vect)
+{
+ SER_STROBE_ON;
+
+ /* Disable Recv complete IRQ */
+ //UCSR1B &= ~BV(RXCIE);
+ //IRQ_ENABLE;
+
+ /* Should be read before UDR */
+ ser_handles[SER_UART3]->status |= UCSR3A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+
+ /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
+ * not going to accept the incoming data
+ */
+ char c = UDR3;
+ struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART3]->rxfifo;
+ //ASSERT_VALID_FIFO(rxfifo);
+
+ if (UNLIKELY(fifo_isfull(rxfifo)))
+ ser_handles[SER_UART3]->status |= SERRF_RXFIFOOVERRUN;
+ else
+ {
+ fifo_push(rxfifo, c);
+#if CONFIG_SER_HWHANDSHAKE
+ if (fifo_isfull(rxfifo))
+ RTS_OFF;
+#endif
+ }
+ /* Re-enable receive complete int */
+ //IRQ_DISABLE;
+ //UCSR1B |= BV(RXCIE);
+
+ SER_STROBE_OFF;
+}
+
+#endif // AVR_HAS_UART3
+
/**
* SPI interrupt handler
*/
-DECLARE_ISR(SIG_SPI)
+DECLARE_ISR(SPI_STC_vect)
{
SER_STROBE_ON;