This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 2b4443e4285c643487ecc4e5f370ace1280e0125 Author: raiden00pl <[email protected]> AuthorDate: Tue Oct 20 14:51:05 2026 +0200 arch/arm/nrf54l: stop the UART DMA with rxstop and txstop helpers Use the same stop helpers as nrf52 and nrf53 in detach, set_format and up_putc, and wait for the transmitter in set_format instead of -EBUSY. Assisted-by: Claude Code Signed-off-by: raiden00pl <[email protected]> --- arch/arm/src/nrf54l/nrf54l_serial.c | 145 +++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 62 deletions(-) diff --git a/arch/arm/src/nrf54l/nrf54l_serial.c b/arch/arm/src/nrf54l/nrf54l_serial.c index 03296fd26bc..7d60272d18f 100644 --- a/arch/arm/src/nrf54l/nrf54l_serial.c +++ b/arch/arm/src/nrf54l/nrf54l_serial.c @@ -539,6 +539,54 @@ static void nrf54l_rxstart(struct nrf54l_dev_s *priv) nrf54l_uart_putreg(priv, NRF54L_UARTE_TASKS_STARTRX_OFFSET, 1); } +/**************************************************************************** + * Name: nrf54l_rxstop + * + * Description: + * Stop reception and deliver a completed byte. Interrupts must be + * disabled. + * + ****************************************************************************/ + +static void nrf54l_rxstop(struct uart_dev_s *dev) +{ + struct nrf54l_dev_s *priv = dev->priv; + + nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET); + nrf54l_uart_putreg(priv, NRF54L_UARTE_TASKS_STOPRX_OFFSET, 1); + while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET)) + { + } + + if (nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_ERROR_OFFSET)) + { + nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_ERROR_OFFSET); + priv->rxstatus |= + nrf54l_uart_getreg(priv, NRF54L_UARTE_ERRORSRC_OFFSET); + nrf54l_uart_putreg(priv, NRF54L_UARTE_ERRORSRC_OFFSET, priv->rxstatus); + } + + /* STOP also generates END for an empty buffer. Deliver a completed + * byte, but never deliver an empty buffer. + */ + + if (nrf54l_uart_getreg(priv, NRF54L_UARTE_DMA_RX_AMOUNT_OFFSET) != 0 && + !nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_DMA_RX_BUSERROR_OFFSET)) + { + UP_DMB(); + priv->rxchar = priv->rxdma; + priv->rxvalid = true; + if (priv->rxenabled) + { + uart_recvchars(dev); + } + + priv->rxvalid = false; + } + + nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_DMA_RX_END_OFFSET); +} + /**************************************************************************** * Name: nrf54l_txstart * @@ -560,6 +608,28 @@ static void nrf54l_txstart(struct nrf54l_dev_s *priv, int ch) nrf54l_uart_putreg(priv, NRF54L_UARTE_TASKS_STARTTX_OFFSET, 1); } +/**************************************************************************** + * Name: nrf54l_txstop + * + * Description: + * Wait for the transmitter to stop. Interrupts must be disabled. + * + ****************************************************************************/ + +static void nrf54l_txstop(struct nrf54l_dev_s *priv) +{ + /* TXSTOPPED, rather than DMA END, guarantees the pin is idle */ + + if (priv->txbusy) + { + while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_TXSTOPPED_OFFSET)) + { + } + + priv->txbusy = false; + } +} + /**************************************************************************** * Name: nrf54l_setup * @@ -636,34 +706,24 @@ static int nrf54l_attach(struct uart_dev_s *dev) static void nrf54l_detach(struct uart_dev_s *dev) { struct nrf54l_dev_s *priv = (struct nrf54l_dev_s *)dev->priv; + irqstate_t flags; /* Stop DMA before detaching the interrupt handler */ + flags = enter_critical_section(); nrf54l_uart_putreg(priv, NRF54L_UARTE_INTENCLR_OFFSET, UINT32_MAX); nrf54l_uart_putreg(priv, NRF54L_UARTE_SHORTS_OFFSET, UARTE_SHORTS_DMA_TX_END_STOP); + if (priv->rxactive) { - /* Wait until the DMA buffer is released before a subsequent attach. */ - - nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET); - nrf54l_uart_putreg(priv, NRF54L_UARTE_TASKS_STOPRX_OFFSET, 1); - while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET)) - { - } - + nrf54l_rxstop(dev); priv->rxactive = false; priv->rxrecover = false; } - if (priv->txbusy) - { - while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_TXSTOPPED_OFFSET)) - { - } - - priv->txbusy = false; - } + nrf54l_txstop(priv); + leave_critical_section(flags); up_disable_irq(priv->irq); irq_detach(priv->irq); @@ -771,11 +831,9 @@ static int nrf54l_set_format(struct uart_dev_s *dev, flags = enter_critical_section(); - /* Do not change the format of a byte still being transmitted or - * interrupt DMA error recovery. - */ + /* Do not interrupt DMA error recovery */ - if (priv->txbusy || priv->rxrecover) + if (priv->rxrecover) { leave_critical_section(flags); return -EBUSY; @@ -783,39 +841,11 @@ static int nrf54l_set_format(struct uart_dev_s *dev, if (priv->rxactive) { - nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET); - nrf54l_uart_putreg(priv, NRF54L_UARTE_TASKS_STOPRX_OFFSET, 1); - while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_RXTO_OFFSET)) - { - } - - /* STOP also generates END for an empty buffer. Deliver a completed - * byte before restarting DMA, but never deliver an empty buffer. - */ - - if (nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_ERROR_OFFSET)) - { - nrf54l_uart_clrevent(priv, NRF54L_UARTE_EVENTS_ERROR_OFFSET); - priv->rxstatus |= - nrf54l_uart_getreg(priv, NRF54L_UARTE_ERRORSRC_OFFSET); - nrf54l_uart_putreg(priv, NRF54L_UARTE_ERRORSRC_OFFSET, - priv->rxstatus); - } - - if (nrf54l_uart_getreg(priv, NRF54L_UARTE_DMA_RX_AMOUNT_OFFSET) != 0 && - !nrf54l_uart_getreg(priv, - NRF54L_UARTE_EVENTS_DMA_RX_BUSERROR_OFFSET)) - { - UP_DMB(); - priv->rxchar = priv->rxdma; - priv->rxvalid = true; - if (priv->rxenabled) - { - uart_recvchars(dev); - } - } + nrf54l_rxstop(dev); } + nrf54l_txstop(priv); + enabled = nrf54l_uart_getreg(priv, NRF54L_UARTE_ENABLE_OFFSET); nrf54l_uart_putreg(priv, NRF54L_UARTE_ENABLE_OFFSET, 0); ret = nrf54l_usart_setformat(priv->uartbase, config); @@ -1215,19 +1245,10 @@ void up_putc(int ch) struct nrf54l_dev_s *priv = CONSOLE_DEV.priv; irqstate_t flags = enter_critical_section(); - /* Serialize polled debug output with the interrupt-driven transmitter. - * TXSTOPPED, rather than DMA END, guarantees the pin is idle before reuse. - */ - - if (priv->txbusy) - { - while (!nrf54l_uart_getreg(priv, NRF54L_UARTE_EVENTS_TXSTOPPED_OFFSET)) - { - } - } + /* Serialize polled debug output with the interrupt-driven transmitter */ + nrf54l_txstop(priv); arm_lowputc(ch); - priv->txbusy = false; leave_critical_section(flags); #endif }
