Merge contributed patch to extend support of atxmega.
[bertos.git] / bertos / cpu / avr / drv / ser_xmega.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2010 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2011 Onno <developer@gorgoz.org>
31  *
32  * -->
33  *
34  * \brief AVR XMEGA USART driver (Implementation)
35  *
36  * This file is heavily inspired by the AVR implementation for BeRTOS,
37  * but uses a different approach for implementing the different debug
38  * ports, by using the USART_t structs.
39  *
40  * \author Onno <developer@gorgoz.org>
41  * notest:all
42  */
43
44 #include "hw/hw_ser.h"     /* Required for bus macros overrides */
45 #include <hw/hw_cpufreq.h> /* CPU_FREQ */
46
47 #include <cfg/macros.h>    /* DIV_ROUND */
48 #include <cfg/debug.h>     /* debug configuration */
49
50 #include <drv/ser.h>
51 #include <drv/ser_p.h>
52 #include <drv/timer.h>
53
54 #include <struct/fifobuf.h>
55
56 #include <avr/io.h>        /* AVR IO ports and structures */
57 #include <avr/interrupt.h> /* AVR Interrupt methods */
58
59 /*
60  * Scalefactor to use for computing the baudrate
61  * this scalefactor should be an integer value between -7
62  * and 7
63  */
64 #ifndef USART_SCALE_FACTOR
65         #define USART_SCALE_FACTOR (-7)
66 #else
67         #if USART_SCALE_FACTOR > 7 || USART_SCALE_FACTOR < -7
68                 #error USART_SCALE_FACTOR should be an integer between -7 and 7
69         #endif
70 #endif
71
72 /* Helper macros, mostly taken from the Atmel Examples
73  * Slightly alterd to match the BeRTOS naming convention
74  */
75
76 /* \brief Set USART baud rate.
77  *
78  *  Sets the USART's baud rate register.
79  *
80  *  UBRR_Value   : Value written to UBRR
81  *  ScaleFactor  : Time Base Generator Scale Factor
82  *
83  *  Equation for calculation of BSEL value in asynchronous normal speed mode:
84  *      If ScaleFactor >= 0
85  *              BSEL = ((I/O clock frequency)/(2^(ScaleFactor)*16*Baudrate))-1
86  *      If ScaleFactor < 0
87  *              BSEL = (1/(2^(ScaleFactor)*16))*(((I/O clock frequency)/Baudrate)-1)
88  *
89  *      \note See XMEGA manual for equations for calculation of BSEL value in other
90  *        modes.
91  *
92  *  \param _usart          Pointer to the USART module.
93  *  \param _bselValue      Value to write to BSEL part of Baud control register.
94  *                         Use uint16_t type.
95  *  \param _bScaleFactor   USART baud rate scale factor.
96  *                         Use uint8_t type
97  */
98 #define USART_SET_BAUDRATE(_usart, _bselValue, _bScaleFactor)                  \
99         (_usart)->BAUDCTRLA =(uint8_t)_bselValue;                                           \
100         (_usart)->BAUDCTRLB =(_bScaleFactor << USART_BSCALE0_bp)|(_bselValue >> 8)
101
102 /* \brief Enable USART receiver.
103  *
104  *  \param _usart    Pointer to the USART module
105  */
106 #define USART_RX_ENABLE(_usart) ((_usart)->CTRLB |= USART_RXEN_bm)
107
108 /* \brief Disable USART receiver.
109  *
110  *  \param _usart Pointer to the USART module.
111  */
112 #define USART_RX_DISABLE(_usart) ((_usart)->CTRLB &= ~USART_RXEN_bm)
113
114 /* \brief Enable USART transmitter.
115  *
116  *  \param _usart Pointer to the USART module.
117  */
118 #define USART_TX_ENABLE(_usart) ((_usart)->CTRLB |= USART_TXEN_bm)
119
120 /* \brief Disable USART transmitter.
121  *
122  *  \param _usart Pointer to the USART module.
123  */
124 #define USART_TX_DISABLE(_usart) ((_usart)->CTRLB &= ~USART_TXEN_bm)
125
126 /* \brief Set USART RXD interrupt level.
127  *
128  *  Sets the interrupt level on RX Complete interrupt.
129  *
130  *  \param _usart        Pointer to the USART module.
131  *  \param _rxdIntLevel  Interrupt level of the RXD interrupt.
132  *                       Use USART_RXCINTLVL_t type.
133  */
134 #define USART_SET_RX_INTERRUPT_LEVEL(_usart, _rxdIntLevel)                      \
135         ((_usart)->CTRLA = ((_usart)->CTRLA & ~USART_RXCINTLVL_gm) | _rxdIntLevel)
136
137 /* \brief Set USART TXD interrupt level.
138  *
139  *  Sets the interrupt level on TX Complete interrupt.
140  *
141  *  \param _usart        Pointer to the USART module.
142  *  \param _txdIntLevel  Interrupt level of the TXD interrupt.
143  *                       Use USART_TXCINTLVL_t type.
144  */
145 #define USART_SET_TX_INTERRUPT_LEVEL(_usart, _txdIntLevel)                      \
146         (_usart)->CTRLA = ((_usart)->CTRLA & ~USART_TXCINTLVL_gm) | _txdIntLevel
147
148 /* \brief Set USART DRE interrupt level.
149  *
150  *  Sets the interrupt level on Data Register interrupt.
151  *
152  *  \param _usart        Pointer to the USART module.
153  *  \param _dreIntLevel  Interrupt level of the DRE interrupt.
154  *                       Use USART_DREINTLVL_t type.
155  */
156 #define USART_SET_DRE_INTERRUPT_LEVEL(_usart, _dreIntLevel)                      \
157         (_usart)->CTRLA = ((_usart)->CTRLA & ~USART_DREINTLVL_gm) | _dreIntLevel
158
159 /* \brief Set the mode the USART run in.
160  *
161  * Set the mode the USART run in. The default mode is asynchronous mode.
162  *
163  *  \param  _usart       Pointer to the USART module register section.
164  *  \param  _usartMode   Selects the USART mode. Use  USART_CMODE_t type.
165  *
166  *  USART modes:
167  *  - 0x0        : Asynchronous mode.
168  *  - 0x1        : Synchronous mode.
169  *  - 0x2        : IrDA mode.
170  *  - 0x3        : Master SPI mode.
171  */
172 #define USART_SET_MODE(_usart, _usartMode)                                      \
173         ((_usart)->CTRLC = ((_usart)->CTRLC & (~USART_CMODE_gm)) | _usartMode)
174
175 /* \brief Check if data register empty flag is set.
176  *
177  *  \param _usart      The USART module.
178  */
179 #define USART_IS_TX_DATA_REGISTER_EMPTY(_usart) (((_usart)->STATUS & USART_DREIF_bm) != 0)
180
181 /* \brief Put data (5-8 bit character).
182  *
183  *  Use the macro USART_IsTXDataRegisterEmpty before using this function to
184  *  put data to the TX register.
185  *
186  *  \param _usart      The USART module.
187  *  \param _data       The data to send.
188  */
189 #define USART_PUT_CHAR(_usart, _data) ((_usart)->DATA = _data)
190
191 /* \brief Checks if the RX complete interrupt flag is set.
192  *
193  *   Checks if the RX complete interrupt flag is set.
194  *
195  *  \param _usart     The USART module.
196  */
197 #define USART_IS_RX_COMPLETE(_usart) (((_usart)->STATUS & USART_RXCIF_bm) != 0)
198
199 /* \brief Get received data (5-8 bit character).
200  *
201  *  This macro reads out the RX register.
202  *  Use the macro USART_RX_Complete to check if anything is received.
203  *
204  *  \param _usart     The USART module.
205  *
206  *  \retval           Received data.
207  */
208 #define USART_GET_CHAR(_usart)  ((_usart)->DATA)
209
210 /* configurable macros */
211
212 #if !CONFIG_SER_HWHANDSHAKE
213         /**
214          * \name Hardware handshake (RTS/CTS).
215          * \{
216          */
217         #define RTS_ON      do {} while (0)
218         #define RTS_OFF     do {} while (0)
219         #define IS_CTS_ON   true
220         #define EIMSKF_CTS  0 /**< Dummy value, must be overridden */
221         /*\}*/
222 #endif
223
224 /*
225  * \name Overridable serial bus hooks
226  *
227  * These can be redefined in hw.h to implement
228  * special bus policies such as half-duplex, 485, etc.
229  *
230  *
231  * \code
232  *  TXBEGIN      TXCHAR      TXEND  TXOFF
233  *    |   __________|__________ |     |
234  *    |   |   |   |   |   |   | |     |
235  *    v   v   v   v   v   v   v v     v
236  * ______  __  __  __  __  __  __  ________________
237  *       \/  \/  \/  \/  \/  \/  \/
238  * ______/\__/\__/\__/\__/\__/\__/
239  *
240  * \endcode
241  *
242  * \{
243  */
244
245 #ifndef SER_UART_BUS_TXINIT
246         /*
247          * Default TXINIT macro - invoked in uart_init()
248          *
249          * - Enable both the receiver and the transmitter
250          * - Enable only the RX complete interrupt
251          */
252         #define SER_UART_BUS_TXINIT(_usart) do { \
253                 USART_RX_ENABLE(_usart); \
254                 USART_TX_ENABLE(_usart); \
255                 USART_SET_RX_INTERRUPT_LEVEL(_usart, USART_RXCINTLVL_MED_gc); \
256         } while (0)
257 #endif
258
259 #ifndef SER_UART_BUS_TXBEGIN
260         /*
261          * Invoked before starting a transmission
262          *
263          * - Enable both the receiver and the transmitter
264          * - Enable both the RX complete and UDR empty interrupts
265          */
266         #define SER_UART_BUS_TXBEGIN(_usart) do { \
267                 USART_SET_RX_INTERRUPT_LEVEL(_usart, USART_RXCINTLVL_MED_gc); \
268                 USART_SET_DRE_INTERRUPT_LEVEL(_usart, USART_DREINTLVL_MED_gc);\
269         } while (0)
270 #endif
271
272 #ifndef SER_UART_BUS_TXCHAR
273         /*
274          * Invoked to send one character.
275          */
276         #define SER_UART_BUS_TXCHAR(_usart, c) do { \
277                 USART_PUT_CHAR(_usart, c); \
278         } while (0)
279 #endif
280
281 #ifndef SER_UART_BUS_TXEND
282         /*
283          * Invoked as soon as the txfifo becomes empty
284          *
285          * - Keep both the receiver and the transmitter enabled
286          * - Keep the RX complete interrupt enabled
287          * - Disable the UDR empty interrupt
288          */
289         #define SER_UART_BUS_TXEND(_usart) do { \
290                 USART_SET_DRE_INTERRUPT_LEVEL(_usart, USART_DREINTLVL_OFF_gc); \
291         } while (0)
292 #endif
293
294 #ifndef SER_UART_BUS_TXOFF
295         /*
296          * \def SER_UART_BUS_TXOFF
297          *
298          * Invoked after the last character has been transmitted
299          *
300          * The default is no action.
301          */
302         #ifdef __doxygen__
303         #define SER_UART_BUS_TXOFF(_usart)
304         #endif
305 #endif
306
307 /*\}*/
308
309 /* From the high-level serial driver */
310 extern struct Serial *ser_handles[SER_CNT];
311
312 /* TX and RX buffers */
313 #if IMPLEMENT_SER_UART0
314         static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
315         static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
316 #endif
317 #if IMPLEMENT_SER_UART1
318         static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
319         static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
320 #endif
321 #if IMPLEMENT_SER_UART2
322         static unsigned char uart2_txbuffer[CONFIG_UART2_TXBUFSIZE];
323         static unsigned char uart2_rxbuffer[CONFIG_UART2_RXBUFSIZE];
324 #endif
325 #if IMPLEMENT_SER_UART3
326         static unsigned char uart3_txbuffer[CONFIG_UART3_TXBUFSIZE];
327         static unsigned char uart3_rxbuffer[CONFIG_UART3_RXBUFSIZE];
328 #endif
329 #if IMPLEMENT_SER_UART4
330         static unsigned char uart4_txbuffer[CONFIG_UART4_TXBUFSIZE];
331         static unsigned char uart4_rxbuffer[CONFIG_UART4_RXBUFSIZE];
332 #endif
333 #if IMPLEMENT_SER_UART5
334         static unsigned char uart5_txbuffer[CONFIG_UART5_TXBUFSIZE];
335         static unsigned char uart5_rxbuffer[CONFIG_UART5_RXBUFSIZE];
336 #endif
337 #if IMPLEMENT_SER_UART6
338         static unsigned char uart6_txbuffer[CONFIG_UART6_TXBUFSIZE];
339         static unsigned char uart6_rxbuffer[CONFIG_UART6_RXBUFSIZE];
340 #endif
341 #if IMPLEMENT_SER_UART7
342         static unsigned char uart7_txbuffer[CONFIG_UART7_TXBUFSIZE];
343         static unsigned char uart7_rxbuffer[CONFIG_UART7_RXBUFSIZE];
344 #endif
345
346 /*
347  * Internal hardware state structure
348  *
349  * The \a sending variable is true while the transmission
350  * interrupt is retriggering itself.
351  *
352  * the \a usart variable will point to the USART_t structure
353  * that should be used.
354  *
355  * the \a port variable will point to the PORT_t structure
356  * that should be modified to set the tx pin as an output and the
357  * rx pin as an input
358  *
359  * the \a txpin variable will hold the pinnumber of the pin to use
360  * as the tx output
361  *
362  * the \a rxpin variable will hold the pinnumber of the pin to use
363  * as the rx input
364  *
365  * For the USARTs the \a sending flag is useful for taking specific
366  * actions before sending a burst of data, at the start of a trasmission
367  * but not before every char sent.
368  *
369  * For the SPI, this flag is necessary because the SPI sends and receives
370  * bytes at the same time and the SPI IRQ is unique for send/receive.
371  * The only way to start transmission is to write data in SPDR (this
372  * is done by spi_starttx()). We do this *only* if a transfer is
373  * not already started.
374  */
375 struct AvrxmegaSerial
376 {
377         struct SerialHardware hw;
378         volatile bool sending;
379         volatile USART_t* usart;
380         volatile PORT_t* port;
381         uint8_t txpin;
382         uint8_t rxpin;
383 };
384
385 /*
386  * Callbacks
387  * The same callbacks are used for all USARTS.
388  * By casting the SerialHardware structure to the AvrxmegaSerial
389  * structure a pointer to the USART_t structure can be obtained,
390  * to perform the callback for the specific USART.
391  * This methode might cost some more cpu time, but saves on
392  * code duplication and code size.
393  */
394
395
396 /*
397  * \brief Initializes the uart
398  *
399  * The TX pin of the uart will be set as an outputpin
400  * The RX pin of the uart will be set as an inputpin
401  * The usart will be initialized
402  * \see SER_UART_BUS_TXINIT
403  *
404  * \param _hw struct AvrxmegaSerial
405  * \param ser Unused
406  */
407 static void uart_init(struct SerialHardware * _hw, UNUSED_ARG(struct Serial *, ser))
408 {
409         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
410         //set transmit pin as output
411         hw->port->DIRSET = BV(hw->txpin);
412         hw->port->OUTCLR = BV(hw->txpin);
413         //set receive pin as input
414         hw->port->DIRCLR = BV(hw->rxpin);
415         //initialize the USART
416         SER_UART_BUS_TXINIT(hw->usart);
417         RTS_ON;
418         SER_STROBE_INIT;
419 }
420
421 /*
422  * \brief Cleans up / Disables the uart
423  *
424  * \param _hw struct AvrxmegaSerial
425  */
426 static void uart_cleanup(struct SerialHardware * _hw)
427 {
428         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
429         hw->usart->CTRLA = 0;
430         hw->usart->CTRLB = 0;
431 }
432
433 /*
434  * \brief Enableds the TX interrupt
435  *
436  * \param _hw struct AvrxmegaSerial
437  */
438 static void uart_enabletxirq(struct SerialHardware *_hw)
439 {
440         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
441
442         /*
443          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
444          * when it runs with an empty fifo.  The order of statements in the
445          * if-block matters.
446          */
447         if (!hw->sending)
448         {
449                 hw->sending = true;
450                 SER_UART_BUS_TXBEGIN(hw->usart);
451         }
452 }
453
454 /*
455  * \brief  sets the uart to the provided baudrate
456  *
457  * For setting the baudrate an scale factor (bscale) and a period
458  * setting (BSEL) is required.
459  *
460  * The scale factor should be privided by defining USART_SCALE_FACTOR
461  *
462  * Atmel specifies BSEL for normal speed mode and bscale >= 0 as:
463  * BSEL = (cpu_freq / ((2^bscale) * 16 * rate)) - 1
464  * To allow BSEL to be calculated with an power function this can be
465  * rewriten to:
466  * BSEL = BSEL = (cpu_freq / ((1 << bscale) * 16 * rate)) - 1
467  *
468  * Atmel specifies BSEL for normal speed mode and bscale < 0 as:
469  * BSEL = (1 / (2^bscale)) * ( (cpu_freq / (16 * rate)) - 1)
470  * To calculte this float atheritmic is required as the second product will be smaller
471  * than zero in a lot of cases.
472  * To allow BSEL to be calculated with interger devision and no power function
473  * this can be rewriten by folowing simple math rules to:
474  * BSEL = ((1 << -bscale) * (cpu_freq - (16 * rate)) / (16 * rate)
475  *
476  * \param _hw struct AvrxmegaSerial
477  * \param _rate the required baudrate
478  *
479  */
480 static void uart_setbaudrate(struct SerialHardware * _hw, unsigned long _rate)
481 {
482         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
483         /* Compute baud-rate period, this requires a valid USART_SCALE_FACTOR */
484         #if USART_SCALE_FACTOR < 0
485                 uint16_t bsel = DIV_ROUND((1 << (-(USART_SCALE_FACTOR))) * (CPU_FREQ - (16 * _rate)), 16 * _rate);
486         #else
487                 uint16_t bsel = DIV_ROUND(CPU_FREQ, (1 << (USART_SCALE_FACTOR)) * 16 * _rate) - 1;
488         #endif
489         USART_SET_BAUDRATE(hw->usart, bsel, USART_SCALE_FACTOR);
490 }
491
492 /*
493  * \brief Sets the parity of the uart
494  *
495  * \param _hw struct AvrxmegaSerial
496  * \param _parity the parity to set
497  */
498 static void uart_setparity(struct SerialHardware * _hw, int _parity)
499 {
500         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
501         USART_SET_MODE(hw->usart, _parity);
502 }
503
504 /*
505  * \brief Returns true if Transmitter is sending
506  *
507  * \param _hw struct AvrxmegaSerial
508  * \return true if transmitter is sending
509  */
510 static bool tx_sending(struct SerialHardware* _hw)
511 {
512         struct AvrxmegaSerial *hw = (struct AvrxmegaSerial *)_hw;
513         return hw->sending;
514 }
515
516
517 // FIXME: move into compiler.h?  Ditch?
518 #if COMPILER_C99
519         #define C99INIT(name,val) .name = val
520 #elif defined(__GNUC__)
521         #define C99INIT(name,val) name: val
522 #else
523         #warning No designated initializers, double check your code
524         #define C99INIT(name,val) (val)
525 #endif
526
527 /*
528  * High-level interface data structures
529  */
530 static const struct SerialHardwareVT UART_VT =
531 {
532         C99INIT(init, uart_init),
533         C99INIT(cleanup, uart_cleanup),
534         C99INIT(setBaudrate, uart_setbaudrate),
535         C99INIT(setParity, uart_setparity),
536         C99INIT(txStart, uart_enabletxirq),
537         C99INIT(txSending, tx_sending)
538 };
539
540 /*
541  * Xmega UARTDesc data structure
542  * Contains all information required to manage a serial port.
543  *
544  * Serial ports are assigned (as far as present on the xmega family) as:
545  * SER_UART0 -> USARTC0
546  * SER_UART1 -> USARTD0
547  * SER_UART2 -> USARTE0
548  * SER_UART3 -> USARTC1
549  * SER_UART4 -> USARTD1
550  * SER_UART5 -> USARTE1
551  * SER_UART6 -> USARTF0
552  * SER_UART7 -> USARTF1
553  */
554 static struct AvrxmegaSerial UARTDescs[SER_CNT] =
555 {
556 #if IMPLEMENT_SER_UART0
557         {
558                 C99INIT(hw, /**/) {
559                         C99INIT(table, &UART_VT),
560                         C99INIT(txbuffer, uart0_txbuffer),
561                         C99INIT(rxbuffer, uart0_rxbuffer),
562                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
563                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
564                 },
565                 C99INIT(sending, false),
566                 C99INIT(usart, &USARTC0),
567                 C99INIT(port, &PORTC),
568                 C99INIT(txpin, PIN3_bp),
569                 C99INIT(rxpin, PIN2_bp),
570         },
571 #endif
572 #if IMPLEMENT_SER_UART1
573         {
574                 C99INIT(hw, /**/) {
575                         C99INIT(table, &UART_VT),
576                         C99INIT(txbuffer, uart1_txbuffer),
577                         C99INIT(rxbuffer, uart1_rxbuffer),
578                         C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
579                         C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
580                 },
581                 C99INIT(sending, false),
582                 C99INIT(usart, &USARTD0),
583                 C99INIT(port, &PORTD),
584                 C99INIT(txpin, PIN3_bp),
585                 C99INIT(rxpin, PIN2_bp),
586         },
587 #endif
588 #if IMPLEMENT_SER_UART2
589         {
590                 C99INIT(hw, /**/) {
591                         C99INIT(table, &UART_VT),
592                         C99INIT(txbuffer, uart2_txbuffer),
593                         C99INIT(rxbuffer, uart2_rxbuffer),
594                         C99INIT(txbuffer_size, sizeof(uart2_txbuffer)),
595                         C99INIT(rxbuffer_size, sizeof(uart2_rxbuffer)),
596                 },
597                 C99INIT(sending, false),
598                 C99INIT(usart, &USARTE0),
599                 C99INIT(port, &PORTE),
600                 C99INIT(txpin, PIN3_bp),
601                 C99INIT(rxpin, PIN2_bp),
602         },
603 #endif
604 #if IMPLEMENT_SER_UART3
605         {
606                 C99INIT(hw, /**/) {
607                         C99INIT(table, &UART_VT),
608                         C99INIT(txbuffer, uart3_txbuffer),
609                         C99INIT(rxbuffer, uart3_rxbuffer),
610                         C99INIT(txbuffer_size, sizeof(uart3_txbuffer)),
611                         C99INIT(rxbuffer_size, sizeof(uart3_rxbuffer)),
612                 },
613                 C99INIT(sending, false),
614                 C99INIT(usart, &USARTC1),
615                 C99INIT(port, &PORTC),
616                 C99INIT(txpin, PIN7_bp),
617                 C99INIT(rxpin, PIN6_bp),
618         },
619 #endif
620 #if IMPLEMENT_SER_UART4
621         {
622                 C99INIT(hw, /**/) {
623                         C99INIT(table, &UART_VT),
624                         C99INIT(txbuffer, uart4_txbuffer),
625                         C99INIT(rxbuffer, uart4_rxbuffer),
626                         C99INIT(txbuffer_size, sizeof(uart4_txbuffer)),
627                         C99INIT(rxbuffer_size, sizeof(uart4_rxbuffer)),
628                 },
629                 C99INIT(sending, false),
630                 C99INIT(usart, &USARTD1),
631                 C99INIT(port, &PORTD),
632                 C99INIT(txpin, PIN7_bp),
633                 C99INIT(rxpin, PIN6_bp),
634         },
635 #endif
636 #if IMPLEMENT_SER_UART5
637         {
638                 C99INIT(hw, /**/) {
639                         C99INIT(table, &UART_VT),
640                         C99INIT(txbuffer, uart5_txbuffer),
641                         C99INIT(rxbuffer, uart5_rxbuffer),
642                         C99INIT(txbuffer_size, sizeof(uart5_txbuffer)),
643                         C99INIT(rxbuffer_size, sizeof(uart5_rxbuffer)),
644                 },
645                 C99INIT(sending, false),
646                 C99INIT(usart, &USARTE1),
647                 C99INIT(port, &PORTE),
648                 C99INIT(txpin, PIN7_bp),
649                 C99INIT(rxpin, PIN6_bp),
650         },
651 #endif
652 #if IMPLEMENT_SER_UART6
653         {
654                 C99INIT(hw, /**/) {
655                         C99INIT(table, &UART_VT),
656                         C99INIT(txbuffer, uart6_txbuffer),
657                         C99INIT(rxbuffer, uart6_rxbuffer),
658                         C99INIT(txbuffer_size, sizeof(uart6_txbuffer)),
659                         C99INIT(rxbuffer_size, sizeof(uart6_rxbuffer)),
660                 },
661                 C99INIT(sending, false),
662                 C99INIT(usart, &USARTF0),
663                 C99INIT(port, &PORTF),
664                 C99INIT(txpin, PIN3_bp),
665                 C99INIT(rxpin, PIN2_bp),
666         },
667 #endif
668 #if IMPLEMENT_SER_UART7
669         {
670                 C99INIT(hw, /**/) {
671                         C99INIT(table, &UART_VT),
672                         C99INIT(txbuffer, uart7_txbuffer),
673                         C99INIT(rxbuffer, uart7_rxbuffer),
674                         C99INIT(txbuffer_size, sizeof(uart7_txbuffer)),
675                         C99INIT(rxbuffer_size, sizeof(uart7_rxbuffer)),
676                 },
677                 C99INIT(sending, false),
678                 C99INIT(usart, &USARTF1),
679                 C99INIT(port, &PORTF),
680                 C99INIT(txpin, PIN7_bp),
681                 C99INIT(rxpin, PIN6_bp),
682         }
683 #endif
684 };
685
686 struct SerialHardware *ser_hw_getdesc(int unit)
687 {
688         ASSERT(unit < SER_CNT);
689         return &UARTDescs[unit].hw;
690 }
691
692
693 /*
694  * Interrupt handlers
695  */
696 static inline void usart_handleDreInterrupt(uint8_t usartNumber)
697 {
698         SER_STROBE_ON;
699         struct FIFOBuffer * const txfifo = &ser_handles[usartNumber]->txfifo;
700         if (fifo_isempty(txfifo))
701         {
702                 SER_UART_BUS_TXEND(UARTDescs[usartNumber].usart);
703                 #ifndef SER_UART_BUS_TXOFF
704                         UARTDescs[usartNumber].sending = false;
705                 #endif
706         }
707         else
708         {
709                 char c = fifo_pop(txfifo);
710                 SER_UART_BUS_TXCHAR(UARTDescs[usartNumber].usart, c);
711         }
712         SER_STROBE_OFF;
713 }
714
715 #define USART_DRE_INTERRUPT_VECTOR(_vector, _usart)             \
716 DECLARE_ISR(_vector)                                                                            \
717 {                                                                                                                       \
718         usart_handleDreInterrupt( _usart );     \
719 }
720
721 /*
722  * Serial RX complete interrupt handler.
723  *
724  * This handler is interruptible.
725  * Interrupt are reenabled as soon as recv complete interrupt is
726  * disabled. Using INTERRUPT() is troublesome when the serial
727  * is heavily loaded, because an interrupt could be retriggered
728  * when executing the handler prologue before RXCIE is disabled.
729  */
730 static inline void USART_handleRXCInterrupt(uint8_t usartNumber)
731 {
732         SER_STROBE_ON;
733         /* read status */
734         ser_handles[usartNumber]->status |=     (UARTDescs[usartNumber].usart)->STATUS & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
735         /* To clear the RXC flag we must _always_ read the UDR even when we're
736          * not going to accept the incoming data, otherwise a new interrupt
737          * will occur once the handler terminates.
738          */
739         char c = (UARTDescs[usartNumber].usart)->DATA;
740         struct FIFOBuffer * const rxfifo = &ser_handles[usartNumber]->rxfifo;
741         if (fifo_isfull(rxfifo))
742         {
743                 ser_handles[usartNumber]->status |= SERRF_RXFIFOOVERRUN;
744         }
745         else
746         {
747                 fifo_push(rxfifo, c);
748                 #if CONFIG_SER_HWHANDSHAKE
749                         if (fifo_isfull(rxfifo))
750                         {
751                                 RTS_OFF(UARTDescs[usartNumber].usart);
752                         }
753                 #endif
754         }
755         SER_STROBE_OFF;
756 }
757
758 #define USART_RXC_INTERRUPT_VECTOR(_vector, _usart)     \
759 DECLARE_ISR(_vector)                                                            \
760 {                                                                                                       \
761         USART_handleRXCInterrupt( _usart );                             \
762 }
763
764 #if IMPLEMENT_SER_UART0
765         USART_DRE_INTERRUPT_VECTOR(USARTC0_DRE_vect, SER_UART0)
766         USART_RXC_INTERRUPT_VECTOR(USARTC0_RXC_vect, SER_UART0)
767 #endif
768 #if IMPLEMENT_SER_UART1
769         USART_DRE_INTERRUPT_VECTOR(USARTD0_DRE_vect, SER_UART1)
770         USART_RXC_INTERRUPT_VECTOR(USARTD0_RXC_vect, SER_UART1)
771 #endif
772 #if IMPLEMENT_SER_UART2
773         USART_DRE_INTERRUPT_VECTOR(USARTE0_DRE_vect, SER_UART2)
774         USART_RXC_INTERRUPT_VECTOR(USARTE0_RXC_vect, SER_UART2)
775 #endif
776 #if IMPLEMENT_SER_UART3
777         USART_DRE_INTERRUPT_VECTOR(USARTC1_DRE_vect, SER_UART3)
778         USART_RXC_INTERRUPT_VECTOR(USARTC1_RXC_vect, SER_UART3)
779 #endif
780 #if IMPLEMENT_SER_UART4
781         USART_DRE_INTERRUPT_VECTOR(USARTD1_DRE_vect, SER_UART4)
782         USART_RXC_INTERRUPT_VECTOR(USARTD1_RXC_vect, SER_UART4)
783 #endif
784 #if IMPLEMENT_SER_UART5
785         USART_DRE_INTERRUPT_VECTOR(USARTE1_DRE_vect, SER_UART5)
786         USART_RXC_INTERRUPT_VECTOR(USARTE1_RXC_vect, SER_UART5)
787 #endif
788 #if IMPLEMENT_SER_UART6
789         USART_DRE_INTERRUPT_VECTOR(USARTF0_DRE_vect, SER_UART6)
790         USART_RXC_INTERRUPT_VECTOR(USARTF0_RXC_vect, SER_UART6)
791 #endif
792 #if IMPLEMENT_SER_UART7
793         USART_DRE_INTERRUPT_VECTOR(USARTF1_DRE_vect, SER_UART7)
794         USART_RXC_INTERRUPT_VECTOR(USARTF1_RXC_vect, SER_UART7)
795 #endif
796
797 #ifdef SER_UART_BUS_TXOFF
798         static inline void USART_handleTXCInterrupt(uint8_t usartNumber)
799         {
800                 SER_STROBE_ON;
801                 struct FIFOBuffer * const txfifo = &ser_handles[usartNumber]->txfifo;
802                 if (fifo_isempty(txfifo))
803                 {
804                         SER_UART_BUS_TXOFF(UARTDescs[usartNumber].usart);
805                         UARTDescs[usartNumber].sending = false;
806                 }
807                 else
808                 {
809                         SER_UART_BUS_TXBEGIN(UARTDescs[usartNumber].usart);
810                 }
811                 SER_STROBE_OFF;
812         }
813
814         /*
815          * Serial port 0 TX complete interrupt handler.
816          *
817          * This IRQ is usually disabled.  The UDR-empty interrupt
818          * enables it when there's no more data to transmit.
819          * We need to wait until the last character has been
820          * transmitted before switching the 485 transceiver to
821          * receive mode.
822          *
823          * The txfifo might have been refilled by putchar() while
824          * we were waiting for the transmission complete interrupt.
825          * In this case, we must restart the UDR empty interrupt,
826          * otherwise we'd stop the serial port with some data
827          * still pending in the buffer.
828          */
829         #define USART_TXC_INTERRUPT_VECTOR(_vector, _usart)     \
830         DECLARE_ISR(_vector)                                                            \
831         {                                                                                                       \
832                 USART_handleTXCInterrupt( _usart );                             \
833         }
834
835         #if IMPLEMENT_SER_UART0
836                 USART_TXC_INTERRUPT_VECTOR(USARTC0_TXC_vect, SER_UART0)
837         #endif
838         #if IMPLEMENT_SER_UART1
839                 USART_TXC_INTERRUPT_VECTOR(USARTD0_TXC_vect, SER_UART1)
840         #endif
841         #if IMPLEMENT_SER_UART2
842                 USART_TXC_INTERRUPT_VECTOR(USARTE0_TXC_vect, SER_UART2)
843         #endif
844         #if IMPLEMENT_SER_UART3
845                 USART_TXC_INTERRUPT_VECTOR(USARTC1_TXC_vect, SER_UART3)
846         #endif
847         #if IMPLEMENT_SER_UART4
848                 USART_TXC_INTERRUPT_VECTOR(USARTD1_TXC_vect, SER_UART4)
849         #endif
850         #if IMPLEMENT_SER_UART5
851                 USART_TXC_INTERRUPT_VECTOR(USARTE1_TXC_vect, SER_UART5)
852         #endif
853         #if IMPLEMENT_SER_UART6
854                 USART_TXC_INTERRUPT_VECTOR(USARTF0_TXC_vect, SER_UART6)
855         #endif
856         #if IMPLEMENT_SER_UART7
857                 USART_TXC_INTERRUPT_VECTOR(USARTF1_TXC_vect, SER_UART7)
858         #endif
859 #endif /* SER_UART_BUS_TXOFF */