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 9a6a13f110ae4d117e237011872d635b1df7b320
Author: raiden00pl <[email protected]>
AuthorDate: Tue Oct 20 14:20:42 2026 +0200

    arch/arm/nrf52,nrf53,nrf91: drive the UART with UARTE EasyDMA
    
    TX was sent polled with the interrupts disabled, which masked them for
    milliseconds per console write. Use UARTE with interrupt-driven
    one-byte DMA transfers as nrf54l does. nRF52832/nRF52833 baud codes
    change to the UARTE values from the SVD.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/arm/src/nrf52/hardware/nrf52_uarte.h |  78 ++----
 arch/arm/src/nrf52/nrf52_lowputc.c        |  65 +++--
 arch/arm/src/nrf52/nrf52_serial.c         | 441 ++++++++++++++++++++++--------
 arch/arm/src/nrf53/hardware/nrf53_uarte.h |   2 +
 arch/arm/src/nrf53/nrf53_lowputc.c        |  65 +++--
 arch/arm/src/nrf53/nrf53_serial.c         | 441 ++++++++++++++++++++++--------
 arch/arm/src/nrf91/hardware/nrf91_uarte.h |   2 +
 arch/arm/src/nrf91/nrf91_lowputc.c        |  65 +++--
 arch/arm/src/nrf91/nrf91_serial.c         | 441 ++++++++++++++++++++++--------
 9 files changed, 1140 insertions(+), 460 deletions(-)

diff --git a/arch/arm/src/nrf52/hardware/nrf52_uarte.h 
b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
index 02fbab9230c..fd429a79ec6 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_uarte.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
@@ -277,6 +277,8 @@
 
 #define NRF52_UART_ENABLE_DISABLE           (0)
 #define NRF52_UART_ENABLE_ENABLE            (4)
+#define NRF52_UARTE_ENABLE_DISABLE          (0)
+#define NRF52_UARTE_ENABLE_ENABLE           (8)
 
 /* INTEN/INTENSET/INTENCLR Register */
 
@@ -294,64 +296,24 @@
 
 /* BAUDRATE Register */
 
-#if defined(CONFIG_ARCH_CHIP_NRF52832)
-#  define UART_BAUDRATE_1200                (0x0004f000)
-#  define UART_BAUDRATE_2400                (0x0009d000)
-#  define UART_BAUDRATE_4800                (0x0013b000)
-#  define UART_BAUDRATE_9600                (0x00275000)
-#  define UART_BAUDRATE_14400               (0x003b0000)
-#  define UART_BAUDRATE_19200               (0x004ea000)
-#  define UART_BAUDRATE_28800               (0x0075f000)
-#  define UART_BAUDRATE_38400               (0x009d5000)
-#  define UART_BAUDRATE_57600               (0x00ebf000)
-#  define UART_BAUDRATE_76000               (0x013a9000)
-#  define UART_BAUDRATE_115200              (0x01d7e000)
-#  define UART_BAUDRATE_230400              (0x03afb000)
-#  define UART_BAUDRATE_250000              (0x04000000)
-#  define UART_BAUDRATE_460800              (0x075f7000)
-#  define UART_BAUDRATE_921600              (0x0ebed000)
-#  define UART_BAUDRATE_1000000             (0x10000000)
-#elif defined(CONFIG_ARCH_CHIP_NRF52833)
-#  define UART_BAUDRATE_1200                (0x0004f000)
-#  define UART_BAUDRATE_2400                (0x0009d000)
-#  define UART_BAUDRATE_4800                (0x0013b000)
-#  define UART_BAUDRATE_9600                (0x00275000)
-#  define UART_BAUDRATE_14400               (0x003b0000)
-#  define UART_BAUDRATE_19200               (0x004ea000)
-#  define UART_BAUDRATE_28800               (0x0075f000)
-#  define UART_BAUDRATE_31250               (0x00800000)
-#  define UART_BAUDRATE_38400               (0x009d5000)
-#  define UART_BAUDRATE_56000               (0x00e50000)
-#  define UART_BAUDRATE_57600               (0x00ebf000)
-#  define UART_BAUDRATE_76000               (0x013a9000)
-#  define UART_BAUDRATE_115200              (0x01d7e000)
-#  define UART_BAUDRATE_230400              (0x03afb000)
-#  define UART_BAUDRATE_250000              (0x04000000)
-#  define UART_BAUDRATE_460800              (0x075f7000)
-#  define UART_BAUDRATE_921600              (0x0ebed000)
-#  define UART_BAUDRATE_1000000             (0x10000000)
-#elif defined(CONFIG_ARCH_CHIP_NRF52840)
-#  define UART_BAUDRATE_1200                (0x0004f000)
-#  define UART_BAUDRATE_2400                (0x0009d000)
-#  define UART_BAUDRATE_4800                (0x0013b000)
-#  define UART_BAUDRATE_9600                (0x00275000)
-#  define UART_BAUDRATE_14400               (0x003af000)
-#  define UART_BAUDRATE_19200               (0x004ea000)
-#  define UART_BAUDRATE_28800               (0x0075c000)
-#  define UART_BAUDRATE_31250               (0x00800000)
-#  define UART_BAUDRATE_38400               (0x009d0000)
-#  define UART_BAUDRATE_56000               (0x00e50000)
-#  define UART_BAUDRATE_57600               (0x00eb0000)
-#  define UART_BAUDRATE_76000               (0x013a9000)
-#  define UART_BAUDRATE_115200              (0x01d60000)
-#  define UART_BAUDRATE_230400              (0x03b00000)
-#  define UART_BAUDRATE_250000              (0x04000000)
-#  define UART_BAUDRATE_460800              (0x07400000)
-#  define UART_BAUDRATE_921600              (0x0f000000)
-#  define UART_BAUDRATE_1000000             (0x10000000)
-#else
-#  error Unknown NRF52 chip !
-#endif
+#define UART_BAUDRATE_1200                  (0x0004f000)
+#define UART_BAUDRATE_2400                  (0x0009d000)
+#define UART_BAUDRATE_4800                  (0x0013b000)
+#define UART_BAUDRATE_9600                  (0x00275000)
+#define UART_BAUDRATE_14400                 (0x003af000)
+#define UART_BAUDRATE_19200                 (0x004ea000)
+#define UART_BAUDRATE_28800                 (0x0075c000)
+#define UART_BAUDRATE_31250                 (0x00800000)
+#define UART_BAUDRATE_38400                 (0x009d0000)
+#define UART_BAUDRATE_56000                 (0x00e50000)
+#define UART_BAUDRATE_57600                 (0x00eb0000)
+#define UART_BAUDRATE_76000                 (0x013a9000)
+#define UART_BAUDRATE_115200                (0x01d60000)
+#define UART_BAUDRATE_230400                (0x03b00000)
+#define UART_BAUDRATE_250000                (0x04000000)
+#define UART_BAUDRATE_460800                (0x07400000)
+#define UART_BAUDRATE_921600                (0x0f000000)
+#define UART_BAUDRATE_1000000               (0x10000000)
 
 /* CONFIG Register */
 
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.c 
b/arch/arm/src/nrf52/nrf52_lowputc.c
index 4a1e866f78c..2ee16bd91d1 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.c
+++ b/arch/arm/src/nrf52/nrf52_lowputc.c
@@ -79,6 +79,10 @@ static const struct uart_config_s g_console_config =
   .txpin     = CONSOLE_TX_PIN,
   .rxpin     = CONSOLE_RX_PIN,
 };
+
+/* Console byte transmitted by EasyDMA */
+
+static uint8_t g_console_tx;
 #endif /* HAVE_UART_CONSOLE */
 
 /****************************************************************************
@@ -219,7 +223,7 @@ static void nrf52_setbaud(uintptr_t base, const struct 
uart_config_s *config)
         }
     }
 
-  putreg32(br, base + NRF52_UART_BAUDRATE_OFFSET);
+  putreg32(br, base + NRF52_UARTE_BAUDRATE_OFFSET);
 }
 
 /****************************************************************************
@@ -231,7 +235,7 @@ static void nrf52_setparity(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF52_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF52_UARTE_CONFIG_OFFSET);
 
   if (config->parity == 2)
     {
@@ -246,7 +250,7 @@ static void nrf52_setparity(uintptr_t base,
       regval &= ~UART_CONFIG_PARITY;
     }
 
-  putreg32(regval, base + NRF52_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF52_UARTE_CONFIG_OFFSET);
 }
 
 /****************************************************************************
@@ -259,7 +263,7 @@ static void nrf52_setstops(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF52_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF52_UARTE_CONFIG_OFFSET);
 
   if (config->stopbits2 == true)
     {
@@ -270,7 +274,7 @@ static void nrf52_setstops(uintptr_t base,
       regval &= ~UART_CONFIG_STOP;
     }
 
-  putreg32(regval, base + NRF52_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF52_UARTE_CONFIG_OFFSET);
 }
 #endif
 
@@ -328,9 +332,10 @@ void nrf52_usart_configure(uintptr_t base,
   uint32_t port   = 0;
   uint32_t regval = 0;
 
-  putreg32(1, base + NRF52_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF52_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF52_UART_ENABLE_DISABLE, base + NRF52_UART_ENABLE_OFFSET);
+  putreg32(0xffffffff, base + NRF52_UARTE_INTENCLR_OFFSET);
+  putreg32(1, base + NRF52_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF52_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF52_UARTE_ENABLE_DISABLE, base + NRF52_UARTE_ENABLE_OFFSET);
 
   /* Set UART format */
 
@@ -348,7 +353,7 @@ void nrf52_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELTXD_PIN_SHIFT);
   regval |= (port << UART_PSELTXD_PORT_SHIFT);
-  putreg32(regval, base + NRF52_UART_PSELTXD_OFFSET);
+  putreg32(regval, base + NRF52_UARTE_PSEL_TXD_OFFSET);
 
   /* Setect RX pins for UART */
 
@@ -357,11 +362,14 @@ void nrf52_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELRXD_PIN_SHIFT);
   regval |= (port << UART_PSELRXD_PORT_SHIFT);
-  putreg32(regval, base + NRF52_UART_PSELRXD_OFFSET);
+  putreg32(regval, base + NRF52_UARTE_PSEL_RXD_OFFSET);
+  putreg32(UART_PSELCTS_RESET, base + NRF52_UARTE_PSEL_CTS_OFFSET);
+  putreg32(UART_PSELRTS_RESET, base + NRF52_UARTE_PSEL_RTS_OFFSET);
+  putreg32(0, base + NRF52_UARTE_SHORTS_OFFSET);
 
   /* Enable UART */
 
-  putreg32(NRF52_UART_ENABLE_ENABLE, base + NRF52_UART_ENABLE_OFFSET);
+  putreg32(NRF52_UARTE_ENABLE_ENABLE, base + NRF52_UARTE_ENABLE_OFFSET);
 }
 
 /****************************************************************************
@@ -379,12 +387,12 @@ void nrf52_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Disable the UART */
 
