X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=drv%2Fser_dsp56k.c;h=38dd40b97222610458e9c5a92e154d96eec8f79c;hb=06f0503a2066ab4fd13529b8ed8906e52b1d672b;hp=d2f1362041180fbed8d63d242a369dad190ca174;hpb=0375780817109b6ab5cd4f36ccf80650b2fe77d5;p=bertos.git diff --git a/drv/ser_dsp56k.c b/drv/ser_dsp56k.c index d2f13620..38dd40b9 100755 --- a/drv/ser_dsp56k.c +++ b/drv/ser_dsp56k.c @@ -1,20 +1,45 @@ -/** +/*! * \file - * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/) - * All Rights Reserved. + * * * \version $Id$ * * \author Stefano Fedrigo + * \author Giovanni Bajo * * \brief DSP5680x CPU specific serial I/O driver */ -#include -#include -#include +/*#* + *#* $Log$ + *#* Revision 1.8 2004/10/26 09:00:49 bernie + *#* Don't access serial data register twice. + *#* + *#* Revision 1.7 2004/10/19 08:57:15 bernie + *#* Bugfixes for DSP56K serial driver from scfirm. + *#* + *#* Revision 1.5 2004/08/25 14:12:08 rasky + *#* Aggiornato il comment block dei log RCS + *#* + *#* Revision 1.4 2004/07/30 14:27:49 rasky + *#* Aggiornati alcuni file DSP56k per la nuova libreria di IRQ management + *#* + *#* Revision 1.3 2004/06/03 11:27:09 bernie + *#* Add dual-license information. + *#* + *#* Revision 1.2 2004/05/23 18:21:53 bernie + *#* Trim CVS logs and cleanup header info. + *#*/ + #include "ser.h" #include "ser_p.h" +#include +#include +#include +#include // GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use // the serial, we need to disable the GPIO functions on them. @@ -29,16 +54,20 @@ #error error flags do not match with register bits #endif +static unsigned char ser0_fifo_rx[CONFIG_SER0_FIFOSIZE_RX]; +static unsigned char ser0_fifo_tx[CONFIG_SER0_FIFOSIZE_TX]; +static unsigned char ser1_fifo_rx[CONFIG_SER1_FIFOSIZE_RX]; +static unsigned char ser1_fifo_tx[CONFIG_SER1_FIFOSIZE_TX]; + struct SCI { struct SerialHardware hw; struct Serial* serial; volatile struct REG_SCI_STRUCT* regs; - uint16_t irq_tx; - uint16_t irq_rx; + IRQ_VECTOR irq_tx; + IRQ_VECTOR irq_rx; }; - static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs) { regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE; @@ -46,7 +75,7 @@ static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs) static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs) { - regs->CR |= REG_SCI_CR_RIE | REG_SCI_CR_REIE; + regs->CR |= REG_SCI_CR_RIE; } static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs) @@ -83,8 +112,9 @@ static inline void enable_rx_irq(struct SerialHardware* _hw) enable_rx_irq_bare(regs); } -INLINE void tx_isr(struct SCI *hw) +static void tx_isr(const struct SCI *hw) { +#pragma interrupt warn volatile struct REG_SCI_STRUCT* regs = hw->regs; if (fifo_isempty(&hw->serial->txfifo)) @@ -97,22 +127,34 @@ INLINE void tx_isr(struct SCI *hw) } } -INLINE void rx_isr(struct SCI *hw) +static void rx_isr(const struct SCI *hw) { +#pragma interrupt warn volatile struct REG_SCI_STRUCT* regs = hw->regs; - hw->serial->status |= regs->SR & (SERRF_PARITYERROR | - SERRF_RXSROVERRUN | - SERRF_FRAMEERROR | + // Propagate errors + hw->serial->status |= regs->SR & (SERRF_PARITYERROR | + SERRF_RXSROVERRUN | + SERRF_FRAMEERROR | SERRF_NOISEERROR); - - if (fifo_isfull(&hw->serial->rxfifo)) - hw->serial->status |= SERRF_RXFIFOOVERRUN; - else - fifo_push(&hw->serial->rxfifo, regs->DR); - - // Writing anything to the status register clear the - // error bits. + + /* + * Serial IRQ can happen for two reason: data ready (RDRF) or overrun (OR) + * If the data is ready, we need to fetch it from the data register or + * the interrupt will retrigger immediatly. In case of overrun, instead, + * the value of the data register is meaningless. + */ + if (regs->SR & REG_SCI_SR_RDRF) + { + unsigned char data = regs->DR; + + if (fifo_isfull(&hw->serial->rxfifo)) + hw->serial->status |= SERRF_RXFIFOOVERRUN; + else + fifo_push(&hw->serial->rxfifo, data); + } + + // Writing anything to the status register clear the error bits. regs->SR = 0; } @@ -124,18 +166,20 @@ static void init(struct SerialHardware* _hw, struct Serial* ser) // Clear status register (IRQ/status flags) (void)regs->SR; regs->SR = 0; - + // Clear data register (void)regs->DR; - - // Set priorities for both IRQs + + // Install the handlers and set priorities for both IRQs + irq_install(hw->irq_tx, (isr_t)tx_isr, hw); + irq_install(hw->irq_rx, (isr_t)rx_isr, hw); irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX); irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX); // Activate the RX error interrupts, and RX/TX transmissions regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE; enable_rx_irq_bare(regs); - + // Disable GPIO pins for TX and RX lines REG_GPIO_SERIAL->PER |= REG_GPIO_SERIAL_MASK; @@ -176,51 +220,36 @@ static const struct SerialHardwareVT SCI_VT = static struct SCI SCIDescs[2] = { - { - .hw = { .table = &SCI_VT }, - .regs = ®_SCI[0], - .irq_rx = IRQ_SCI0_RECEIVER_FULL, - .irq_tx = IRQ_SCI0_TRANSMITTER_READY, - }, - - { - .hw = { .table = &SCI_VT }, + { + .hw = + { + .table = &SCI_VT, + .rxbuffer = ser0_fifo_rx, + .txbuffer = ser0_fifo_tx, + .rxbuffer_size = countof(ser0_fifo_rx), + .txbuffer_size = countof(ser0_fifo_tx), + }, + .regs = ®_SCI[0], + .irq_rx = IRQ_SCI0_RECEIVER_FULL, + .irq_tx = IRQ_SCI0_TRANSMITTER_READY, + }, + + { + .hw = + { + .table = &SCI_VT, + .rxbuffer = ser1_fifo_rx, + .txbuffer = ser1_fifo_tx, + .rxbuffer_size = countof(ser1_fifo_rx), + .txbuffer_size = countof(ser1_fifo_tx), + }, .regs = ®_SCI[1], - .irq_rx = IRQ_SCI1_RECEIVER_FULL, - .irq_tx = IRQ_SCI1_TRANSMITTER_READY, - }, + .irq_rx = IRQ_SCI1_RECEIVER_FULL, + .irq_tx = IRQ_SCI1_TRANSMITTER_READY, + }, }; - -void ser_hw_tx_isr_0(void); -void ser_hw_tx_isr_0(void) -{ -#pragma interrupt warn - tx_isr(&SCIDescs[0]); -} - -void ser_hw_rx_isr_0(void); -void ser_hw_rx_isr_0(void) -{ -#pragma interrupt warn - rx_isr(&SCIDescs[0]); -} - -void ser_hw_tx_isr_1(void); -void ser_hw_tx_isr_1(void) -{ -#pragma interrupt warn - tx_isr(&SCIDescs[1]); -} - -void ser_hw_rx_isr_1(void); -void ser_hw_rx_isr_1(void) -{ -#pragma interrupt warn - rx_isr(&SCIDescs[1]); -} - struct SerialHardware* ser_hw_getdesc(int unit) { ASSERT(unit < 2);