Fix project generation for ATmega CPU.
[bertos.git] / bertos / cpu / avr / drv / ser_avr.c
index 21da6b8eb2f6ea36f334f7e3ad60db9dfca6d67d..ce44fd1983c08d7027f4b5b04233bb2ae95fd3f1 100644 (file)
  * 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 */
-#include "hw/hw_cpu.h"  /* CLOCK_FREQ */
+#include <hw/hw_cpufreq.h>  /* CPU_FREQ */
 
 #include "cfg/cfg_ser.h"
 
 #include <cfg/macros.h> /* DIV_ROUND */
 #include <cfg/debug.h>
+#include <cfg/cfg_arch.h> // ARCH_NIGHTTEST
 
 #include <drv/ser.h>
 #include <drv/ser_p.h>
@@ -74,7 +74,7 @@
        /*\}*/
 #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
         * - Enable only the RX complete interrupt
         */
        #define SER_UART0_BUS_TXINIT do { \
+               UCSR0A = 0; /* The Arduino Uno bootloader turns on U2X0 */ \
                UCSR0B = BV(BIT_RXCIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0); \
        } while (0)
 #endif
        #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
+       #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
-#elif CPU_AVR_ATMEGA8
+       #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
 
 
-/**
- * \def CONFIG_SER_STROBE
- *
- * This is a debug facility that can be used to
- * monitor SER interrupt activity on an external pin.
- *
- * To use strobes, redefine the macros SER_STROBE_ON,
- * SER_STROBE_OFF and SER_STROBE_INIT and set
- * CONFIG_SER_STROBE to 1.
- */
-#if !defined(CONFIG_SER_STROBE) || !CONFIG_SER_STROBE
-       #define SER_STROBE_ON    do {/*nop*/} while(0)
-       #define SER_STROBE_OFF   do {/*nop*/} while(0)
-       #define SER_STROBE_INIT  do {/*nop*/} while(0)
-#endif
-
-
 /* From the high-level serial driver */
 extern struct Serial *ser_handles[SER_CNT];
 
@@ -313,6 +424,14 @@ static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
        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];
 
@@ -339,7 +458,20 @@ struct AvrSerial
        volatile bool sending;
 };
 
+static uint16_t uart_period(unsigned long bps)
+{
+       uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, bps) - 1;
+
+       #ifdef _DEBUG
+               long skew = bps - (long)(period + 1) * (CPU_FREQ / 16);
+               /* 8N1 is reliable within 3% skew */
+               if ((unsigned long)ABS(skew) > bps / (100 / 3))
+                       kprintf("Baudrate off by %ldbps\n", skew);
+       #endif
 
+       //DB(kprintf("uart_period(bps=%lu): period=%u\n", bps, period);)
+       return period;
+}
 
 /*
  * Callbacks
@@ -376,15 +508,12 @@ static void uart0_enabletxirq(struct SerialHardware *_hw)
 
 static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
 {
-       /* Compute baud-rate period */
-       uint16_t period = DIV_ROUND(CLOCK_FREQ / 16UL, rate) - 1;
+       uint16_t period = uart_period(rate);
 
 #if !CPU_AVR_ATMEGA103
-       UBRR0H = (period) >> 8;
+       UBRR0H = period >> 8;
 #endif
-       UBRR0L = (period);
-
-       //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
+       UBRR0L = period;
 }
 
 static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
@@ -429,13 +558,9 @@ static void uart1_enabletxirq(struct SerialHardware *_hw)
 
 static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
 {
-       /* Compute baud-rate period */
-       uint16_t period = DIV_ROUND(CLOCK_FREQ / 16UL, rate) - 1;
-
-       UBRR1H = (period) >> 8;
-       UBRR1L = (period);
-
-       //DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
+       uint16_t period = uart_period(rate);
+       UBRR1H = period >> 8;
+       UBRR1L = period;
 }
 
 static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
@@ -445,6 +570,101 @@ static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity
 
 #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)
+{
+       uint16_t period = uart_period(rate);
+       UBRR2H = period >> 8;
+       UBRR2L = 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)
+{
+       uint16_t period = uart_period(rate);
+       UBRR3H = period >> 8;
+       UBRR3L = 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))
 {
        /*
@@ -470,7 +690,7 @@ static void spi_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct
         * - as input but tied high forever!
         * This driver set the pin as output.
         */
-       #warning SPI SS pin set as output for proper operation, check schematics for possible conflicts.
+       #warning FIXME:SPI SS pin set as output for proper operation, check schematics for possible conflicts.
        ATOMIC(SPI_DDR |= BV(SPI_SS_BIT));
 
        ATOMIC(SPI_DDR &= ~BV(SPI_MISO_BIT));
@@ -601,6 +821,30 @@ static const struct SerialHardwareVT UART1_VT =
 };
 #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),