-  putreg32(1, base + NRF52_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF52_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF52_UART_ENABLE_DISABLE, base + NRF52_UART_ENABLE_OFFSET);
+  putreg32(1, base + NRF52_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF52_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF52_UARTE_ENABLE_DISABLE, base + NRF52_UARTE_ENABLE_OFFSET);
 
-  putreg32(0xffffffff, base + NRF52_UART_PSELTXD_OFFSET);
-  putreg32(0xffffffff, base + NRF52_UART_PSELRXD_OFFSET);
+  putreg32(0xffffffff, base + NRF52_UARTE_PSEL_TXD_OFFSET);
+  putreg32(0xffffffff, base + NRF52_UARTE_PSEL_RXD_OFFSET);
 
   /* Unconfigure GPIO */
 
@@ -393,8 +401,8 @@ void nrf52_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Deatach TWI from GPIO */
 
-  putreg32(UART_PSELTXD_RESET, base + NRF52_UART_PSELTXD_OFFSET);
-  putreg32(UART_PSELRXD_RESET, base + NRF52_UART_PSELRXD_OFFSET);
+  putreg32(UART_PSELTXD_RESET, base + NRF52_UARTE_PSEL_TXD_OFFSET);
+  putreg32(UART_PSELRXD_RESET, base + NRF52_UARTE_PSEL_RXD_OFFSET);
 }
 
 /****************************************************************************
@@ -439,13 +447,24 @@ void nrf52_usart_setformat(uintptr_t base,
 void arm_lowputc(char ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  putreg32(1, CONSOLE_BASE + NRF52_UART_TASKS_STARTTX_OFFSET);
-  putreg32(0, CONSOLE_BASE + NRF52_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(ch, CONSOLE_BASE + NRF52_UART_TXD_OFFSET);
-  while (getreg32(CONSOLE_BASE + NRF52_UART_EVENTS_TXDRDY_OFFSET) == 0)
+  g_console_tx = ch;
+
+  putreg32(0, CONSOLE_BASE + NRF52_UARTE_EVENTS_ENDTX_OFFSET);
+  putreg32(0, CONSOLE_BASE + NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  putreg32((uintptr_t)&g_console_tx,
+           CONSOLE_BASE + NRF52_UARTE_TXD_PTR_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF52_UARTE_TXD_MAXCNT_OFFSET);
+
+  UP_DMB();
+
+  putreg32(1, CONSOLE_BASE + NRF52_UARTE_TASKS_STARTTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF52_UARTE_EVENTS_ENDTX_OFFSET) == 0)
     {
     }
 
-  putreg32(1, CONSOLE_BASE + NRF52_UART_TASKS_STOPTX_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF52_UARTE_TASKS_STOPTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET) == 0)
+    {
+    }
 #endif
 }
diff --git a/arch/arm/src/nrf52/nrf52_serial.c 
b/arch/arm/src/nrf52/nrf52_serial.c
index 047df233e3a..25da3063aa9 100644
--- a/arch/arm/src/nrf52/nrf52_serial.c
+++ b/arch/arm/src/nrf52/nrf52_serial.c
@@ -93,6 +93,9 @@
 #  define TTYS0_DEV           g_uart1port /* UART1 is ttyS0 */
 #endif
 
+#define RX_INTERRUPTS (UART_INT_ENDRX | UART_INT_ERROR | UART_INT_RXTO)
+#define TX_INTERRUPTS (UART_INT_ENDTX | UART_INT_TXSTOPPED)
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -101,9 +104,17 @@
 
 struct nrf52_dev_s
 {
-  uintptr_t uartbase;     /* Base address of UART registers */
-  uint8_t   irq;          /* IRQ associated with this UART */
-  bool      rx_available; /* rx byte available */
+  uintptr_t     uartbase;       /* Base address of UART registers */
+  uint8_t       irq;            /* IRQ associated with this UART */
+  uint8_t       rxdma;          /* Receive DMA buffer */
+  uint8_t       txdma;          /* Transmit DMA buffer */
+  uint8_t       rxchar;         /* Completed receive byte */
+  uint32_t      rxstatus;       /* Receive error status */
+  bool          rxvalid;        /* Receive byte available */
+  bool          rxenabled;      /* Upper-half reception enabled */
+  bool          rxactive;       /* Receiver started */
+  bool          txenabled;      /* Upper-half transmission enabled */
+  volatile bool txbusy;         /* DMA transmitter owns txdma */
 
   /* UART configuration */
 
@@ -169,7 +180,6 @@ static struct nrf52_dev_s g_uart0priv =
 {
   .uartbase       = NRF52_UART0_BASE,
   .irq            = NRF52_IRQ_UART0,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART0_BAUD,
@@ -211,7 +221,6 @@ static struct nrf52_dev_s g_uart1priv =
 {
   .uartbase       = NRF52_UART1_BASE,
   .irq            = NRF52_IRQ_UART1,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART1_BAUD,
@@ -262,6 +271,192 @@ static struct uart_dev_s * const g_uart_devs[NRF52_NUART] 
=
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: nrf52_uart_putreg
+ *
+ * Description:
+ *   Write a UART register.
+ *
+ ****************************************************************************/
+
+static inline void nrf52_uart_putreg(struct nrf52_dev_s *priv,
+                                     uint32_t offset, uint32_t value)
+{
+  putreg32(value, priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_uart_getreg
+ *
+ * Description:
+ *   Read a UART register.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf52_uart_getreg(struct nrf52_dev_s *priv,
+                                         uint32_t offset)
+{
+  return getreg32(priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_uart_clrevent
+ *
+ * Description:
+ *   Clear a UARTE event and read it back before returning.
+ *
+ ****************************************************************************/
+
+static void nrf52_uart_clrevent(struct nrf52_dev_s *priv, uint32_t event)
+{
+  nrf52_uart_putreg(priv, event, 0);
+  (void)nrf52_uart_getreg(priv, event);
+}
+
+/****************************************************************************
+ * Name: nrf52_rxstart
+ *
+ * Description:
+ *   Start reception and queue the first one-byte DMA buffer.
+ *
+ ****************************************************************************/
+
+static void nrf52_rxstart(struct nrf52_dev_s *priv)
+{
+  priv->rxactive = true;
+  priv->rxvalid = false;
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ENDRX_OFFSET);
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_RXTO_OFFSET);
+  nrf52_uart_putreg(priv, NRF52_UARTE_RXD_PTR_OFFSET,
+                    (uintptr_t)&priv->rxdma);
+  nrf52_uart_putreg(priv, NRF52_UARTE_RXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STARTRX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf52_rxdeliver
+ *
+ * Description:
+ *   Deliver the completed byte and restart the one-byte DMA. A byte
+ *   received with the delivery disabled is kept, the UART FIFO holds the
+ *   next bytes until rxint() enables the delivery.
+ *
+ ****************************************************************************/
+
+static void nrf52_rxdeliver(struct uart_dev_s *dev)
+{
+  struct nrf52_dev_s *priv = dev->priv;
+
+  if (priv->rxvalid && priv->rxenabled)
+    {
+      uart_recvchars(dev);
+      if (!priv->rxvalid)
+        {
+          UP_DMB();
+          nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STARTRX_OFFSET, 1);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: nrf52_rxstop
+ *
+ * Description:
+ *   Stop reception and deliver a completed byte. Interrupts must be
+ *   disabled.
+ *
+ ****************************************************************************/
+
+static void nrf52_rxstop(struct uart_dev_s *dev)
+{
+  struct nrf52_dev_s *priv = dev->priv;
+
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_RXTO_OFFSET);
+  nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STOPRX_OFFSET, 1);
+  while (!nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_RXTO_OFFSET))
+    {
+    }
+
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf52_uart_getreg(priv, NRF52_UARTE_ERRORSRC_OFFSET);
+      nrf52_uart_putreg(priv, NRF52_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
+
+  /* STOP also generates ENDRX for an empty buffer. Deliver a completed
+   * byte, but never deliver an empty buffer.
+   */
+
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_RXD_AMOUNT_OFFSET) != 0)
+    {
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
+      if (priv->rxenabled)
+        {
+          uart_recvchars(dev);
+        }
+
+      priv->rxvalid = false;
+    }
+
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ENDRX_OFFSET);
+}
+
+/****************************************************************************
+ * Name: nrf52_txstart
+ *
+ * Description:
+ *   Start a one-byte DMA transfer. The caller must serialize access.
+ *
+ ****************************************************************************/
+
+static void nrf52_txstart(struct nrf52_dev_s *priv, int ch)
+{
+  priv->txdma = ch;
+  priv->txbusy = true;
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ENDTX_OFFSET);
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  nrf52_uart_putreg(priv, NRF52_UARTE_TXD_PTR_OFFSET,
+                    (uintptr_t)&priv->txdma);
+  nrf52_uart_putreg(priv, NRF52_UARTE_TXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STARTTX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf52_txstop
+ *
+ * Description:
+ *   Wait for the transmitter to stop. Interrupts must be disabled.
+ *
+ ****************************************************************************/
+
+static void nrf52_txstop(struct nrf52_dev_s *priv)
+{
+  if (priv->txbusy)
+    {
+      while (!nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ENDTX_OFFSET) &&
+             !nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+        }
+
+      if (!nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+          nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STOPTX_OFFSET, 1);
+          while (!nrf52_uart_getreg(priv,
+                                    NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET))
+            {
+            }
+        }
+
+      priv->txbusy = false;
+    }
+}
+
 /****************************************************************************
  * Name: nrf52_setup
  *
@@ -318,15 +513,10 @@ static void nrf52_shutdown(struct uart_dev_s *dev)
  * Name: nrf52_attach
  *
  * Description:
- *   Configure the UART to operation in interrupt driven mode.  This method
- *   is called when the serial port is opened.  Normally, this is just after
- *   the setup() method is called, however, the serial console may
- *   operate in a non-interrupt driven mode during the boot phase.
- *
- *   RX and TX interrupts are not enabled when by the attach method (unless
- *   the hardware supports multiple levels of interrupt enabling).
- *   The RX and TX interrupts are not enabled until the txint() and rxint()
- *   methods are called.
+ *   Configure the UART to operate in interrupt driven mode. This method
+ *   is called when the serial port is opened, normally just after setup.
+ *   DMA completion interrupts release buffers even when delivery to the
+ *   upper half is disabled by the rxint() and txint() methods.
  *
  ****************************************************************************/
 
@@ -335,14 +525,17 @@ static int nrf52_attach(struct uart_dev_s *dev)
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
   int ret;
 
-  /* Attach and enable the IRQ(s).  The interrupts are (probably) still
-   * disabled in the C2 register.
-   */
+  /* Attach and enable the IRQ */
 
   ret = irq_attach(priv->irq, nrf52_interrupt, dev);
   if (ret == OK)
     {
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+      nrf52_uart_putreg(priv, NRF52_UARTE_INTENSET_OFFSET,
+                        RX_INTERRUPTS | TX_INTERRUPTS);
       up_enable_irq(priv->irq);
+      nrf52_rxstart(priv);
+#endif
     }
 
   return ret;
@@ -352,7 +545,7 @@ static int nrf52_attach(struct uart_dev_s *dev)
  * Name: nrf52_detach
  *
  * Description:
- *   Detach UART interrupts.  This method is called when the serial port is
+ *   Detach UART interrupts. This method is called when the serial port is
  *   closed normally just before the shutdown method is called.
  *   The exception is the serial console which is never shutdown.
  *
@@ -361,14 +554,23 @@ static int nrf52_attach(struct uart_dev_s *dev)
 static void nrf52_detach(struct uart_dev_s *dev)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
+  irqstate_t flags;
 
-  /* Disable interrupts */
+  /* Stop DMA before detaching the interrupt handler */
 
-  putreg32(UART_INT_RXDRDY, priv->uartbase + NRF52_UART_INTENCLR_OFFSET);
-  up_disable_irq(priv->irq);
+  flags = enter_critical_section();
+  nrf52_uart_putreg(priv, NRF52_UARTE_INTENCLR_OFFSET, UINT32_MAX);
+
+  if (priv->rxactive)
+    {
+      nrf52_rxstop(dev);
+      priv->rxactive = false;
+    }
 
-  /* Detach from the interrupt(s) */
+  nrf52_txstop(priv);
+  leave_critical_section(flags);
 
+  up_disable_irq(priv->irq);
   irq_detach(priv->irq);
 }
 
@@ -376,37 +578,56 @@ static void nrf52_detach(struct uart_dev_s *dev)
  * Name: nrf52_interrupt
  *
  * Description:
- *   This is the UART interrupt handler.  It will be invoked when an
- *   interrupt is received on the 'irq'.  It should call uart_xmitchars or
- *   uart_recvchars to perform the appropriate data transfers.  The
- *   interrupt handling logic must be able to map the 'arg' to the
- *   appropriate uart_dev_s structure in order to call these functions.
+ *   Handle receive buffers and transfer completion.
  *
  ****************************************************************************/
 
 static int nrf52_interrupt(int irq, void *context, void *arg)
 {
-  struct uart_dev_s *dev = (struct uart_dev_s *)arg;
-  struct nrf52_dev_s *priv;
-  uint32_t regval;
-
-  DEBUGASSERT(dev != NULL && dev->priv != NULL);
-  priv = (struct nrf52_dev_s *)dev->priv;
+  struct uart_dev_s *dev = arg;
+  struct nrf52_dev_s *priv = dev->priv;
 
-  /* Check RX event */
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf52_uart_getreg(priv, NRF52_UARTE_ERRORSRC_OFFSET);
+      nrf52_uart_putreg(priv, NRF52_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
 
-  regval = getreg32(priv->uartbase + NRF52_UART_EVENTS_RXDRDY_OFFSET);
+  /* Copy the completed byte before restarting DMA. Automatic ENDRX-to-
+   * STARTRX would let DMA overwrite a buffer before the upper half
+   * consumes it. The UART FIFO holds incoming bytes between transfers.
+   */
 
-  if (regval != 0)
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ENDRX_OFFSET))
     {
-      putreg32(0, priv->uartbase + NRF52_UART_EVENTS_RXDRDY_OFFSET);
-      priv->rx_available = true;
-      uart_recvchars(dev);
+      nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ENDRX_OFFSET);
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
     }
 
-  /* Clear errors */
+  nrf52_rxdeliver(dev);
+  nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_RXTO_OFFSET);
 
