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
 }

Reply via email to