X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Favr%2Fdrv%2Fser_avr.c;h=c7c36ff77e163e83cde9fd0bc495b3d8309d89e3;hb=402db875d587a89e87e545883514dca50bc5ca54;hp=783f6cdaec0a66ecdfbc28b90e9fe3687a9b4ee5;hpb=eefd46ab866bff0f1f19414db632fc46c4a0fd59;p=bertos.git diff --git a/bertos/cpu/avr/drv/ser_avr.c b/bertos/cpu/avr/drv/ser_avr.c index 783f6cda..c7c36ff7 100644 --- a/bertos/cpu/avr/drv/ser_avr.c +++ b/bertos/cpu/avr/drv/ser_avr.c @@ -26,8 +26,8 @@ * 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 2000 Bernardo Innocenti + * Copyright 2003, 2004, 2010 Develer S.r.l. (http://www.develer.com/) + * Copyright 2000 Bernie Innocenti * * --> * @@ -35,23 +35,25 @@ * * \version $Id$ * - * \author Bernardo Innocenti + * \author Bernie Innocenti * \author Stefano Fedrigo + * \author Luca Ottaviano */ #include "hw/hw_ser.h" /* Required for bus macros overrides */ -#include "hw/hw_cpu.h" /* CLOCK_FREQ */ +#include /* CPU_FREQ */ #include "cfg/cfg_ser.h" #include /* DIV_ROUND */ #include +#include // ARCH_NIGHTTEST #include #include #include -#include +#include #include @@ -84,6 +86,16 @@ #define BIT_RXEN1 RXEN1 #define BIT_TXEN1 TXEN1 #define BIT_UDRIE1 UDRIE1 +#elif 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 @@ -247,7 +259,16 @@ #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 @@ -261,6 +282,11 @@ /* USART register definitions */ #if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 #define AVR_HAS_UART1 1 +#elif CPU_AVR_ATMEGA328P + #define AVR_HAS_UART1 0 + #define USART0_UDRE_vect USART_UDRE_vect + #define USART0_RX_vect USART_RX_vect + #define SIG_UART0_TRANS SIG_UART_TRANS #elif CPU_AVR_ATMEGA8 #define AVR_HAS_UART1 0 #define UCSR0A UCSRA @@ -269,6 +295,7 @@ #define UDR0 UDR #define UBRR0L UBRRL #define UBRR0H UBRRH +/* TODO: The following SIGs are old style interrupts, must be refactored */ #define SIG_UART0_DATA SIG_UART_DATA #define SIG_UART0_RECV SIG_UART_RECV #define SIG_UART0_TRANS SIG_UART_TRANS @@ -278,6 +305,7 @@ #define UDR0 UDR #define UCSR0A USR #define UBRR0L UBRR +/* TODO: The following SIGs are old style interrupts, must be refactored */ #define SIG_UART0_DATA SIG_UART_DATA #define SIG_UART0_RECV SIG_UART_RECV #define SIG_UART0_TRANS SIG_UART_TRANS @@ -286,25 +314,8 @@ #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]; +extern struct Serial *ser_handles[SER_CNT]; /* TX and RX buffers */ static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE]; @@ -340,20 +351,6 @@ struct AvrSerial }; -/* - * These are to trick GCC into *not* using absolute addressing mode - * when accessing ser_handles, which is very expensive. - * - * Accessing through these pointers generates much shorter - * (and hopefully faster) code. - */ -struct Serial *ser_uart0 = &ser_handles[SER_UART0]; -#if AVR_HAS_UART1 -struct Serial *ser_uart1 = &ser_handles[SER_UART1]; -#endif -struct Serial *ser_spi = &ser_handles[SER_SPI]; - - /* * Callbacks @@ -391,7 +388,7 @@ 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 = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; #if !CPU_AVR_ATMEGA103 UBRR0H = (period) >> 8; @@ -444,7 +441,7 @@ 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; + uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1; UBRR1H = (period) >> 8; UBRR1L = (period); @@ -484,7 +481,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)); @@ -547,14 +544,14 @@ static void spi_starttx(struct SerialHardware *_hw) { struct AvrSerial *hw = (struct AvrSerial *)_hw; - cpuflags_t flags; + cpu_flags_t flags; IRQ_SAVE_DISABLE(flags); /* Send data only if the SPI is not already transmitting */ - if (!hw->sending && !fifo_isempty(&ser_spi->txfifo)) + if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI]->txfifo)) { hw->sending = true; - SPDR = fifo_pop(&ser_spi->txfifo); + SPDR = fifo_pop(&ser_handles[SER_SPI]->txfifo); } IRQ_RESTORE(flags); @@ -675,10 +672,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; } @@ -688,11 +685,11 @@ SIGNAL(SIG_CTS) /** * Serial 0 TX interrupt handler */ -SIGNAL(USART0_UDRE_vect) +DECLARE_ISR(USART0_UDRE_vect) { SER_STROBE_ON; - struct FIFOBuffer * const txfifo = &ser_uart0->txfifo; + struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo; if (fifo_isempty(txfifo)) { @@ -706,7 +703,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; } @@ -736,18 +733,18 @@ 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(SIG_UART0_TRANS) { SER_STROBE_ON; - struct FIFOBuffer * const txfifo = &ser_uart0->txfifo; + struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo; if (fifo_isempty(txfifo)) { SER_UART0_BUS_TXOFF; 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; } @@ -759,11 +756,11 @@ SIGNAL(SIG_UART0_TRANS) /** * Serial 1 TX interrupt handler */ -SIGNAL(USART1_UDRE_vect) +DECLARE_ISR(USART1_UDRE_vect) { SER_STROBE_ON; - struct FIFOBuffer * const txfifo = &ser_uart1->txfifo; + struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo; if (fifo_isempty(txfifo)) { @@ -777,7 +774,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; } @@ -797,18 +794,18 @@ SIGNAL(USART1_UDRE_vect) * * \sa port 0 TX complete handler. */ -SIGNAL(SIG_UART1_TRANS) +DECLARE_ISR(USART1_TX_vect) { SER_STROBE_ON; - struct FIFOBuffer * const txfifo = &ser_uart1->txfifo; + struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo; if (fifo_isempty(txfifo)) { SER_UART1_BUS_TXOFF; 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; } @@ -832,7 +829,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; @@ -841,17 +838,17 @@ SIGNAL(USART0_RX_vect) //IRQ_ENABLE; /* Should be read before UDR */ - ser_uart0->status |= UCSR0A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR); + ser_handles[SER_UART0]->status |= UCSR0A & (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 = UDR0; - struct FIFOBuffer * const rxfifo = &ser_uart0->rxfifo; + struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo; if (fifo_isfull(rxfifo)) - ser_uart0->status |= SERRF_RXFIFOOVERRUN; + ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN; else { fifo_push(rxfifo, c); @@ -880,9 +877,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; @@ -891,17 +888,17 @@ SIGNAL(USART1_RX_vect) //IRQ_ENABLE; /* Should be read before UDR */ - ser_uart1->status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR); + ser_handles[SER_UART1]->status |= UCSR1A & (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 = UDR1; - struct FIFOBuffer * const rxfifo = &ser_uart1->rxfifo; + struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo; //ASSERT_VALID_FIFO(rxfifo); if (UNLIKELY(fifo_isfull(rxfifo))) - ser_uart1->status |= SERRF_RXFIFOOVERRUN; + ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN; else { fifo_push(rxfifo, c); @@ -923,22 +920,22 @@ SIGNAL(USART1_RX_vect) /** * SPI interrupt handler */ -SIGNAL(SIG_SPI) +DECLARE_ISR(SIG_SPI) { SER_STROBE_ON; /* Read incoming byte. */ - if (!fifo_isfull(&ser_spi->rxfifo)) - fifo_push(&ser_spi->rxfifo, SPDR); + if (!fifo_isfull(&ser_handles[SER_SPI]->rxfifo)) + fifo_push(&ser_handles[SER_SPI]->rxfifo, SPDR); /* * FIXME else - ser_spi->status |= SERRF_RXFIFOOVERRUN; + ser_handles[SER_SPI]->status |= SERRF_RXFIFOOVERRUN; */ /* Send */ - if (!fifo_isempty(&ser_spi->txfifo)) - SPDR = fifo_pop(&ser_spi->txfifo); + if (!fifo_isempty(&ser_handles[SER_SPI]->txfifo)) + SPDR = fifo_pop(&ser_handles[SER_SPI]->txfifo); else UARTDescs[SER_SPI].sending = false;