-  putreg32(0, priv->uartbase + NRF52_UART_ERRORSRC_OFFSET);
+  /* There is no ENDTX-to-STOPTX shortcut */
+
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ENDTX_OFFSET))
+    {
+      nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_ENDTX_OFFSET);
+      nrf52_uart_putreg(priv, NRF52_UARTE_TASKS_STOPTX_OFFSET, 1);
+    }
+
+  if (nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET))
+    {
+      nrf52_uart_clrevent(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET);
+      priv->txbusy = false;
+      if (priv->txenabled)
+        {
+          uart_xmitchars(dev);
+        }
+    }
 
   return OK;
 }
@@ -415,7 +636,7 @@ static int nrf52_interrupt(int irq, void *context, void 
*arg)
  * Name: nrf52_set_format
  *
  * Description:
- *   Set the serial line format and speed.
+ *   Set the serial line format and speed with DMA stopped.
  *
  ****************************************************************************/
 
@@ -423,8 +644,29 @@ static int nrf52_interrupt(int irq, void *context, void 
*arg)
 void nrf52_set_format(struct uart_dev_s *dev)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (priv->rxactive)
+    {
+      nrf52_rxstop(dev);
+    }
+
+  nrf52_txstop(priv);
 
+  nrf52_uart_putreg(priv, NRF52_UARTE_ENABLE_OFFSET,
+                    NRF52_UARTE_ENABLE_DISABLE);
   nrf52_usart_setformat(priv->uartbase, &priv->config);
+  nrf52_uart_putreg(priv, NRF52_UARTE_ENABLE_OFFSET,
+                    NRF52_UARTE_ENABLE_ENABLE);
+
+  if (priv->rxactive)
+    {
+      nrf52_rxstart(priv);
+    }
+
+  leave_critical_section(flags);
 }
 #endif
 
@@ -563,61 +805,48 @@ static int nrf52_ioctl(struct file *filep, int cmd, 
unsigned long arg)
 static int nrf52_receive(struct uart_dev_s *dev, unsigned int *status)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
-  uint32_t data;
-
-  /* Get input data along with receiver control information */
-
-  data = getreg32(priv->uartbase + NRF52_UART_RXD_OFFSET);
-  priv->rx_available = false;
-
-  /* Return receiver control information */
 
   if (status)
     {
-      *status = 0x00;
+      *status = priv->rxstatus;
     }
 
-  /* Then return the actual received data. */
-
-  return data;
+  priv->rxstatus = 0;
+  priv->rxvalid = false;
+  return priv->rxchar;
 }
 
 /****************************************************************************
  * Name: nrf52_rxint
  *
  * Description:
- *   Call to enable or disable RX interrupts
+ *   Enable or disable delivery of received characters to the upper half.
  *
  ****************************************************************************/
 
 static void nrf52_rxint(struct uart_dev_s *dev, bool enable)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  if (enable)
-    {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      /* Receive an interrupt when their is anything in the Rx data register
-       * (or an Rx timeout occurs).
-       */
-
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF52_UART_INTENSET_OFFSET);
-      putreg32(1, priv->uartbase + NRF52_UART_TASKS_STARTRX_OFFSET);
-
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
 #endif
-    }
-  else
+
+  priv->rxenabled = enable;
+  if (enable)
     {
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF52_UART_INTENCLR_OFFSET);
-      putreg32(1, priv->uartbase + NRF52_UART_TASKS_STOPRX_OFFSET);
+      nrf52_rxdeliver(dev);
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf52_rxavailable
  *
  * Description:
- *   Return true if the receive register is not empty
+ *   Report whether a received character is waiting for the upper half.
  *
  ****************************************************************************/
 
@@ -625,82 +854,71 @@ static bool nrf52_rxavailable(struct uart_dev_s *dev)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
 
-  /* Return true if the receive buffer/fifo is not "empty." */
-
-  return priv->rx_available;
+  return priv->rxvalid;
 }
 
 /****************************************************************************
  * Name: nrf52_send
  *
  * Description:
- *   This method will send one byte on the UART.
+ *   Start transmitting the character supplied by the upper half.
  *
  ****************************************************************************/
 
 static void nrf52_send(struct uart_dev_s *dev, int ch)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  putreg32(0, priv->uartbase + NRF52_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(1, priv->uartbase + NRF52_UART_TASKS_STARTTX_OFFSET);
-
-  putreg32(ch, priv->uartbase + NRF52_UART_TXD_OFFSET);
-  while (getreg32(priv->uartbase + NRF52_UART_EVENTS_TXDRDY_OFFSET) == 0)
-    {
-    }
-
-  putreg32(1, priv->uartbase + NRF52_UART_TASKS_STOPTX_OFFSET);
+  nrf52_txstart(priv, ch);
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf52_txint
  *
  * Description:
- *   Call to enable or disable TX interrupts
+ *   Enable or disable transmission from the upper-half transmit buffer.
  *
  ****************************************************************************/
 
 static void nrf52_txint(struct uart_dev_s *dev, bool enable)
 {
-  /* struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv; */
+  struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
+#endif
+
+  priv->txenabled = enable;
   if (enable)
     {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      irqstate_t flags;
-
-      /* Enable the TX interrupt */
-
-      flags = enter_critical_section();
-
-      /* Fake a TX interrupt here by just calling uart_xmitchars() with
-       * interrupts disabled (note this may recurse).
-       */
-
       uart_xmitchars(dev);
-      leave_critical_section(flags);
-#endif
-    }
-  else
-    {
-      /* Disable the TX interrupt */
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf52_txready
  *
  * Description:
- *   Return true if the tranmsit data register is empty
+ *   Report whether the transmitter can accept another character. The
+ *   events are read, the upper half also polls with interrupts disabled.
+ *   A transfer ended without STOPTX can be restarted.
  *
  ****************************************************************************/
 
 static bool nrf52_txready(struct uart_dev_s *dev)
 {
-  /* struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv; */
+  struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
 
-  /* Return true if the transmit FIFO is "not full." */
+  if (priv->txbusy)
+    {
+      return nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_ENDTX_OFFSET) ||
+             nrf52_uart_getreg(priv, NRF52_UARTE_EVENTS_TXSTOPPED_OFFSET);
+    }
 
   return true;
 }
@@ -715,11 +933,7 @@ static bool nrf52_txready(struct uart_dev_s *dev)
 
 static bool nrf52_txempty(struct uart_dev_s *dev)
 {
-  /* struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv; */
-
-  /* Return true if the transmit FIFO is "empty." */
-
-  return true;
+  return nrf52_txready(dev);
 }
 
 /****************************************************************************
@@ -817,9 +1031,14 @@ void arm_serialinit(void)
 void up_putc(int ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  /* struct nrf52_dev_s *priv = (struct nrf52_dev_s *)CONSOLE_DEV.priv; */
+  struct nrf52_dev_s *priv = CONSOLE_DEV.priv;
+  irqstate_t flags = enter_critical_section();
+
+  /* Serialize polled debug output with the interrupt-driven transmitter */
 
+  nrf52_txstop(priv);
   arm_lowputc(ch);
+  leave_critical_section(flags);
 #endif
 }
 
diff --git a/arch/arm/src/nrf53/hardware/nrf53_uarte.h 
b/arch/arm/src/nrf53/hardware/nrf53_uarte.h
index 3df7fecb459..9d76f039d9a 100644
--- a/arch/arm/src/nrf53/hardware/nrf53_uarte.h
+++ b/arch/arm/src/nrf53/hardware/nrf53_uarte.h
@@ -262,6 +262,8 @@
 
 #define NRF53_UART_ENABLE_DISABLE           (0)
 #define NRF53_UART_ENABLE_ENABLE            (4)
+#define NRF53_UARTE_ENABLE_DISABLE          (0)
+#define NRF53_UARTE_ENABLE_ENABLE           (8)
 
 /* INTEN/INTENSET/INTENCLR Register */
 
diff --git a/arch/arm/src/nrf53/nrf53_lowputc.c 
b/arch/arm/src/nrf53/nrf53_lowputc.c
index dfcf39c6f03..2c6a8ef1441 100644
--- a/arch/arm/src/nrf53/nrf53_lowputc.c
+++ b/arch/arm/src/nrf53/nrf53_lowputc.c
@@ -79,6 +79,10 @@ static const struct uart_config_s g_console_config =
   .txpin     = CONSOLE_TX_PIN,
   .rxpin     = CONSOLE_RX_PIN,
 };