@@ -634,6 +878,30 @@ static struct AvrSerial UARTDescs[SER_CNT] =
                },
                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, /**/) {
@@ -661,10 +929,10 @@ struct SerialHardware *ser_hw_getdesc(int unit)
 #if CONFIG_SER_HWHANDSHAKE
 
 /// This interrupt is triggered when the CTS line goes high
-SIGNAL(SIG_CTS)
+DECLARE_ISR(SIG_CTS)
 {
        // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
-       UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+       UCSR0B = BV(BIT_RXCIE0) | BV(BIT_UDRIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0);
        EIMSK &= ~EIMSKF_CTS;
 }
 
@@ -674,7 +942,7 @@ SIGNAL(SIG_CTS)
 /**
  * Serial 0 TX interrupt handler
  */
-SIGNAL(USART0_UDRE_vect)
+DECLARE_ISR(USART0_UDRE_vect)
 {
        SER_STROBE_ON;
 
@@ -692,7 +960,7 @@ SIGNAL(USART0_UDRE_vect)
        {
                // Disable rx interrupt and tx, enable CTS interrupt
                // UNTESTED
-               UCSR0B = BV(RXCIE) | BV(RXEN) | BV(TXEN);
+               UCSR0B = BV(BIT_RXCIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0);
                EIFR |= EIMSKF_CTS;
                EIMSK |= EIMSKF_CTS;
        }
@@ -722,7 +990,7 @@ SIGNAL(USART0_UDRE_vect)
  * otherwise we'd stop the serial port with some data
  * still pending in the buffer.
  */
-SIGNAL(SIG_UART0_TRANS)
+DECLARE_ISR(USART0_TX_vect)
 {
        SER_STROBE_ON;
 
@@ -733,7 +1001,7 @@ SIGNAL(SIG_UART0_TRANS)
                UARTDescs[SER_UART0].sending = false;
        }
        else
-               UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+               UCSR0B = BV(BIT_RXCIE0) | BV(BIT_UDRIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0);
 
        SER_STROBE_OFF;
 }
@@ -745,7 +1013,7 @@ SIGNAL(SIG_UART0_TRANS)
 /**
  * Serial 1 TX interrupt handler
  */
-SIGNAL(USART1_UDRE_vect)
+DECLARE_ISR(USART1_UDRE_vect)
 {
        SER_STROBE_ON;
 
@@ -763,7 +1031,7 @@ SIGNAL(USART1_UDRE_vect)
        {
                // Disable rx interrupt and tx, enable CTS interrupt
                // UNTESTED
-               UCSR1B = BV(RXCIE) | BV(RXEN) | BV(TXEN);
+               UCSR1B = BV(BIT_RXCIE1) | BV(BIT_RXEN1) | BV(BIT_TXEN1);
                EIFR |= EIMSKF_CTS;
                EIMSK |= EIMSKF_CTS;
        }
@@ -783,7 +1051,7 @@ SIGNAL(USART1_UDRE_vect)
  *
  * \sa port 0 TX complete handler.
  */
-SIGNAL(SIG_UART1_TRANS)
+DECLARE_ISR(USART1_TX_vect)
 {
        SER_STROBE_ON;
 
@@ -794,7 +1062,7 @@ SIGNAL(SIG_UART1_TRANS)
                UARTDescs[SER_UART1].sending = false;
        }
        else
-               UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+               UCSR1B = BV(BIT_RXCIE1) | BV(BIT_UDRIE1) | BV(BIT_RXEN1) | BV(BIT_TXEN1);
 
        SER_STROBE_OFF;
 }
@@ -802,6 +1070,110 @@ SIGNAL(SIG_UART1_TRANS)
 
 #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.
@@ -818,7 +1190,7 @@ SIGNAL(SIG_UART1_TRANS)
  *       RXCIE is cleared.  Unfortunately the RXC flag is read-only
  *       and can't be cleared by code.
  */
-SIGNAL(USART0_RX_vect)
+DECLARE_ISR(USART0_RX_vect)
 {
        SER_STROBE_ON;
 
@@ -866,9 +1238,9 @@ SIGNAL(USART0_RX_vect)
  * is heavily loaded, because an interrupt could be retriggered
  * when executing the handler prologue before RXCIE is disabled.
  *
- * \see SIGNAL(USART1_RX_vect)
+ * \see DECLARE_ISR(USART1_RX_vect)
  */
-SIGNAL(USART1_RX_vect)
+DECLARE_ISR(USART1_RX_vect)
 {
        SER_STROBE_ON;
 
@@ -905,11 +1277,111 @@ SIGNAL(USART1_RX_vect)
 
 #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
  */
-SIGNAL(SIG_SPI)
+DECLARE_ISR(SPI_STC_vect)
 {
        SER_STROBE_ON;