Don't access serial data register twice.
[bertos.git] / drv / ser_dsp56k.c
index 6c75f8a348457a78f58b7cf4e99bbba7e53540d7..38dd40b97222610458e9c5a92e154d96eec8f79c 100755 (executable)
@@ -1,7 +1,7 @@
 /*!
  * \file
  * <!--
- * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
  * This file is part of DevLib - See devlib/README for information.
  * -->
  *
  * \brief DSP5680x CPU specific serial I/O driver
  */
 
-/*
- * $Log$
- * 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.
- *
- */
+/*#*
+ *#* $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 <drv/kdebug.h>
+#include <drv/irq.h>
+#include <debug.h>
 #include <hw.h>
-#include <DSP56F807.H>
+#include <DSP56F807.h>
 
 // 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.
        #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;
@@ -59,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)
@@ -96,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))
@@ -110,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;
 
+       // 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);
+       /*
+        * 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.
+       // Writing anything to the status register clear the error bits.
        regs->SR = 0;
 }
 
@@ -141,7 +170,9 @@ static void init(struct SerialHardware* _hw, struct Serial* ser)
        // 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);
 
@@ -190,14 +221,28 @@ static const struct SerialHardwareVT SCI_VT =
 static struct SCI SCIDescs[2] =
 {
        {
-               .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 = &REG_SCI[0],
                .irq_rx = IRQ_SCI0_RECEIVER_FULL,
                .irq_tx = IRQ_SCI0_TRANSMITTER_READY,
        },
 
        {
-               .hw = { .table = &SCI_VT },
+               .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 = &REG_SCI[1],
                .irq_rx = IRQ_SCI1_RECEIVER_FULL,
                .irq_tx = IRQ_SCI1_TRANSMITTER_READY,
@@ -205,35 +250,6 @@ static struct SCI SCIDescs[2] =
 };
 
 
-
-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);