+
+/* Console byte transmitted by EasyDMA */
+
+static uint8_t g_console_tx;
 #endif /* HAVE_UART_CONSOLE */
 
 /****************************************************************************
@@ -219,7 +223,7 @@ static void nrf53_setbaud(uintptr_t base, const struct 
uart_config_s *config)
         }
     }
 
-  putreg32(br, base + NRF53_UART_BAUDRATE_OFFSET);
+  putreg32(br, base + NRF53_UARTE_BAUDRATE_OFFSET);
 }
 
 /****************************************************************************
@@ -231,7 +235,7 @@ static void nrf53_setparity(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF53_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF53_UARTE_CONFIG_OFFSET);
 
   if (config->parity == 2)
     {
@@ -246,7 +250,7 @@ static void nrf53_setparity(uintptr_t base,
       regval &= ~UART_CONFIG_PARITY;
     }
 
-  putreg32(regval, base + NRF53_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF53_UARTE_CONFIG_OFFSET);
 }
 
 /****************************************************************************
@@ -259,7 +263,7 @@ static void nrf53_setstops(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF53_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF53_UARTE_CONFIG_OFFSET);
 
   if (config->stopbits2 == true)
     {
@@ -270,7 +274,7 @@ static void nrf53_setstops(uintptr_t base,
       regval &= ~UART_CONFIG_STOP;
     }
 
-  putreg32(regval, base + NRF53_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF53_UARTE_CONFIG_OFFSET);
 }
 #endif
 
@@ -328,9 +332,10 @@ void nrf53_usart_configure(uintptr_t base,
   uint32_t port   = 0;
   uint32_t regval = 0;
 
-  putreg32(1, base + NRF53_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF53_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF53_UART_ENABLE_DISABLE, base + NRF53_UART_ENABLE_OFFSET);
+  putreg32(0xffffffff, base + NRF53_UARTE_INTENCLR_OFFSET);
+  putreg32(1, base + NRF53_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF53_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF53_UARTE_ENABLE_DISABLE, base + NRF53_UARTE_ENABLE_OFFSET);
 
   /* Set UART format */
 
@@ -348,7 +353,7 @@ void nrf53_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELTXD_PIN_SHIFT);
   regval |= (port << UART_PSELTXD_PORT_SHIFT);
-  putreg32(regval, base + NRF53_UART_PSELTXD_OFFSET);
+  putreg32(regval, base + NRF53_UARTE_PSEL_TXD_OFFSET);
 
   /* Setect RX pins for UART */
 
@@ -357,11 +362,14 @@ void nrf53_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELRXD_PIN_SHIFT);
   regval |= (port << UART_PSELRXD_PORT_SHIFT);
-  putreg32(regval, base + NRF53_UART_PSELRXD_OFFSET);
+  putreg32(regval, base + NRF53_UARTE_PSEL_RXD_OFFSET);
+  putreg32(UART_PSELCTS_RESET, base + NRF53_UARTE_PSEL_CTS_OFFSET);
+  putreg32(UART_PSELRTS_RESET, base + NRF53_UARTE_PSEL_RTS_OFFSET);
+  putreg32(0, base + NRF53_UARTE_SHORTS_OFFSET);
 
   /* Enable UART */
 
-  putreg32(NRF53_UART_ENABLE_ENABLE, base + NRF53_UART_ENABLE_OFFSET);
+  putreg32(NRF53_UARTE_ENABLE_ENABLE, base + NRF53_UARTE_ENABLE_OFFSET);
 }
 
 /****************************************************************************
@@ -379,12 +387,12 @@ void nrf53_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Disable the UART */
 
-  putreg32(1, base + NRF53_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF53_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF53_UART_ENABLE_DISABLE, base + NRF53_UART_ENABLE_OFFSET);
+  putreg32(1, base + NRF53_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF53_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF53_UARTE_ENABLE_DISABLE, base + NRF53_UARTE_ENABLE_OFFSET);
 
-  putreg32(0xffffffff, base + NRF53_UART_PSELTXD_OFFSET);
-  putreg32(0xffffffff, base + NRF53_UART_PSELRXD_OFFSET);
+  putreg32(0xffffffff, base + NRF53_UARTE_PSEL_TXD_OFFSET);
+  putreg32(0xffffffff, base + NRF53_UARTE_PSEL_RXD_OFFSET);
 
   /* Unconfigure GPIO */
 
@@ -393,8 +401,8 @@ void nrf53_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Deatach TWI from GPIO */
 
-  putreg32(UART_PSELTXD_RESET, base + NRF53_UART_PSELTXD_OFFSET);
-  putreg32(UART_PSELRXD_RESET, base + NRF53_UART_PSELRXD_OFFSET);
+  putreg32(UART_PSELTXD_RESET, base + NRF53_UARTE_PSEL_TXD_OFFSET);
+  putreg32(UART_PSELRXD_RESET, base + NRF53_UARTE_PSEL_RXD_OFFSET);
 }
 
 /****************************************************************************
@@ -439,13 +447,24 @@ void nrf53_usart_setformat(uintptr_t base,
 void arm_lowputc(char ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  putreg32(1, CONSOLE_BASE + NRF53_UART_TASKS_STARTTX_OFFSET);
-  putreg32(0, CONSOLE_BASE + NRF53_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(ch, CONSOLE_BASE + NRF53_UART_TXD_OFFSET);
-  while (getreg32(CONSOLE_BASE + NRF53_UART_EVENTS_TXDRDY_OFFSET) == 0)
+  g_console_tx = ch;
+
+  putreg32(0, CONSOLE_BASE + NRF53_UARTE_EVENTS_ENDTX_OFFSET);
+  putreg32(0, CONSOLE_BASE + NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  putreg32((uintptr_t)&g_console_tx,
+           CONSOLE_BASE + NRF53_UARTE_TXD_PTR_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF53_UARTE_TXD_MAXCNT_OFFSET);
+
+  UP_DMB();
+
+  putreg32(1, CONSOLE_BASE + NRF53_UARTE_TASKS_STARTTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF53_UARTE_EVENTS_ENDTX_OFFSET) == 0)
     {
     }
 
-  putreg32(1, CONSOLE_BASE + NRF53_UART_TASKS_STOPTX_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF53_UARTE_TASKS_STOPTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET) == 0)
+    {
+    }
 #endif
 }
diff --git a/arch/arm/src/nrf53/nrf53_serial.c 
b/arch/arm/src/nrf53/nrf53_serial.c
index c5924a8cb45..05f247a8410 100644
--- a/arch/arm/src/nrf53/nrf53_serial.c
+++ b/arch/arm/src/nrf53/nrf53_serial.c
@@ -93,6 +93,9 @@
 #  define TTYS0_DEV           g_uart1port /* UART1 is ttyS0 */
 #endif
 
