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 *
