Don't access serial data register twice.
[bertos.git] / drv / ser_dsp56k.c
index cb892c7265b41feaed07e581eff53ee10a96a2da..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.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.
- *
- */
+/*#*
+ *#* $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;
@@ -62,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)
@@ -119,18 +132,29 @@ 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;
 }
 
@@ -197,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,