+#define RX_INTERRUPTS (UART_INT_ENDRX | UART_INT_ERROR | UART_INT_RXTO)
+#define TX_INTERRUPTS (UART_INT_ENDTX | UART_INT_TXSTOPPED)
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -101,9 +104,17 @@
 
 struct nrf53_dev_s
 {
-  uintptr_t uartbase;     /* Base address of UART registers */
-  uint8_t   irq;          /* IRQ associated with this UART */
-  bool      rx_available; /* rx byte available */
+  uintptr_t     uartbase;       /* Base address of UART registers */
+  uint8_t       irq;            /* IRQ associated with this UART */
+  uint8_t       rxdma;          /* Receive DMA buffer */
+  uint8_t       txdma;          /* Transmit DMA buffer */
+  uint8_t       rxchar;         /* Completed receive byte */
+  uint32_t      rxstatus;       /* Receive error status */
+  bool          rxvalid;        /* Receive byte available */
+  bool          rxenabled;      /* Upper-half reception enabled */
+  bool          rxactive;       /* Receiver started */
+  bool          txenabled;      /* Upper-half transmission enabled */
+  volatile bool txbusy;         /* DMA transmitter owns txdma */
 
   /* UART configuration */
 
@@ -169,7 +180,6 @@ static struct nrf53_dev_s g_uart0priv =
 {
   .uartbase       = NRF53_UART0_BASE,
   .irq            = NRF53_IRQ_SERIAL0,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART0_BAUD,
@@ -211,7 +221,6 @@ static struct nrf53_dev_s g_uart1priv =
 {
   .uartbase       = NRF53_UART1_BASE,
   .irq            = NRF53_IRQ_SERIAL1,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART1_BAUD,
@@ -262,6 +271,192 @@ static struct uart_dev_s * const g_uart_devs[NRF53_NUART] 
=
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: nrf53_uart_putreg
+ *
+ * Description:
+ *   Write a UART register.
+ *
+ ****************************************************************************/
+
+static inline void nrf53_uart_putreg(struct nrf53_dev_s *priv,
+                                     uint32_t offset, uint32_t value)
+{
+  putreg32(value, priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_uart_getreg
+ *
+ * Description:
+ *   Read a UART register.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf53_uart_getreg(struct nrf53_dev_s *priv,
+                                         uint32_t offset)
+{
+  return getreg32(priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_uart_clrevent
+ *
+ * Description:
+ *   Clear a UARTE event and read it back before returning.
+ *
+ ****************************************************************************/
+
+static void nrf53_uart_clrevent(struct nrf53_dev_s *priv, uint32_t event)
+{
+  nrf53_uart_putreg(priv, event, 0);
+  (void)nrf53_uart_getreg(priv, event);
+}
+
+/****************************************************************************
+ * Name: nrf53_rxstart
+ *
+ * Description:
+ *   Start reception and queue the first one-byte DMA buffer.
+ *
+ ****************************************************************************/
+
+static void nrf53_rxstart(struct nrf53_dev_s *priv)
+{
+  priv->rxactive = true;
+  priv->rxvalid = false;
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ENDRX_OFFSET);
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_RXTO_OFFSET);
+  nrf53_uart_putreg(priv, NRF53_UARTE_RXD_PTR_OFFSET,
+                    (uintptr_t)&priv->rxdma);
+  nrf53_uart_putreg(priv, NRF53_UARTE_RXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STARTRX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf53_rxdeliver
+ *
+ * Description:
+ *   Deliver the completed byte and restart the one-byte DMA. A byte
+ *   received with the delivery disabled is kept, the UART FIFO holds the
+ *   next bytes until rxint() enables the delivery.
+ *
+ ****************************************************************************/
+
+static void nrf53_rxdeliver(struct uart_dev_s *dev)
+{
+  struct nrf53_dev_s *priv = dev->priv;
+
+  if (priv->rxvalid && priv->rxenabled)
+    {
+      uart_recvchars(dev);
+      if (!priv->rxvalid)
+        {
+          UP_DMB();
+          nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STARTRX_OFFSET, 1);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: nrf53_rxstop
+ *
+ * Description:
+ *   Stop reception and deliver a completed byte. Interrupts must be
+ *   disabled.
+ *
+ ****************************************************************************/
+
+static void nrf53_rxstop(struct uart_dev_s *dev)
+{
+  struct nrf53_dev_s *priv = dev->priv;
+
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_RXTO_OFFSET);
+  nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STOPRX_OFFSET, 1);
+  while (!nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_RXTO_OFFSET))
+    {
+    }
+
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf53_uart_getreg(priv, NRF53_UARTE_ERRORSRC_OFFSET);
+      nrf53_uart_putreg(priv, NRF53_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
+
+  /* STOP also generates ENDRX for an empty buffer. Deliver a completed
+   * byte, but never deliver an empty buffer.
+   */
+
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_RXD_AMOUNT_OFFSET) != 0)
+    {
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
+      if (priv->rxenabled)
+        {
+          uart_recvchars(dev);
+        }
+
+      priv->rxvalid = false;
+    }
+
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ENDRX_OFFSET);
+}
+
+/****************************************************************************
+ * Name: nrf53_txstart
+ *
+ * Description:
+ *   Start a one-byte DMA transfer. The caller must serialize access.
+ *
+ ****************************************************************************/
+
+static void nrf53_txstart(struct nrf53_dev_s *priv, int ch)
+{
+  priv->txdma = ch;
+  priv->txbusy = true;
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ENDTX_OFFSET);
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  nrf53_uart_putreg(priv, NRF53_UARTE_TXD_PTR_OFFSET,
+                    (uintptr_t)&priv->txdma);
+  nrf53_uart_putreg(priv, NRF53_UARTE_TXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STARTTX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf53_txstop
+ *
+ * Description:
+ *   Wait for the transmitter to stop. Interrupts must be disabled.
+ *
+ ****************************************************************************/
+
+static void nrf53_txstop(struct nrf53_dev_s *priv)
+{
+  if (priv->txbusy)
+    {
+      while (!nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ENDTX_OFFSET) &&
+             !nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+        }
+
+      if (!nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+          nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STOPTX_OFFSET, 1);
+          while (!nrf53_uart_getreg(priv,
+                                    NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET))
+            {
+            }
+        }
+
+      priv->txbusy = false;
+    }
+}
+
 /****************************************************************************
  * Name: nrf53_setup
  *
@@ -318,15 +513,10 @@ static void nrf53_shutdown(struct uart_dev_s *dev)
  * Name: nrf53_attach
  *
  * Description:
- *   Configure the UART to operation in interrupt driven mode.  This method
- *   is called when the serial port is opened.  Normally, this is just after
- *   the setup() method is called, however, the serial console may
- *   operate in a non-interrupt driven mode during the boot phase.
- *
- *   RX and TX interrupts are not enabled when by the attach method (unless
- *   the hardware supports multiple levels of interrupt enabling).
- *   The RX and TX interrupts are not enabled until the txint() and rxint()
- *   methods are called.
+ *   Configure the UART to operate in interrupt driven mode. This method
+ *   is called when the serial port is opened, normally just after setup.
+ *   DMA completion interrupts release buffers even when delivery to the
+ *   upper half is disabled by the rxint() and txint() methods.
  *
  ****************************************************************************/
 
@@ -335,14 +525,17 @@ static int nrf53_attach(struct uart_dev_s *dev)
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
   int ret;
 
-  /* Attach and enable the IRQ(s).  The interrupts are (probably) still
-   * disabled in the C2 register.
-   */
+  /* Attach and enable the IRQ */
 
   ret = irq_attach(priv->irq, nrf53_interrupt, dev);
   if (ret == OK)
     {
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+      nrf53_uart_putreg(priv, NRF53_UARTE_INTENSET_OFFSET,
+                        RX_INTERRUPTS | TX_INTERRUPTS);
       up_enable_irq(priv->irq);
+      nrf53_rxstart(priv);
+#endif
     }
 
   return ret;
@@ -352,7 +545,7 @@ static int nrf53_attach(struct uart_dev_s *dev)
  * Name: nrf53_detach
  *
  * Description:
- *   Detach UART interrupts.  This method is called when the serial port is
+ *   Detach UART interrupts. This method is called when the serial port is
  *   closed normally just before the shutdown method is called.
  *   The exception is the serial console which is never shutdown.
  *
@@ -361,14 +554,23 @@ static int nrf53_attach(struct uart_dev_s *dev)
 static void nrf53_detach(struct uart_dev_s *dev)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
+  irqstate_t flags;
 
-  /* Disable interrupts */
+  /* Stop DMA before detaching the interrupt handler */
 
-  putreg32(UART_INT_RXDRDY, priv->uartbase + NRF53_UART_INTENCLR_OFFSET);
-  up_disable_irq(priv->irq);
+  flags = enter_critical_section();
+  nrf53_uart_putreg(priv, NRF53_UARTE_INTENCLR_OFFSET, UINT32_MAX);
+
+  if (priv->rxactive)
+    {
+      nrf53_rxstop(dev);
+      priv->rxactive = false;
+    }
 
-  /* Detach from the interrupt(s) */
+  nrf53_txstop(priv);
+  leave_critical_section(flags);
 
+  up_disable_irq(priv->irq);
   irq_detach(priv->irq);
 }
 
@@ -376,37 +578,56 @@ static void nrf53_detach(struct uart_dev_s *dev)
  * Name: nrf53_interrupt
  *
  * Description:
- *   This is the UART interrupt handler.  It will be invoked when an
- *   interrupt is received on the 'irq'.  It should call uart_xmitchars or
- *   uart_recvchars to perform the appropriate data transfers.  The
- *   interrupt handling logic must be able to map the 'arg' to the
- *   appropriate uart_dev_s structure in order to call these functions.
+ *   Handle receive buffers and transfer completion.
  *
  ****************************************************************************/
 
 static int nrf53_interrupt(int irq, void *context, void *arg)
 {
-  struct uart_dev_s *dev = (struct uart_dev_s *)arg;
-  struct nrf53_dev_s *priv;
-  uint32_t regval;
-
-  DEBUGASSERT(dev != NULL && dev->priv != NULL);
-  priv = (struct nrf53_dev_s *)dev->priv;
+  struct uart_dev_s *dev = arg;
+  struct nrf53_dev_s *priv = dev->priv;
 
-  /* Check RX event */
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf53_uart_getreg(priv, NRF53_UARTE_ERRORSRC_OFFSET);
+      nrf53_uart_putreg(priv, NRF53_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
 
-  regval = getreg32(priv->uartbase + NRF53_UART_EVENTS_RXDRDY_OFFSET);
+  /* Copy the completed byte before restarting DMA. Automatic ENDRX-to-
+   * STARTRX would let DMA overwrite a buffer before the upper half
+   * consumes it. The UART FIFO holds incoming bytes between transfers.
+   */
 
-  if (regval != 0)
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ENDRX_OFFSET))
     {
-      putreg32(0, priv->uartbase + NRF53_UART_EVENTS_RXDRDY_OFFSET);
-      priv->rx_available = true;
-      uart_recvchars(dev);
+      nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ENDRX_OFFSET);
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
     }
 
-  /* Clear errors */
+  nrf53_rxdeliver(dev);
+  nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_RXTO_OFFSET);
 
-  putreg32(0, priv->uartbase + NRF53_UART_ERRORSRC_OFFSET);
+  /* There is no ENDTX-to-STOPTX shortcut */
+
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ENDTX_OFFSET))
+    {
+      nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_ENDTX_OFFSET);
+      nrf53_uart_putreg(priv, NRF53_UARTE_TASKS_STOPTX_OFFSET, 1);
+    }
+
+  if (nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET))
+    {
+      nrf53_uart_clrevent(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET);
+      priv->txbusy = false;
+      if (priv->txenabled)
+        {
+          uart_xmitchars(dev);
+        }
+    }
 
   return OK;
 }
@@ -415,7 +636,7 @@ static int nrf53_interrupt(int irq, void *context, void 
*arg)
  * Name: nrf53_set_format
  *
  * Description:
- *   Set the serial line format and speed.
+ *   Set the serial line format and speed with DMA stopped.
  *
  ****************************************************************************/
 
@@ -423,8 +644,29 @@ static int nrf53_interrupt(int irq, void *context, void 
*arg)
 void nrf53_set_format(struct uart_dev_s *dev)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (priv->rxactive)
+    {
+      nrf53_rxstop(dev);
+    }
+
+  nrf53_txstop(priv);
 
+  nrf53_uart_putreg(priv, NRF53_UARTE_ENABLE_OFFSET,
+                    NRF53_UARTE_ENABLE_DISABLE);
   nrf53_usart_setformat(priv->uartbase, &priv->config);
+  nrf53_uart_putreg(priv, NRF53_UARTE_ENABLE_OFFSET,
+                    NRF53_UARTE_ENABLE_ENABLE);
+
+  if (priv->rxactive)
+    {
+      nrf53_rxstart(priv);
+    }
+
+  leave_critical_section(flags);
 }
 #endif
 
@@ -563,61 +805,48 @@ static int nrf53_ioctl(struct file *filep, int cmd, 
unsigned long arg)
 static int nrf53_receive(struct uart_dev_s *dev, unsigned int *status)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
-  uint32_t data;
-
-  /* Get input data along with receiver control information */
-
-  data = getreg32(priv->uartbase + NRF53_UART_RXD_OFFSET);
-  priv->rx_available = false;
-
-  /* Return receiver control information */
 
   if (status)
     {
-      *status = 0x00;
+      *status = priv->rxstatus;
     }
 
-  /* Then return the actual received data. */
-
-  return data;
+  priv->rxstatus = 0;
+  priv->rxvalid = false;
+  return priv->rxchar;
 }
 
 /****************************************************************************
  * Name: nrf53_rxint
  *
  * Description:
- *   Call to enable or disable RX interrupts
+ *   Enable or disable delivery of received characters to the upper half.
  *
  ****************************************************************************/
 
 static void nrf53_rxint(struct uart_dev_s *dev, bool enable)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  if (enable)
