You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2026/10/22 06:14:40 UTC
(nuttx) 03/05: arch/arm/nrf54l: stop the UART DMA with rxstop and txstop helpers
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 <ra...@railab.me>
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 <ra...@railab.me>
---
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
}