diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-04-02 01:02:41 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-04-02 01:02:41 +0000 |
commit | dd4f93db606a1360efef7b59a97bd4a0bd8c6ad0 (patch) | |
tree | 09af0046e3d702c013359820c0115c36e370bdb6 | |
parent | 67a850ba575659cb195e67aa8357a70dece9c418 (diff) | |
download | nuttx-dd4f93db606a1360efef7b59a97bd4a0bd8c6ad0.tar.gz nuttx-dd4f93db606a1360efef7b59a97bd4a0bd8c6ad0.tar.bz2 nuttx-dd4f93db606a1360efef7b59a97bd4a0bd8c6ad0.zip |
A couple of fixes to common and STM32 serial handling to fix some data overrun conditions
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4550 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_serial.c | 60 | ||||
-rw-r--r-- | nuttx/drivers/serial/serial.c | 9 |
2 files changed, 47 insertions, 22 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_serial.c b/nuttx/arch/arm/src/stm32/stm32_serial.c index de918efbe..680a77216 100644 --- a/nuttx/arch/arm/src/stm32/stm32_serial.c +++ b/nuttx/arch/arm/src/stm32/stm32_serial.c @@ -799,8 +799,8 @@ static void up_detach(struct uart_dev_s *dev) static int up_interrupt_common(struct up_dev_s *priv) { - int passes; - bool handled; + int passes; + bool handled; /* Loop until there are no characters to be transferred or, * until we have been looping for a long time. @@ -811,7 +811,7 @@ static int up_interrupt_common(struct up_dev_s *priv) { handled = false; - /* Get the masked USART status and clear the pending interrupts. */ + /* Get the masked USART status word. */ priv->sr = up_serialin(priv, STM32_USART_SR_OFFSET); @@ -837,16 +837,35 @@ static int up_interrupt_common(struct up_dev_s *priv) * being used. */ - /* Handle incoming, receive bytes (with or without timeout) */ + /* Handle incoming, receive bytes. */ if ((priv->sr & USART_SR_RXNE) != 0 && (priv->ie & USART_CR1_RXNEIE) != 0) { - /* Received data ready... process incoming bytes */ + /* Received data ready... process incoming bytes. NOTE the check for + * RXNEIE: We cannot call uart_recvchards of RX interrupts are disabled. + */ uart_recvchars(&priv->dev); handled = true; } + /* We may still have to read from the DR register to clear any pending + * error conditions. + */ + + else if ((priv->sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE)) != 0) + { + /* If an error occurs, read from DR to clear the error (data has + * been lost). If ORE is set along with RXNE then it tells you + * that the byte *after* the one in the data register has been + * lost, but the data register value is correct. That case will + * be handled above if interrupts are enabled. Otherwise, that + * good byte will be lost. + */ + + (void)up_serialin(priv, STM32_USART_DR_OFFSET); + } + /* Handle outgoing, transmit bytes */ if ((priv->sr & USART_SR_TXE) != 0 && (priv->ie & USART_CR1_TXEIE) != 0) @@ -962,23 +981,25 @@ static int up_receive(struct uart_dev_s *dev, uint32_t *status) static void up_rxint(struct uart_dev_s *dev, bool enable) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + irqstate_t flags; uint16_t ie; - /* USART receive interrupts: - * - * Enable Bit Status Meaning Usage - * ------------------ --- --------------- ------------------------------- ---------- - * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) - * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read - * " " USART_SR_ORE Overrun Error Detected - * USART_CR1_PEIE 8 USART_SR_PE Parity Error - * - * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) - * USART_CR3_EIE 0 USART_SR_FE Framing Error - * " " USART_SR_NE Noise Error - * " " USART_SR_ORE Overrun Error Detected - */ + /* USART receive interrupts: + * + * Enable Bit Status Meaning Usage + * ------------------ --- --------------- ------------------------------- ---------- + * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read + * " " USART_SR_ORE Overrun Error Detected + * USART_CR1_PEIE 8 USART_SR_PE Parity Error + * + * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) + * USART_CR3_EIE 0 USART_SR_FE Framing Error + * " " USART_SR_NE Noise Error + * " " USART_SR_ORE Overrun Error Detected + */ + flags = irqsave(); ie = priv->ie; if (enable) { @@ -1002,6 +1023,7 @@ static void up_rxint(struct uart_dev_s *dev, bool enable) /* Then set the new interrupt state */ up_restoreusartint(priv, ie); + irqrestore(flags); } /**************************************************************************** diff --git a/nuttx/drivers/serial/serial.c b/nuttx/drivers/serial/serial.c index 2fbd94cfd..7aa342d9d 100644 --- a/nuttx/drivers/serial/serial.c +++ b/nuttx/drivers/serial/serial.c @@ -321,11 +321,11 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen * data from the end of the buffer. */ - uart_disablerxint(dev); while (recvd < buflen) { /* Check if there is more data to return in the circular buffer */ + uart_disablerxint(dev); if (dev->recv.head != dev->recv.tail) { *buffer++ = dev->recv.buffer[dev->recv.tail]; @@ -335,6 +335,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen { dev->recv.tail = 0; } + uart_enablerxint(dev); } #ifdef CONFIG_DEV_SERIAL_FULLBLOCKS @@ -353,6 +354,8 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen { recvd = -EAGAIN; } + + uart_enablerxint(dev); break; } #else @@ -366,6 +369,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen * received up to the wait condition. */ + uart_enablerxint(dev); break; } @@ -379,6 +383,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen /* Break out of the loop returning -EAGAIN */ recvd = -EAGAIN; + uart_enablerxint(dev); break; } #endif @@ -395,12 +400,10 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen dev->recvwaiting = true; uart_enablerxint(dev); uart_takesem(&dev->recvsem); - uart_disablerxint(dev); irqrestore(flags); } } - uart_enablerxint(dev); uart_givesem(&dev->recv.sem); return recvd; } |