-    {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      /* Receive an interrupt when their is anything in the Rx data register
-       * (or an Rx timeout occurs).
-       */
-
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF53_UART_INTENSET_OFFSET);
-      putreg32(1, priv->uartbase + NRF53_UART_TASKS_STARTRX_OFFSET);
-
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
 #endif
-    }
-  else
+
+  priv->rxenabled = enable;
+  if (enable)
     {
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF53_UART_INTENCLR_OFFSET);
-      putreg32(1, priv->uartbase + NRF53_UART_TASKS_STOPRX_OFFSET);
+      nrf53_rxdeliver(dev);
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf53_rxavailable
  *
  * Description:
- *   Return true if the receive register is not empty
+ *   Report whether a received character is waiting for the upper half.
  *
  ****************************************************************************/
 
@@ -625,82 +854,71 @@ static bool nrf53_rxavailable(struct uart_dev_s *dev)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
 
-  /* Return true if the receive buffer/fifo is not "empty." */
-
-  return priv->rx_available;
+  return priv->rxvalid;
 }
 
 /****************************************************************************
  * Name: nrf53_send
  *
  * Description:
- *   This method will send one byte on the UART.
+ *   Start transmitting the character supplied by the upper half.
  *
  ****************************************************************************/
 
 static void nrf53_send(struct uart_dev_s *dev, int ch)
 {
   struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  putreg32(0, priv->uartbase + NRF53_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(1, priv->uartbase + NRF53_UART_TASKS_STARTTX_OFFSET);
-
-  putreg32(ch, priv->uartbase + NRF53_UART_TXD_OFFSET);
-  while (getreg32(priv->uartbase + NRF53_UART_EVENTS_TXDRDY_OFFSET) == 0)
-    {
-    }
-
-  putreg32(1, priv->uartbase + NRF53_UART_TASKS_STOPTX_OFFSET);
+  nrf53_txstart(priv, ch);
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf53_txint
  *
  * Description:
- *   Call to enable or disable TX interrupts
+ *   Enable or disable transmission from the upper-half transmit buffer.
  *
  ****************************************************************************/
 
 static void nrf53_txint(struct uart_dev_s *dev, bool enable)
 {
-  /* struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv; */
+  struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
+#endif
+
+  priv->txenabled = enable;
   if (enable)
     {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      irqstate_t flags;
-
-      /* Enable the TX interrupt */
-
-      flags = enter_critical_section();
-
-      /* Fake a TX interrupt here by just calling uart_xmitchars() with
-       * interrupts disabled (note this may recurse).
-       */
-
       uart_xmitchars(dev);
-      leave_critical_section(flags);
-#endif
-    }
-  else
-    {
-      /* Disable the TX interrupt */
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf53_txready
  *
  * Description:
- *   Return true if the tranmsit data register is empty
+ *   Report whether the transmitter can accept another character. The
+ *   events are read, the upper half also polls with interrupts disabled.
+ *   A transfer ended without STOPTX can be restarted.
  *
  ****************************************************************************/
 
 static bool nrf53_txready(struct uart_dev_s *dev)
 {
-  /* struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv; */
+  struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv;
 
-  /* Return true if the transmit FIFO is "not full." */
+  if (priv->txbusy)
+    {
+      return nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_ENDTX_OFFSET) ||
+             nrf53_uart_getreg(priv, NRF53_UARTE_EVENTS_TXSTOPPED_OFFSET);
+    }
 
   return true;
 }
@@ -715,11 +933,7 @@ static bool nrf53_txready(struct uart_dev_s *dev)
 
 static bool nrf53_txempty(struct uart_dev_s *dev)
 {
-  /* struct nrf53_dev_s *priv = (struct nrf53_dev_s *)dev->priv; */
-
-  /* Return true if the transmit FIFO is "empty." */
-
-  return true;
+  return nrf53_txready(dev);
 }
 
 /****************************************************************************
@@ -817,9 +1031,14 @@ void arm_serialinit(void)
 void up_putc(int ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  /* struct nrf53_dev_s *priv = (struct nrf53_dev_s *)CONSOLE_DEV.priv; */
+  struct nrf53_dev_s *priv = CONSOLE_DEV.priv;
+  irqstate_t flags = enter_critical_section();
+
+  /* Serialize polled debug output with the interrupt-driven transmitter */
 
+  nrf53_txstop(priv);
   arm_lowputc(ch);
+  leave_critical_section(flags);
 #endif
 }
 
diff --git a/arch/arm/src/nrf91/hardware/nrf91_uarte.h 
b/arch/arm/src/nrf91/hardware/nrf91_uarte.h
index 5a1e79e091b..4246d6dbf05 100644
--- a/arch/arm/src/nrf91/hardware/nrf91_uarte.h
+++ b/arch/arm/src/nrf91/hardware/nrf91_uarte.h
@@ -262,6 +262,8 @@
 
 #define NRF91_UART_ENABLE_DISABLE           (0)
 #define NRF91_UART_ENABLE_ENABLE            (8)
+#define NRF91_UARTE_ENABLE_DISABLE          (0)
+#define NRF91_UARTE_ENABLE_ENABLE           (8)
 
 /* INTEN/INTENSET/INTENCLR Register */
 
diff --git a/arch/arm/src/nrf91/nrf91_lowputc.c 
b/arch/arm/src/nrf91/nrf91_lowputc.c
index f73b19823ad..70aa0a7b9e4 100644
--- a/arch/arm/src/nrf91/nrf91_lowputc.c
+++ b/arch/arm/src/nrf91/nrf91_lowputc.c
@@ -79,6 +79,10 @@ static const struct uart_config_s g_console_config =
   .txpin     = CONSOLE_TX_PIN,
   .rxpin     = CONSOLE_RX_PIN,
 };
+
+/* Console byte transmitted by EasyDMA */
+
+static uint8_t g_console_tx;
 #endif /* HAVE_UART_CONSOLE */
 
 /****************************************************************************
@@ -219,7 +223,7 @@ static void nrf91_setbaud(uintptr_t base, const struct 
uart_config_s *config)
         }
     }
 
-  putreg32(br, base + NRF91_UART_BAUDRATE_OFFSET);
+  putreg32(br, base + NRF91_UARTE_BAUDRATE_OFFSET);
 }
 
 /****************************************************************************
@@ -231,7 +235,7 @@ static void nrf91_setparity(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF91_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF91_UARTE_CONFIG_OFFSET);
 
   if (config->parity == 2)
     {
@@ -246,7 +250,7 @@ static void nrf91_setparity(uintptr_t base,
       regval &= ~UART_CONFIG_PARITY;
     }
 
-  putreg32(regval, base + NRF91_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF91_UARTE_CONFIG_OFFSET);
 }
 
 /****************************************************************************
@@ -259,7 +263,7 @@ static void nrf91_setstops(uintptr_t base,
 {
   uint32_t regval = 0;
 
-  regval = getreg32(base + NRF91_UART_CONFIG_OFFSET);
+  regval = getreg32(base + NRF91_UARTE_CONFIG_OFFSET);
 
   if (config->stopbits2 == true)
     {
@@ -270,7 +274,7 @@ static void nrf91_setstops(uintptr_t base,
       regval &= ~UART_CONFIG_STOP;
     }
 
-  putreg32(regval, base + NRF91_UART_CONFIG_OFFSET);
+  putreg32(regval, base + NRF91_UARTE_CONFIG_OFFSET);
 }
 #endif
 
@@ -328,9 +332,10 @@ void nrf91_usart_configure(uintptr_t base,
   uint32_t port   = 0;
   uint32_t regval = 0;
 
-  putreg32(1, base + NRF91_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF91_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF91_UART_ENABLE_DISABLE, base + NRF91_UART_ENABLE_OFFSET);
+  putreg32(0xffffffff, base + NRF91_UARTE_INTENCLR_OFFSET);
+  putreg32(1, base + NRF91_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF91_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF91_UARTE_ENABLE_DISABLE, base + NRF91_UARTE_ENABLE_OFFSET);
 
   /* Set UART format */
 
@@ -348,7 +353,7 @@ void nrf91_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELTXD_PIN_SHIFT);
   regval |= (port << UART_PSELTXD_PORT_SHIFT);
-  putreg32(regval, base + NRF91_UART_PSELTXD_OFFSET);
+  putreg32(regval, base + NRF91_UARTE_PSEL_TXD_OFFSET);
 
   /* Setect RX pins for UART */
 
@@ -357,11 +362,14 @@ void nrf91_usart_configure(uintptr_t base,
 
   regval = (pin << UART_PSELRXD_PIN_SHIFT);
   regval |= (port << UART_PSELRXD_PORT_SHIFT);
-  putreg32(regval, base + NRF91_UART_PSELRXD_OFFSET);
+  putreg32(regval, base + NRF91_UARTE_PSEL_RXD_OFFSET);
+  putreg32(UART_PSELCTS_RESET, base + NRF91_UARTE_PSEL_CTS_OFFSET);
+  putreg32(UART_PSELRTS_RESET, base + NRF91_UARTE_PSEL_RTS_OFFSET);
+  putreg32(0, base + NRF91_UARTE_SHORTS_OFFSET);
 
   /* Enable UART */
 
-  putreg32(NRF91_UART_ENABLE_ENABLE, base + NRF91_UART_ENABLE_OFFSET);
+  putreg32(NRF91_UARTE_ENABLE_ENABLE, base + NRF91_UARTE_ENABLE_OFFSET);
 }
 
 /****************************************************************************
@@ -379,12 +387,12 @@ void nrf91_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Disable the UART */
 
-  putreg32(1, base + NRF91_UART_TASKS_STOPRX_OFFSET);
-  putreg32(1, base + NRF91_UART_TASKS_STOPTX_OFFSET);
-  putreg32(NRF91_UART_ENABLE_DISABLE, base + NRF91_UART_ENABLE_OFFSET);
+  putreg32(1, base + NRF91_UARTE_TASKS_STOPRX_OFFSET);
+  putreg32(1, base + NRF91_UARTE_TASKS_STOPTX_OFFSET);
+  putreg32(NRF91_UARTE_ENABLE_DISABLE, base + NRF91_UARTE_ENABLE_OFFSET);
 
-  putreg32(0xffffffff, base + NRF91_UART_PSELTXD_OFFSET);
-  putreg32(0xffffffff, base + NRF91_UART_PSELRXD_OFFSET);
+  putreg32(0xffffffff, base + NRF91_UARTE_PSEL_TXD_OFFSET);
+  putreg32(0xffffffff, base + NRF91_UARTE_PSEL_RXD_OFFSET);
 
   /* Unconfigure GPIO */
 
@@ -393,8 +401,8 @@ void nrf91_usart_disable(uintptr_t base, const struct 
uart_config_s *config)
 
   /* Deatach TWI from GPIO */
 
