This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit bcf7624ee78392608c3acc3c57679af54f8b3b70
Author: Max Kriegleder <[email protected]>
AuthorDate: Tue Oct 27 00:55:42 2026 +0100

    arch/arm/stm32h7: Drain the serial TX FIFO before shutting a port down.
    
    txempty pointed to up_txready(), which tests TXE: with the 16-byte TX
    FIFO enabled that means the FIFO has room, not that it is empty.  On
    the last close() of a port, uart_tcdrain() saw the software buffer
    empty and txempty true at once, and up_shutdown() turned the USART
    clock off with the data still in the FIFO.  Up to 16 bytes were lost:
    a write that fit into the FIFO did not come out at all (e.g. "echo
    abc > /dev/ttyS1").
    
    Add up_txempty() that tests TC (transmission complete), and use it for
    txempty.
    
    up_shutdown() also turned the clock off before clearing UE, TE and RE
    in CR1, so that write was lost and the USART stayed enabled.  Disable
    the USART first.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: Max Kriegleder <[email protected]>
---
 arch/arm/src/stm32h7/stm32_serial.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/arch/arm/src/stm32h7/stm32_serial.c 
b/arch/arm/src/stm32h7/stm32_serial.c
index ed233257427..f336edf26e2 100644
--- a/arch/arm/src/stm32h7/stm32_serial.c
+++ b/arch/arm/src/stm32h7/stm32_serial.c
@@ -690,6 +690,7 @@ static void up_send(struct uart_dev_s *dev, int ch);
 static void up_txint(struct uart_dev_s *dev, bool enable);
 #endif
 static bool up_txready(struct uart_dev_s *dev);
+static bool up_txempty(struct uart_dev_s *dev);
 
 #ifdef SERIAL_HAVE_TXDMA
 static void up_dma_send(struct uart_dev_s *dev);
@@ -744,7 +745,7 @@ static const struct uart_ops_s g_uart_ops =
   .send           = up_send,
   .txint          = up_txint,
   .txready        = up_txready,
-  .txempty        = up_txready,
+  .txempty        = up_txempty,
 };
 #endif
 
@@ -765,7 +766,7 @@ static const struct uart_ops_s g_uart_rxtxdma_ops =
   .send           = up_send,
   .txint          = up_dma_txint,
   .txready        = up_txready,
-  .txempty        = up_txready,
+  .txempty        = up_txempty,
   .dmatxavail     = up_dma_txavailable,
   .dmasend        = up_dma_send,
 };
@@ -788,7 +789,7 @@ static const struct uart_ops_s g_uart_rxdma_ops =
   .send           = up_send,
   .txint          = up_txint,
   .txready        = up_txready,
-  .txempty        = up_txready,
+  .txempty        = up_txempty,
 };
 #endif
 
@@ -809,7 +810,7 @@ static const struct uart_ops_s g_uart_txdma_ops =
   .send           = up_send,
   .txint          = up_dma_txint,
   .txready        = up_txready,
-  .txempty        = up_txready,
+  .txempty        = up_txempty,
   .dmatxavail     = up_dma_txavailable,
   .dmasend        = up_dma_send,
 };
@@ -2302,16 +2303,16 @@ static void up_shutdown(struct uart_dev_s *dev)
 
   up_disableusartint(priv, NULL);
 
-  /* Disable USART APB1/2 clock */
-
-  up_set_apb_clock(dev, false);
-
-  /* Disable Rx, Tx, and the UART */
+  /* Disable Rx, Tx, and the UART, while its clock still runs */
 
   regval  = up_serialin(priv, STM32_USART_CR1_OFFSET);
   regval &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
   up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
 
+  /* Disable USART APB1/2 clock */
+
+  up_set_apb_clock(dev, false);
+
   /* Release pins.
    * "If the serial-attached device is powered down, the TX
    * pin causes back-powering, potentially confusing the device
@@ -3602,6 +3603,22 @@ static bool up_txready(struct uart_dev_s *dev)
   return ((up_serialin(priv, STM32_USART_ISR_OFFSET) & USART_ISR_TXE) != 0);
 }
 
+/****************************************************************************
+ * Name: up_txempty
+ *
+ * Description:
+ *   Return true if all data has been sent: the TX FIFO and the shift
+ *   register are empty (transmission complete).
+ *
+ ****************************************************************************/
+
+static bool up_txempty(struct uart_dev_s *dev)
+{
+  struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
+
+  return ((up_serialin(priv, STM32_USART_ISR_OFFSET) & USART_ISR_TC) != 0);
+}
+
 /****************************************************************************
  * Name: up_dma_rxcallback
  *

Reply via email to