-  putreg32(UART_PSELTXD_RESET, base + NRF91_UART_PSELTXD_OFFSET);
-  putreg32(UART_PSELRXD_RESET, base + NRF91_UART_PSELRXD_OFFSET);
+  putreg32(UART_PSELTXD_RESET, base + NRF91_UARTE_PSEL_TXD_OFFSET);
+  putreg32(UART_PSELRXD_RESET, base + NRF91_UARTE_PSEL_RXD_OFFSET);
 }
 
 /****************************************************************************
@@ -439,13 +447,24 @@ void nrf91_usart_setformat(uintptr_t base,
 void arm_lowputc(char ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  putreg32(1, CONSOLE_BASE + NRF91_UART_TASKS_STARTTX_OFFSET);
-  putreg32(0, CONSOLE_BASE + NRF91_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(ch, CONSOLE_BASE + NRF91_UART_TXD_OFFSET);
-  while (getreg32(CONSOLE_BASE + NRF91_UART_EVENTS_TXDRDY_OFFSET) == 0)
+  g_console_tx = ch;
+
+  putreg32(0, CONSOLE_BASE + NRF91_UARTE_EVENTS_ENDTX_OFFSET);
+  putreg32(0, CONSOLE_BASE + NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  putreg32((uintptr_t)&g_console_tx,
+           CONSOLE_BASE + NRF91_UARTE_TXD_PTR_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF91_UARTE_TXD_MAXCNT_OFFSET);
+
+  UP_DMB();
+
+  putreg32(1, CONSOLE_BASE + NRF91_UARTE_TASKS_STARTTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF91_UARTE_EVENTS_ENDTX_OFFSET) == 0)
     {
     }
 
-  putreg32(1, CONSOLE_BASE + NRF91_UART_TASKS_STOPTX_OFFSET);
+  putreg32(1, CONSOLE_BASE + NRF91_UARTE_TASKS_STOPTX_OFFSET);
+  while (getreg32(CONSOLE_BASE + NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET) == 0)
+    {
+    }
 #endif
 }
diff --git a/arch/arm/src/nrf91/nrf91_serial.c 
b/arch/arm/src/nrf91/nrf91_serial.c
index 13fb2beba10..f99891f3309 100644
--- a/arch/arm/src/nrf91/nrf91_serial.c
+++ b/arch/arm/src/nrf91/nrf91_serial.c
@@ -93,6 +93,9 @@
 #  define TTYS0_DEV           g_uart1port /* UART1 is ttyS0 */
 #endif
 
+#define RX_INTERRUPTS (UART_INT_ENDRX | UART_INT_ERROR | UART_INT_RXTO)
+#define TX_INTERRUPTS (UART_INT_ENDTX | UART_INT_TXSTOPPED)
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -101,9 +104,17 @@
 
 struct nrf91_dev_s
 {
-  uintptr_t uartbase;     /* Base address of UART registers */
-  uint8_t   irq;          /* IRQ associated with this UART */
-  bool      rx_available; /* rx byte available */
+  uintptr_t     uartbase;       /* Base address of UART registers */
+  uint8_t       irq;            /* IRQ associated with this UART */
+  uint8_t       rxdma;          /* Receive DMA buffer */
+  uint8_t       txdma;          /* Transmit DMA buffer */
+  uint8_t       rxchar;         /* Completed receive byte */
+  uint32_t      rxstatus;       /* Receive error status */
+  bool          rxvalid;        /* Receive byte available */
+  bool          rxenabled;      /* Upper-half reception enabled */
+  bool          rxactive;       /* Receiver started */
+  bool          txenabled;      /* Upper-half transmission enabled */
+  volatile bool txbusy;         /* DMA transmitter owns txdma */
 
   /* UART configuration */
 
@@ -169,7 +180,6 @@ static struct nrf91_dev_s g_uart0priv =
 {
   .uartbase       = NRF91_UART0_BASE,
   .irq            = NRF91_IRQ_SERIAL0,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART0_BAUD,
@@ -211,7 +221,6 @@ static struct nrf91_dev_s g_uart1priv =
 {
   .uartbase       = NRF91_UART1_BASE,
   .irq            = NRF91_IRQ_SERIAL1,
-  .rx_available   = false,
   .config         =
   {
     .baud         = CONFIG_UART1_BAUD,
@@ -262,6 +271,192 @@ static struct uart_dev_s * const g_uart_devs[NRF91_NUART] 
=
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: nrf91_uart_putreg
+ *
+ * Description:
+ *   Write a UART register.
+ *
+ ****************************************************************************/
+
+static inline void nrf91_uart_putreg(struct nrf91_dev_s *priv,
+                                     uint32_t offset, uint32_t value)
+{
+  putreg32(value, priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf91_uart_getreg
+ *
+ * Description:
+ *   Read a UART register.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf91_uart_getreg(struct nrf91_dev_s *priv,
+                                         uint32_t offset)
+{
+  return getreg32(priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: nrf91_uart_clrevent
+ *
+ * Description:
+ *   Clear a UARTE event and read it back before returning.
+ *
+ ****************************************************************************/
+
+static void nrf91_uart_clrevent(struct nrf91_dev_s *priv, uint32_t event)
+{
+  nrf91_uart_putreg(priv, event, 0);
+  (void)nrf91_uart_getreg(priv, event);
+}
+
+/****************************************************************************
+ * Name: nrf91_rxstart
+ *
+ * Description:
+ *   Start reception and queue the first one-byte DMA buffer.
+ *
+ ****************************************************************************/
+
+static void nrf91_rxstart(struct nrf91_dev_s *priv)
+{
+  priv->rxactive = true;
+  priv->rxvalid = false;
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ENDRX_OFFSET);
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_RXTO_OFFSET);
+  nrf91_uart_putreg(priv, NRF91_UARTE_RXD_PTR_OFFSET,
+                    (uintptr_t)&priv->rxdma);
+  nrf91_uart_putreg(priv, NRF91_UARTE_RXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STARTRX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf91_rxdeliver
+ *
+ * Description:
+ *   Deliver the completed byte and restart the one-byte DMA. A byte
+ *   received with the delivery disabled is kept, the UART FIFO holds the
+ *   next bytes until rxint() enables the delivery.
+ *
+ ****************************************************************************/
+
+static void nrf91_rxdeliver(struct uart_dev_s *dev)
+{
+  struct nrf91_dev_s *priv = dev->priv;
+
+  if (priv->rxvalid && priv->rxenabled)
+    {
+      uart_recvchars(dev);
+      if (!priv->rxvalid)
+        {
+          UP_DMB();
+          nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STARTRX_OFFSET, 1);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: nrf91_rxstop
+ *
+ * Description:
+ *   Stop reception and deliver a completed byte. Interrupts must be
+ *   disabled.
+ *
+ ****************************************************************************/
+
+static void nrf91_rxstop(struct uart_dev_s *dev)
+{
+  struct nrf91_dev_s *priv = dev->priv;
+
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_RXTO_OFFSET);
+  nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STOPRX_OFFSET, 1);
+  while (!nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_RXTO_OFFSET))
+    {
+    }
+
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf91_uart_getreg(priv, NRF91_UARTE_ERRORSRC_OFFSET);
+      nrf91_uart_putreg(priv, NRF91_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
+
+  /* STOP also generates ENDRX for an empty buffer. Deliver a completed
+   * byte, but never deliver an empty buffer.
+   */
+
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_RXD_AMOUNT_OFFSET) != 0)
+    {
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
+      if (priv->rxenabled)
+        {
+          uart_recvchars(dev);
+        }
+
+      priv->rxvalid = false;
+    }
+
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ENDRX_OFFSET);
+}
+
+/****************************************************************************
+ * Name: nrf91_txstart
+ *
+ * Description:
+ *   Start a one-byte DMA transfer. The caller must serialize access.
+ *
+ ****************************************************************************/
+
+static void nrf91_txstart(struct nrf91_dev_s *priv, int ch)
+{
+  priv->txdma = ch;
+  priv->txbusy = true;
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ENDTX_OFFSET);
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET);
+  nrf91_uart_putreg(priv, NRF91_UARTE_TXD_PTR_OFFSET,
+                    (uintptr_t)&priv->txdma);
+  nrf91_uart_putreg(priv, NRF91_UARTE_TXD_MAXCNT_OFFSET, 1);
+  UP_DMB();
+  nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STARTTX_OFFSET, 1);
+}
+
+/****************************************************************************
+ * Name: nrf91_txstop
+ *
+ * Description:
+ *   Wait for the transmitter to stop. Interrupts must be disabled.
+ *
+ ****************************************************************************/
+
+static void nrf91_txstop(struct nrf91_dev_s *priv)
+{
+  if (priv->txbusy)
+    {
+      while (!nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ENDTX_OFFSET) &&
+             !nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+        }
+
+      if (!nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET))
+        {
+          nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STOPTX_OFFSET, 1);
+          while (!nrf91_uart_getreg(priv,
+                                    NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET))
+            {
+            }
+        }
+
+      priv->txbusy = false;
+    }
+}
+
 /****************************************************************************
  * Name: nrf91_setup
  *
@@ -318,15 +513,10 @@ static void nrf91_shutdown(struct uart_dev_s *dev)
  * Name: nrf91_attach
  *
  * Description:
- *   Configure the UART to operation in interrupt driven mode.  This method
- *   is called when the serial port is opened.  Normally, this is just after
- *   the setup() method is called, however, the serial console may
- *   operate in a non-interrupt driven mode during the boot phase.
- *
- *   RX and TX interrupts are not enabled when by the attach method (unless
- *   the hardware supports multiple levels of interrupt enabling).
- *   The RX and TX interrupts are not enabled until the txint() and rxint()
- *   methods are called.
+ *   Configure the UART to operate in interrupt driven mode. This method
+ *   is called when the serial port is opened, normally just after setup.
+ *   DMA completion interrupts release buffers even when delivery to the
+ *   upper half is disabled by the rxint() and txint() methods.
  *
  ****************************************************************************/
 
@@ -335,14 +525,17 @@ static int nrf91_attach(struct uart_dev_s *dev)
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
   int ret;
 
-  /* Attach and enable the IRQ(s).  The interrupts are (probably) still
-   * disabled in the C2 register.
-   */
+  /* Attach and enable the IRQ */
 
   ret = irq_attach(priv->irq, nrf91_interrupt, dev);
   if (ret == OK)
     {
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+      nrf91_uart_putreg(priv, NRF91_UARTE_INTENSET_OFFSET,
+                        RX_INTERRUPTS | TX_INTERRUPTS);
       up_enable_irq(priv->irq);
+      nrf91_rxstart(priv);
+#endif
     }
 
   return ret;
@@ -352,7 +545,7 @@ static int nrf91_attach(struct uart_dev_s *dev)
  * Name: nrf91_detach
  *
  * Description:
- *   Detach UART interrupts.  This method is called when the serial port is
+ *   Detach UART interrupts. This method is called when the serial port is
  *   closed normally just before the shutdown method is called.
  *   The exception is the serial console which is never shutdown.
  *
@@ -361,14 +554,23 @@ static int nrf91_attach(struct uart_dev_s *dev)
 static void nrf91_detach(struct uart_dev_s *dev)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
+  irqstate_t flags;
 
-  /* Disable interrupts */
+  /* Stop DMA before detaching the interrupt handler */
 
-  putreg32(UART_INT_RXDRDY, priv->uartbase + NRF91_UART_INTENCLR_OFFSET);
-  up_disable_irq(priv->irq);
+  flags = enter_critical_section();
+  nrf91_uart_putreg(priv, NRF91_UARTE_INTENCLR_OFFSET, UINT32_MAX);
+
+  if (priv->rxactive)
+    {
+      nrf91_rxstop(dev);
+      priv->rxactive = false;
+    }
 
-  /* Detach from the interrupt(s) */
+  nrf91_txstop(priv);
+  leave_critical_section(flags);
 
+  up_disable_irq(priv->irq);
   irq_detach(priv->irq);
 }
 
@@ -376,37 +578,56 @@ static void nrf91_detach(struct uart_dev_s *dev)
  * Name: nrf91_interrupt
  *
  * Description:
- *   This is the UART interrupt handler.  It will be invoked when an
- *   interrupt is received on the 'irq'.  It should call uart_xmitchars or
- *   uart_recvchars to perform the appropriate data transfers.  The
- *   interrupt handling logic must be able to map the 'arg' to the
- *   appropriate uart_dev_s structure in order to call these functions.
+ *   Handle receive buffers and transfer completion.
  *
  ****************************************************************************/
 
 static int nrf91_interrupt(int irq, void *context, void *arg)
 {
-  struct uart_dev_s *dev = (struct uart_dev_s *)arg;
-  struct nrf91_dev_s *priv;
-  uint32_t regval;
-
-  DEBUGASSERT(dev != NULL && dev->priv != NULL);
-  priv = (struct nrf91_dev_s *)dev->priv;
+  struct uart_dev_s *dev = arg;
+  struct nrf91_dev_s *priv = dev->priv;
 
-  /* Check RX event */
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ERROR_OFFSET))
+    {
+      nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ERROR_OFFSET);
+      priv->rxstatus |=
+        nrf91_uart_getreg(priv, NRF91_UARTE_ERRORSRC_OFFSET);
+      nrf91_uart_putreg(priv, NRF91_UARTE_ERRORSRC_OFFSET, priv->rxstatus);
+    }
 
-  regval = getreg32(priv->uartbase + NRF91_UART_EVENTS_RXDRDY_OFFSET);
+  /* Copy the completed byte before restarting DMA. Automatic ENDRX-to-
+   * STARTRX would let DMA overwrite a buffer before the upper half
+   * consumes it. The UART FIFO holds incoming bytes between transfers.
+   */
 
-  if (regval != 0)
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ENDRX_OFFSET))
     {
-      putreg32(0, priv->uartbase + NRF91_UART_EVENTS_RXDRDY_OFFSET);
-      priv->rx_available = true;
-      uart_recvchars(dev);
+      nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ENDRX_OFFSET);
+      UP_DMB();
+      priv->rxchar = priv->rxdma;
+      priv->rxvalid = true;
     }
 
-  /* Clear errors */
+  nrf91_rxdeliver(dev);
+  nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_RXTO_OFFSET);
 
-  putreg32(0, priv->uartbase + NRF91_UART_ERRORSRC_OFFSET);
+  /* There is no ENDTX-to-STOPTX shortcut */
+
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ENDTX_OFFSET))
+    {
+      nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_ENDTX_OFFSET);
+      nrf91_uart_putreg(priv, NRF91_UARTE_TASKS_STOPTX_OFFSET, 1);
+    }
+
+  if (nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET))
+    {
+      nrf91_uart_clrevent(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET);
+      priv->txbusy = false;
+      if (priv->txenabled)
+        {
+          uart_xmitchars(dev);
+        }
+    }
 
   return OK;
 }
@@ -415,7 +636,7 @@ static int nrf91_interrupt(int irq, void *context, void 
*arg)
  * Name: nrf91_set_format
  *
  * Description:
- *   Set the serial line format and speed.
+ *   Set the serial line format and speed with DMA stopped.
  *
  ****************************************************************************/
 
@@ -423,8 +644,29 @@ static int nrf91_interrupt(int irq, void *context, void 
*arg)
 void nrf91_set_format(struct uart_dev_s *dev)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (priv->rxactive)
+    {
+      nrf91_rxstop(dev);
+    }
+
+  nrf91_txstop(priv);
 
+  nrf91_uart_putreg(priv, NRF91_UARTE_ENABLE_OFFSET,
+                    NRF91_UARTE_ENABLE_DISABLE);
   nrf91_usart_setformat(priv->uartbase, &priv->config);
+  nrf91_uart_putreg(priv, NRF91_UARTE_ENABLE_OFFSET,
+                    NRF91_UARTE_ENABLE_ENABLE);
+
+  if (priv->rxactive)
+    {
+      nrf91_rxstart(priv);
+    }
+
+  leave_critical_section(flags);
 }
 #endif
 
@@ -563,61 +805,48 @@ static int nrf91_ioctl(struct file *filep, int cmd, 
unsigned long arg)
 static int nrf91_receive(struct uart_dev_s *dev, unsigned int *status)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
-  uint32_t data;
-
-  /* Get input data along with receiver control information */
-
-  data = getreg32(priv->uartbase + NRF91_UART_RXD_OFFSET);
-  priv->rx_available = false;
-
-  /* Return receiver control information */
 
   if (status)
     {
-      *status = 0x00;
+      *status = priv->rxstatus;
     }
 
-  /* Then return the actual received data. */
-
-  return data;
+  priv->rxstatus = 0;
+  priv->rxvalid = false;
+  return priv->rxchar;
 }
 
 /****************************************************************************
  * Name: nrf91_rxint
  *
  * Description:
- *   Call to enable or disable RX interrupts
+ *   Enable or disable delivery of received characters to the upper half.
  *
  ****************************************************************************/
 
 static void nrf91_rxint(struct uart_dev_s *dev, bool enable)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  if (enable)
-    {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      /* Receive an interrupt when their is anything in the Rx data register
-       * (or an Rx timeout occurs).
-       */
-
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF91_UART_INTENSET_OFFSET);
-      putreg32(1, priv->uartbase + NRF91_UART_TASKS_STARTRX_OFFSET);
-
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
 #endif
-    }
-  else
+
+  priv->rxenabled = enable;
+  if (enable)
     {
-      putreg32(UART_INT_RXDRDY, priv->uartbase + NRF91_UART_INTENCLR_OFFSET);
-      putreg32(1, priv->uartbase + NRF91_UART_TASKS_STOPRX_OFFSET);
+      nrf91_rxdeliver(dev);
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf91_rxavailable
  *
  * Description:
- *   Return true if the receive register is not empty
+ *   Report whether a received character is waiting for the upper half.
  *
  ****************************************************************************/
 
@@ -625,82 +854,71 @@ static bool nrf91_rxavailable(struct uart_dev_s *dev)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
 
-  /* Return true if the receive buffer/fifo is not "empty." */
-
-  return priv->rx_available;
+  return priv->rxvalid;
 }
 
 /****************************************************************************
  * Name: nrf91_send
  *
  * Description:
- *   This method will send one byte on the UART.
+ *   Start transmitting the character supplied by the upper half.
  *
  ****************************************************************************/
 
 static void nrf91_send(struct uart_dev_s *dev, int ch)
 {
   struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
-  putreg32(0, priv->uartbase + NRF91_UART_EVENTS_TXDRDY_OFFSET);
-  putreg32(1, priv->uartbase + NRF91_UART_TASKS_STARTTX_OFFSET);
-
-  putreg32(ch, priv->uartbase + NRF91_UART_TXD_OFFSET);
-  while (getreg32(priv->uartbase + NRF91_UART_EVENTS_TXDRDY_OFFSET) == 0)
-    {
-    }
-
-  putreg32(1, priv->uartbase + NRF91_UART_TASKS_STOPTX_OFFSET);
+  nrf91_txstart(priv, ch);
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf91_txint
  *
  * Description:
- *   Call to enable or disable TX interrupts
+ *   Enable or disable transmission from the upper-half transmit buffer.
  *
  ****************************************************************************/
 
 static void nrf91_txint(struct uart_dev_s *dev, bool enable)
 {
-  /* struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv; */
+  struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
+  irqstate_t flags = enter_critical_section();
 
+#ifdef CONFIG_SUPPRESS_SERIAL_INTS
+  enable = false;
+#endif
+
+  priv->txenabled = enable;
   if (enable)
     {
-#ifndef CONFIG_SUPPRESS_SERIAL_INTS
-      irqstate_t flags;
-
-      /* Enable the TX interrupt */
-
-      flags = enter_critical_section();
-
-      /* Fake a TX interrupt here by just calling uart_xmitchars() with
-       * interrupts disabled (note this may recurse).
-       */
-
       uart_xmitchars(dev);
-      leave_critical_section(flags);
-#endif
-    }
-  else
-    {
-      /* Disable the TX interrupt */
     }
+
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
  * Name: nrf91_txready
  *
  * Description:
- *   Return true if the tranmsit data register is empty
+ *   Report whether the transmitter can accept another character. The
+ *   events are read, the upper half also polls with interrupts disabled.
+ *   A transfer ended without STOPTX can be restarted.
  *
  ****************************************************************************/
 
 static bool nrf91_txready(struct uart_dev_s *dev)
 {
-  /* struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv; */
+  struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv;
 
-  /* Return true if the transmit FIFO is "not full." */
+  if (priv->txbusy)
+    {
+      return nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_ENDTX_OFFSET) ||
+             nrf91_uart_getreg(priv, NRF91_UARTE_EVENTS_TXSTOPPED_OFFSET);
+    }
 
   return true;
 }
@@ -715,11 +933,7 @@ static bool nrf91_txready(struct uart_dev_s *dev)
 
 static bool nrf91_txempty(struct uart_dev_s *dev)
 {
-  /* struct nrf91_dev_s *priv = (struct nrf91_dev_s *)dev->priv; */
-
-  /* Return true if the transmit FIFO is "empty." */
-
-  return true;
+  return nrf91_txready(dev);
 }
 
 /****************************************************************************
@@ -817,9 +1031,14 @@ void arm_serialinit(void)
 void up_putc(int ch)
 {
 #ifdef HAVE_UART_CONSOLE
-  /* struct nrf91_dev_s *priv = (struct nrf91_dev_s *)CONSOLE_DEV.priv; */
+  struct nrf91_dev_s *priv = CONSOLE_DEV.priv;
+  irqstate_t flags = enter_critical_section();
+
+  /* Serialize polled debug output with the interrupt-driven transmitter */
 
+  nrf91_txstop(priv);
   arm_lowputc(ch);
+  leave_critical_section(flags);
 #endif
 }
 

Reply via email to