This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 4995c836f3 arch/arm/stm32h5: Add DMA Support to STM32H5 Serial Driver
4995c836f3 is described below

commit 4995c836f30fdfb338bef3a25680e2595b6ebc4e
Author: kywwilson11 <kwil...@2g-eng.com>
AuthorDate: Fri Jul 25 11:49:22 2025 -0500

    arch/arm/stm32h5: Add DMA Support to STM32H5 Serial Driver
    
    Style fixes.
---
 arch/arm/src/stm32h5/Kconfig                       | 105 ++++++
 .../arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h |   8 +-
 arch/arm/src/stm32h5/stm32_dma.c                   |  29 +-
 arch/arm/src/stm32h5/stm32_serial.c                | 375 +++++++++------------
 arch/arm/src/stm32h5/stm32_uart.h                  |   3 +-
 5 files changed, 301 insertions(+), 219 deletions(-)

diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig
index 5dee7bc065..5899576daf 100644
--- a/arch/arm/src/stm32h5/Kconfig
+++ b/arch/arm/src/stm32h5/Kconfig
@@ -4397,6 +4397,13 @@ config LPUART1_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on LPUART1. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config LPUART1_RXDMA
+       bool "LPUART1 RX DMA"
+       default n
+       depends on STM32H5_LPUART1 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # LPUART1_SERIALDRIVER
 
 choice
@@ -4431,6 +4438,13 @@ config USART1_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART1. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART1_RXDMA
+       bool "USART1 RX DMA"
+       default n
+       depends on STM32H5_USART1 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART1_SERIALDRIVER
 
 choice
@@ -4465,6 +4479,13 @@ config USART2_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART2. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART2_RXDMA
+       bool "USART2 RX DMA"
+       default n
+       depends on STM32H5_USART2 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART2_SERIALDRIVER
 
 choice
@@ -4499,6 +4520,13 @@ config USART3_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART3. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART3_RXDMA
+       bool "USART3 RX DMA"
+       default n
+       depends on STM32H5_USART3 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART3_SERIALDRIVER
 
 choice
@@ -4533,6 +4561,13 @@ config UART4_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART4. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART4_RXDMA
+       bool "UART4 RX DMA"
+       default n
+       depends on STM32H5_UART4 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART4_SERIALDRIVER
 
 choice
@@ -4567,6 +4602,13 @@ config UART5_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART5. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART5_RXDMA
+       bool "UART5 RX DMA"
+       default n
+       depends on STM32H5_UART5 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART5_SERIALDRIVER
 
 choice
@@ -4601,6 +4643,13 @@ config USART6_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART6. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART6_RXDMA
+       bool "USART6 RX DMA"
+       default n
+       depends on STM32H5_USART6 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART6_SERIALDRIVER
 
 if UART7_SERIALDRIVER
@@ -4623,6 +4672,13 @@ config UART7_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART7. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART7_RXDMA
+       bool "UART7 RX DMA"
+       default n
+       depends on STM32H5_UART7 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART7_SERIALDRIVER
 
 if UART8_SERIALDRIVER
@@ -4645,6 +4701,13 @@ config UART8_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART8. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART8_RXDMA
+       bool "UART8 RX DMA"
+       default n
+       depends on STM32H5_UART8 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART8_SERIALDRIVER
 
 if UART9_SERIALDRIVER
@@ -4667,6 +4730,13 @@ config UART9_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART9. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART9_RXDMA
+       bool "UART9 RX DMA"
+       default n
+       depends on STM32H5_UART9 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART9_SERIALDRIVER
 
 if USART10_SERIALDRIVER
@@ -4689,6 +4759,13 @@ config USART10_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART10. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART10_RXDMA
+       bool "USART10 RX DMA"
+       default n
+       depends on STM32H5_USART10 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART10_SERIALDRIVER
 
 if USART11_SERIALDRIVER
@@ -4711,6 +4788,13 @@ config USART11_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on USART11. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config USART11_RXDMA
+       bool "USART11 RX DMA"
+       default n
+       depends on STM32H5_USART11 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # USART11_SERIALDRIVER
 
 if UART12_SERIALDRIVER
@@ -4733,12 +4817,33 @@ config UART12_RS485_DIR_POLARITY
                Polarity of DIR pin for RS-485 on UART12. Set to state on DIR 
pin which
                enables TX (0 - low / nTXEN, 1 - high / TXEN).
 
+config UART12_RXDMA
+       bool "UART12 RX DMA"
+       default n
+       depends on STM32H5_UART12 && (STM32H5_DMA1 || STM32H5_DMA2)
+       ---help---
+               In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
 endif # UART12_SERIALDRIVER
 
 if STM32H5_SERIALDRIVER
 
 comment "Serial Driver Configuration"
 
+config STM32H5_SERIAL_RXDMA_BUFFER_SIZE
+       int "Rx DMA buffer size"
+       default 32
+       depends on USART1_RXDMA || USART2_RXDMA || USART3_RXDMA || USART6_RXDMA 
|| USART10_RXDMA || \
+                  USART11_RXDMA || UART4_RXDMA || UART5_RXDMA || UART7_RXDMA 
|| UART8_RXDMA || \
+                  UART9_RXDMA || UART12_RXDMA || LPUART1_RXDMA
+       ---help---
+               The DMA buffer size when using RX DMA to emulate a FIFO.
+
+               When streaming data, the generic serial layer will be called
+               every time the FIFO receives half this number of bytes.
+
+               Value given here will be rounded up to next multiple of 32 
bytes.
+
 config STM32H5_SERIAL_DISABLE_REORDERING
        bool "Disable reordering of ttySx devices."
        depends on STM32H5_USART1 || STM32H5_USART2 || STM32H5_USART3 || 
STM32H5_UART4 || STM32H5_UART5
diff --git a/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h 
b/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
index 9a65403226..3fc1c4fb9d 100644
--- a/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
+++ b/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
@@ -70,10 +70,10 @@
 #define GPDMA_REQ_UART8_TX          (36)
 #define GPDMA_REQ_UART9_RX          (37)
 #define GPDMA_REQ_UART9_TX          (38)
-#define GPDMA_REQ_UART10_RX         (39)
-#define GPDMA_REQ_UART10_TX         (40)
-#define GPDMA_REQ_UART11_RX         (41)
-#define GPDMA_REQ_UART11_TX         (42)
+#define GPDMA_REQ_USART10_RX        (39)
+#define GPDMA_REQ_USART10_TX        (40)
+#define GPDMA_REQ_USART11_RX        (41)
+#define GPDMA_REQ_USART11_TX        (42)
 #define GPDMA_REQ_UART12_RX         (43)
 #define GPDMA_REQ_UART12_TX         (44)
 #define GPDMA_REQ_LPUART1_RX        (45)
diff --git a/arch/arm/src/stm32h5/stm32_dma.c b/arch/arm/src/stm32h5/stm32_dma.c
index 2745c5b464..3d10262eb4 100644
--- a/arch/arm/src/stm32h5/stm32_dma.c
+++ b/arch/arm/src/stm32h5/stm32_dma.c
@@ -51,7 +51,7 @@
  * off this in this file.
  */
 
-#define CH_BASE_OFFSET(ch)  (0x80*(ch)) 
+#define CH_BASE_OFFSET(ch)  (0x80*(ch))
 #define CH_CXLBAR_OFFSET     0x50
 #define CH_CXFCR_OFFSET      0x5C
 #define CH_CXSR_OFFSET       0x60
@@ -694,6 +694,31 @@ void stm32_dmastop(DMA_HANDLE handle)
   /* gpdma_ch_abort(chan); */
 }
 
+/****************************************************************************
+ * Name: stm32_dmaresidual
+ *
+ * Description:
+ *   Returns the number of data beats remaining to transfer in the current
+ *   STM32H5 GPDMA block.  This reads the BNDT[15:0] field from the
+ *   GPDMA_CxBR1 register, which indicates how many beats are left in the
+ *   programmed transfer.
+ *
+ * Assumptions:
+ *   - DMA handle was allocated by stm32_dmachannel().
+ *   - The handle refers to a valid STM32H5 GPDMA channel.
+ *
+ ****************************************************************************/
+
+size_t stm32_dmaresidual(DMA_HANDLE handle)
+{
+  struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
+  uint32_t           br1  = getreg32(chan->base + CH_CXBR1_OFFSET);
+
+  /* BNDT[15:0] = beats remaining in current block transfer */
+
+  return (size_t)(br1 & GPDMA_CXBR1_BNDT_MASK);
+}
+
 #ifdef CONFIG_STM32H5_DMACAPABLE
 /****************************************************************************
  * Name: stm32_dmacapable
@@ -760,4 +785,4 @@ void stm32_dmasample(DMA_HANDLE handle, struct 
stm32_dmaregs_s *regs)
 {
   #warning "stm32_dmasample() not implemented yet!"
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/arch/arm/src/stm32h5/stm32_serial.c 
b/arch/arm/src/stm32h5/stm32_serial.c
index c27d9b7567..5e032cc6ad 100644
--- a/arch/arm/src/stm32h5/stm32_serial.c
+++ b/arch/arm/src/stm32h5/stm32_serial.c
@@ -52,13 +52,7 @@
 #include "chip.h"
 #include "stm32_gpio.h"
 #include "stm32_uart.h"
-
-/* DMA has not been implemented for H5 chip yet, so disable any serial DMA */
-
-#ifdef SERIAL_HAVE_DMA
-#  error Serial DMA not implemented for STM32H5 chips.
-#undef SERIAL_HAVE_DMA
-#endif
+#include "stm32_dma.h"
 
 #include "stm32_rcc.h"
 #include "arm_internal.h"
@@ -81,22 +75,18 @@
  *    5       X
  */
 
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+#  warning STM32H5 Serial IFLOWCONTROL is untested
+#endif
+
 #ifdef SERIAL_HAVE_DMA
 
 /* Verify that DMA has been enabled and the DMA channel has been defined.
  */
 
-#  if defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA)
-#    if !defined(CONFIG_STM32H5_DMA1) && !defined(CONFIG_STM32H5_DMAMUX)
-#      error STM32H5 USART2/3 receive DMA requires CONFIG_STM32H5_DMA1
-#    endif
-#  endif
-
-#  if defined(CONFIG_UART4_RXDMA) || defined(CONFIG_UART5_RXDMA)
-#    if !defined(CONFIG_STM32H5_DMA2) && !defined(CONFIG_STM32H5_DMAMUX)
-#      error STM32H5 UART4/5 receive DMA requires CONFIG_STM32H5_DMA2
-#    endif
-#  endif
+#if !defined(CONFIG_STM32H5_DMA1) && !defined(CONFIG_STM32H5_DMA2)
+#  error STM32H5 Serial DMA requires one of DMA1 or DMA2 to be enabled
+#endif
 
 /* Currently RS-485 support cannot be enabled when RXDMA is in use due to
  * lack of testing - RS-485 support was developed on STM32F1x
@@ -110,40 +100,6 @@
 #    error "RXDMA and RS-485 cannot be enabled at the same time for the same 
U[S]ART"
 #  endif
 
-/* For the L4, there are alternate DMA channels for USART1.
- * Logic in the board.h file make the DMA channel selection by defining
- * the following in the board.h file.
- */
-
-#  if defined(CONFIG_USART1_RXDMA) && !defined(DMAMAP_USART1_RX)
-#    error "USART1 DMA channel not defined (DMAMAP_USART1_RX)"
-#  endif
-
-/* UART2-5 have no alternate channels without DMAMUX */
-
-#  ifndef CONFIG_STM32H5_HAVE_DMAMUX
-#    define DMAMAP_USART2_RX  DMACHAN_USART2_RX
-#    define DMAMAP_USART3_RX  DMACHAN_USART3_RX
-#    define DMAMAP_UART4_RX   DMACHAN_UART4_RX
-#    define DMAMAP_UART5_RX   DMACHAN_UART5_RX
-#  endif
-
-#  if defined(CONFIG_USART2_RXDMA) && !defined(DMAMAP_USART2_RX)
-#    error "USART2 DMA channel not defined (DMAMAP_USART2_RX)"
-#  endif
-
-#  if defined(CONFIG_USART3_RXDMA) && !defined(DMAMAP_USART3_RX)
-#    error "USART3 DMA channel not defined (DMAMAP_USART3_RX)"
-#  endif
-
-#  if defined(CONFIG_UART4_RXDMA) && !defined(DMAMAP_UART4_RX)
-#    error "UART4 DMA channel not defined (DMAMAP_UART4_RX)"
-#  endif
-
-#  if defined(CONFIG_UART5_RXDMA) && !defined(DMAMAP_UART5_RX)
-#    error "UART5 DMA channel not defined (DMAMAP_UART5_RX)"
-#  endif
-
 /* The DMA buffer size when using RX DMA to emulate a FIFO.
  *
  * When streaming data, the generic serial layer will be called
@@ -161,31 +117,6 @@
 #    define RXDMA_BUFFER_SIZE ((CONFIG_STM32H5_SERIAL_RXDMA_BUFFER_SIZE + 31) 
& ~31)
 #  endif
 
-/* DMA priority */
-
-#  ifndef CONFIG_USART_DMAPRIO
-#    define CONFIG_USART_DMAPRIO  DMA_CCR_PRIMED
-#  endif
-#  if (CONFIG_USART_DMAPRIO & ~DMA_CCR_PL_MASK) != 0
-#    error "Illegal value for CONFIG_USART_DMAPRIO"
-#  endif
-
-/* DMA control words */
-
-#  define SERIAL_DMA_CONTROL_WORD      \
-              (DMA_CCR_CIRC          | \
-               DMA_CCR_MINC          | \
-               DMA_CCR_PSIZE_8BITS   | \
-               DMA_CCR_MSIZE_8BITS   | \
-               CONFIG_USART_DMAPRIO)
-#  ifdef CONFIG_SERIAL_IFLOWCONTROL
-#    define SERIAL_DMA_IFLOW_CONTROL_WORD \
-              (DMA_CCR_MINC          | \
-               DMA_CCR_PSIZE_8BITS   | \
-               DMA_CCR_MSIZE_8BITS   | \
-               CONFIG_USART_DMAPRIO)
-#  endif
-
 #endif
 
 /* Power management definitions */
@@ -243,9 +174,6 @@ struct stm32_serial_s
   uint8_t           parity;    /* 0=none, 1=odd, 2=even */
   uint8_t           bits;      /* Number of bits (7 or 8) */
   bool              stopbits2; /* True: Configure with 2 stop bits instead of 
1 */
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
-  bool              iflow;     /* input flow control (RTS) enabled */
-#endif
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
   bool              oflow;     /* output flow control (CTS) enabled */
 #endif
@@ -254,15 +182,11 @@ struct stm32_serial_s
   const uint8_t     parity;    /* 0=none, 1=odd, 2=even */
   const uint8_t     bits;      /* Number of bits (7 or 8) */
   const bool        stopbits2; /* True: Configure with 2 stop bits instead of 
1 */
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
-  const bool        iflow;     /* input flow control (RTS) enabled */
-#endif
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
   const bool        oflow;     /* output flow control (CTS) enabled */
 #endif
   const uint32_t    baud;      /* Configured baud */
 #endif
-
   const uint8_t     irq;       /* IRQ associated with this USART */
   const uint32_t    apbclock;  /* PCLK 1 or 2 frequency */
   const uint32_t    usartbase; /* Base address of USART registers */
@@ -274,10 +198,7 @@ struct stm32_serial_s
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
   const uint32_t    cts_gpio;  /* U[S]ART CTS GPIO pin configuration */
 #endif
-
-#ifdef SERIAL_HAVE_DMA
-  const unsigned int rxdma_channel; /* DMA channel assigned */
-#endif
+  const bool        iflow;     /* input flow control (RTS) enabled */
 
   /* RX DMA state */
 
@@ -288,7 +209,8 @@ struct stm32_serial_s
   bool              rxdmasusp; /* Rx DMA suspended */
 #endif
   uint32_t          rxdmanext; /* Next byte in the DMA buffer to be read */
-  char       *const rxfifo;    /* Receive DMA buffer */
+  uint16_t          rxdma_req; /* GPDMA Request number */
+  char          *const rxfifo; /* Receive DMA buffer */
 #endif
 
 #ifdef HAVE_RS485
@@ -543,8 +465,8 @@ static struct stm32_serial_s g_lpuart1priv =
   .rts_gpio      = GPIO_LPUART1_RTS,
 #  endif
 #  ifdef CONFIG_LPUART1_RXDMA
-  .rxdma_channel = DMAMAP_LPUSART_RX,
   .rxfifo        = g_lpuart1rxfifo,
+  .rxdma_req     = GPDMA_REQ_LPUART1_RX,
 #  endif
 
 #  ifdef CONFIG_USART1_RS485
@@ -604,8 +526,8 @@ static struct stm32_serial_s g_usart1priv =
   .rts_gpio      = GPIO_USART1_RTS,
 #  endif
 #  ifdef CONFIG_USART1_RXDMA
-  .rxdma_channel = DMAMAP_USART1_RX,
   .rxfifo        = g_usart1rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART1_RX,
 #  endif
 
 #  ifdef CONFIG_USART1_RS485
@@ -667,8 +589,8 @@ static struct stm32_serial_s g_usart2priv =
   .rts_gpio      = GPIO_USART2_RTS,
 #  endif
 #  ifdef CONFIG_USART2_RXDMA
-  .rxdma_channel = DMAMAP_USART2_RX,
   .rxfifo        = g_usart2rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART2_RX,
 #  endif
 
 #  ifdef CONFIG_USART2_RS485
@@ -730,8 +652,8 @@ static struct stm32_serial_s g_usart3priv =
   .rts_gpio      = GPIO_USART3_RTS,
 #  endif
 #  ifdef CONFIG_USART3_RXDMA
-  .rxdma_channel = DMAMAP_USART3_RX,
   .rxfifo        = g_usart3rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART3_RX,
 #  endif
 
 #  ifdef CONFIG_USART3_RS485
@@ -793,8 +715,8 @@ static struct stm32_serial_s g_uart4priv =
   .tx_gpio       = GPIO_UART4_TX,
   .rx_gpio       = GPIO_UART4_RX,
 #  ifdef CONFIG_UART4_RXDMA
-  .rxdma_channel = DMAMAP_UART4_RX,
   .rxfifo        = g_uart4rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART4_RX,
 #  endif
 
 #  ifdef CONFIG_UART4_RS485
@@ -856,8 +778,8 @@ static struct stm32_serial_s g_uart5priv =
   .tx_gpio        = GPIO_UART5_TX,
   .rx_gpio        = GPIO_UART5_RX,
 #  ifdef CONFIG_UART5_RXDMA
-  .rxdma_channel = DMAMAP_UART5_RX,
   .rxfifo        = g_uart5rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART5_RX,
 #  endif
 
 #  ifdef CONFIG_UART5_RS485
@@ -919,8 +841,8 @@ static struct stm32_serial_s g_usart6priv =
   .rts_gpio      = GPIO_USART6_RTS,
 #  endif
 #  ifdef CONFIG_USART6_RXDMA
-  .rxdma_channel = DMAMAP_USART6_RX,
   .rxfifo        = g_usart6rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART6_RX,
 #  endif
 
 #  ifdef CONFIG_USART6_RS485
@@ -982,8 +904,8 @@ static struct stm32_serial_s g_uart7priv =
   .tx_gpio        = GPIO_UART7_TX,
   .rx_gpio        = GPIO_UART7_RX,
 #  ifdef CONFIG_UART7_RXDMA
-  .rxdma_channel = DMAMAP_UART7_RX,
   .rxfifo        = g_uart7rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART7_RX,
 #  endif
 
 #  ifdef CONFIG_UART7_RS485
@@ -1045,8 +967,8 @@ static struct stm32_serial_s g_uart8priv =
   .tx_gpio        = GPIO_UART8_TX,
   .rx_gpio        = GPIO_UART8_RX,
 #  ifdef CONFIG_UART8_RXDMA
-  .rxdma_channel = DMAMAP_UART8_RX,
   .rxfifo        = g_uart8rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART8_RX,
 #  endif
 
 #  ifdef CONFIG_UART8_RS485
@@ -1108,8 +1030,8 @@ static struct stm32_serial_s g_uart9priv =
   .tx_gpio        = GPIO_UART9_TX,
   .rx_gpio        = GPIO_UART9_RX,
 #  ifdef CONFIG_UART9_RXDMA
-  .rxdma_channel = DMAMAP_UART9_RX,
   .rxfifo        = g_uart9rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART9_RX,
 #  endif
 
 #  ifdef CONFIG_UART9_RS485
@@ -1171,8 +1093,8 @@ static struct stm32_serial_s g_usart10priv =
   .rts_gpio      = GPIO_USART10_RTS,
 #  endif
 #  ifdef CONFIG_USART10_RXDMA
-  .rxdma_channel = DMAMAP_USART10_RX,
   .rxfifo        = g_usart10rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART10_RX,
 #  endif
 
 #  ifdef CONFIG_USART10_RS485
@@ -1234,8 +1156,8 @@ static struct stm32_serial_s g_usart11priv =
   .rts_gpio      = GPIO_USART11_RTS,
 #  endif
 #  ifdef CONFIG_USART11_RXDMA
-  .rxdma_channel = DMAMAP_USART11_RX,
   .rxfifo        = g_usart11rxfifo,
+  .rxdma_req     = GPDMA_REQ_USART11_RX,
 #  endif
 
 #  ifdef CONFIG_USART11_RS485
@@ -1297,8 +1219,8 @@ static struct stm32_serial_s g_uart12priv =
   .tx_gpio        = GPIO_UART12_TX,
   .rx_gpio        = GPIO_UART12_RX,
 #  ifdef CONFIG_UART12_RXDMA
-  .rxdma_channel = DMAMAP_UART12_RX,
   .rxfifo        = g_uart12rxfifo,
+  .rxdma_req     = GPDMA_REQ_UART12_RX,
 #  endif
 
 #  ifdef CONFIG_UART12_RS485
@@ -2166,69 +2088,88 @@ static int stm32serial_setup(struct uart_dev_s *dev)
   return OK;
 }
 
+/****************************************************************************
+ * Name: serial_rxdmacfg
+ *
+ * Description:
+ *   Generate the required DMA configuration structure for oneshot mode based
+ *   on the serial configuration.
+ *
+ * Input Parameters:
+ *   priv     - serial instance structure
+ *   cfg      - DMA configuration structure
+ *   circular - 0 = oneshot, 1 = circular
+ *
+ * Returned Value:
+ *   None
+ ****************************************************************************/
+
+ #ifdef SERIAL_HAVE_DMA
+static void serial_rxdmacfg(struct stm32_serial_s *priv,
+                            struct stm32_gpdma_cfg_s *cfg)
+{
+  cfg->src_addr   = priv->usartbase + STM32_USART_RDR_OFFSET;
+  cfg->dest_addr  = (uint32_t)priv->rxfifo;
+
+  cfg->request    = priv->rxdma_req;
+
+  cfg->priority   = GPMDACFG_PRIO_LH;
+
+  cfg->mode       = GPDMACFG_MODE_CIRC;
+
+  cfg->ntransfers = RXDMA_BUFFER_SIZE;
+
+  /* Write SDW and DDW to 0 for 8-bit beats */
+
+  cfg->tr1        = GPDMA_CXTR1_DINC;  /* dest-inc, source fixed */
+}
+#endif
+
 /****************************************************************************
  * Name: stm32serial_dmasetup
  *
  * Description:
- *   Configure the USART baud, bits, parity, etc. This method is called the
- *   first time that the serial port is opened.
+ *   Configure and start circular RX DMA for USART:
+ *     - Allocate a GPDMA channel
+ *     - Set up source (USART RDR), destination (RX buffer), REQSEL,
+ *       circular mode
+ *     - Program DMA and reset read index
+ *     - Enable USART CR3.DMAR
+ *     - Start DMA with half‑ and full‑transfer callbacks
  *
+ * Returned Value:
+ *   OK on success; negative errno on failure.
  ****************************************************************************/
 
 #ifdef SERIAL_HAVE_DMA
 static int stm32serial_dmasetup(struct uart_dev_s *dev)
 {
-  struct stm32_serial_s *priv =
-    (struct stm32_serial_s *)dev->priv;
-  int result;
-  uint32_t regval;
-
-  /* Do the basic UART setup first, unless we are the console */
+  struct stm32_serial_s   *priv = (struct stm32_serial_s *)dev->priv;
+  struct stm32_gpdma_cfg_s dmacfg;
+  uint32_t                 regval;
+  int                      ret;
 
   if (!dev->isconsole)
     {
-      result = stm32serial_setup(dev);
-      if (result != OK)
+      ret = stm32serial_setup(dev);
+      if (ret != OK)
         {
-          return result;
+          return ret;
         }
     }
 
-  /* Acquire the DMA channel.  This should always succeed. */
-
-  priv->rxdma = stm32h5_dmachannel(priv->rxdma_channel);
-
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
-  if (priv->iflow)
+  priv->rxdma = stm32_dmachannel(GPDMA_TTYPE_P2M);
+  if (!priv->rxdma)
     {
-      /* Configure for non-circular DMA reception into the RX FIFO */
-
-      stm32h5_dmasetup(priv->rxdma,
-                     priv->usartbase + STM32_USART_RDR_OFFSET,
-                     (uint32_t)priv->rxfifo,
-                     RXDMA_BUFFER_SIZE,
-                     SERIAL_DMA_IFLOW_CONTROL_WORD);
+      return -EBUSY;
     }
-  else
-#endif
-    {
-      /* Configure for circular DMA reception into the RX FIFO */
 
-      stm32h5_dmasetup(priv->rxdma,
-                     priv->usartbase + STM32_USART_RDR_OFFSET,
-                     (uint32_t)priv->rxfifo,
-                     RXDMA_BUFFER_SIZE,
-                     SERIAL_DMA_CONTROL_WORD);
-    }
+  serial_rxdmacfg(priv, &dmacfg);
 
-  /* Reset our DMA shadow pointer to match the address just
-   * programmed above.
-   */
+  stm32_dmasetup(priv->rxdma, &dmacfg);
 
   priv->rxdmanext = 0;
 
-  /* Enable receive DMA for the UART */
-
   regval  = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET);
   regval |= USART_CR3_DMAR;
   stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, regval);
@@ -2241,8 +2182,8 @@ static int stm32serial_dmasetup(struct uart_dev_s *dev)
        * in and DMA transfer is stopped.
        */
 
-      stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
-                       (void *)priv, false);
+      stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
+                      (void *)priv, false);
     }
   else
 #endif
@@ -2252,8 +2193,8 @@ static int stm32serial_dmasetup(struct uart_dev_s *dev)
        * worth of time to claim bytes before they are overwritten.
        */
 
-      stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
-                       (void *)priv, true);
+      stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
+                      (void *)priv, true);
     }
 
   return OK;
@@ -2347,11 +2288,13 @@ static void stm32serial_dmashutdown(struct uart_dev_s 
*dev)
 
   /* Stop the DMA channel */
 
-  stm32h5_dmastop(priv->rxdma);
+  stm32_dmastop(priv->rxdma);
+
+  priv->rxenable = false;
 
   /* Release the DMA channel */
 
-  stm32h5_dmafree(priv->rxdma);
+  stm32_dmafree(priv->rxdma);
   priv->rxdma = NULL;
 }
 #endif
@@ -3131,43 +3074,64 @@ static bool stm32serial_rxflowcontrol(struct uart_dev_s 
*dev,
  * Name: stm32serial_dmareceive
  *
  * Description:
- *   Called (usually) from the interrupt level to receive one
- *   character from the USART.  Error bits associated with the
- *   receipt are provided in the return 'status'.
+ *   Retrieve one character from the RX FIFO filled by circular DMA.  Also
+ *   report any USART error flags in *status.
  *
  ****************************************************************************/
 
 #ifdef SERIAL_HAVE_DMA
 static int stm32serial_dmareceive(struct uart_dev_s *dev,
-                                    unsigned int *status)
+                                     unsigned int *status)
 {
   struct stm32_serial_s *priv =
     (struct stm32_serial_s *)dev->priv;
-  int c = 0;
+  unsigned int next;
+  int          ch  = -1;
+  uint32_t     sr;
+
+  /* 1) Capture USART error flags */
 
-  if (stm32serial_dmanextrx(priv) != priv->rxdmanext)
+  sr      = getreg32(priv->usartbase + STM32_USART_ISR_OFFSET);
+  *status = sr & (USART_ISR_ORE | USART_ISR_NF |
+                  USART_ISR_FE  | USART_ISR_PE);
+
+  /* 2) Where will DMA write the next byte? */
+
+  next = stm32serial_dmanextrx(priv);
+
+  /* 3) Pull one byte if available */
+
+  if (next != priv->rxdmanext)
     {
-      c = priv->rxfifo[priv->rxdmanext];
+      ch = priv->rxfifo[priv->rxdmanext++];
 
-      priv->rxdmanext++;
-      if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
+      /* 4) End‑of‑buffer wrap or flow‑control pause */
+
+      if (priv->rxdmanext >= RXDMA_BUFFER_SIZE)
         {
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
           if (priv->iflow)
             {
-              /* RX DMA buffer full. RX paused, RTS line pulled up to prevent
-               * more input data from other end.
-               */
+              /* Pause DMA callbacks */
+
+              stm32serial_dmarxint(&priv->dev, false);
+
+              /* Assert RTS to halt sender */
+
+              (void)stm32serial_rxflowcontrol(&priv->dev,
+                                              RXDMA_BUFFER_SIZE, true);
             }
           else
 #endif
             {
+              /* Simply wrap to buffer start */
+
               priv->rxdmanext = 0;
             }
         }
     }
 
-  return c;
+  return ch;
 }
 #endif
 
@@ -3182,28 +3146,10 @@ static int stm32serial_dmareceive(struct uart_dev_s 
*dev,
 #if defined(SERIAL_HAVE_DMA)
 static void stm32serial_dmareenable(struct stm32_serial_s *priv)
 {
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
-  if (priv->iflow)
-    {
-      /* Configure for non-circular DMA reception into the RX FIFO */
+  struct stm32_gpdma_cfg_s dmacfg;
 
-      stm32h5_dmasetup(priv->rxdma,
-                       priv->usartbase + STM32_USART_RDR_OFFSET,
-                       (uint32_t)priv->rxfifo,
-                       RXDMA_BUFFER_SIZE,
-                       SERIAL_DMA_IFLOW_CONTROL_WORD);
-    }
-  else
-#endif
-    {
-      /* Configure for circular DMA reception into the RX FIFO */
-
-      stm32h5_dmasetup(priv->rxdma,
-                       priv->usartbase + STM32_USART_RDR_OFFSET,
-                       (uint32_t)priv->rxfifo,
-                       RXDMA_BUFFER_SIZE,
-                       SERIAL_DMA_CONTROL_WORD);
-    }
+  serial_rxdmacfg(priv, &dmacfg);
+  stm32_dmasetup(priv->rxdma, &dmacfg);
 
   /* Reset our DMA shadow pointer to match the address just
    * programmed above.
@@ -3219,7 +3165,7 @@ static void stm32serial_dmareenable(struct stm32_serial_s 
*priv)
        * in and DMA transfer is stopped.
        */
 
-      stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
+      stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
                       (void *)priv, false);
     }
   else
@@ -3230,7 +3176,7 @@ static void stm32serial_dmareenable(struct stm32_serial_s 
*priv)
        * worth of time to claim bytes before they are overwritten.
        */
 
-      stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
+      stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
                       (void *)priv, true);
     }
 
@@ -3461,50 +3407,57 @@ static bool stm32serial_txready(struct uart_dev_s *dev)
  * Name: stm32serial_dmarxcallback
  *
  * Description:
- *   This function checks the current DMA state and calls the generic
- *   serial stack when bytes appear to be available.
+ *   DMA callback for STM32H5 USART RX.  Called on half and full‐transfer
+ *   events.  Reads and clears the GPDMA status flags, notifies the NuttX
+ *   serial core of newly arrived bytes, signals end‐of‐buffer when a
+ *   full transfer completes, handles RTS flow control restart, and
+ *   clears any lingering UART error flags to keep RX‐DMA running.
+ *
+ * Input Parameters:
+ *   handle         - DMA channel handle returned by stm32_dmachannel()
+ *   status         - Raw status byte passed by the DMA ISR (ignored here)
+ *   arg            - Pointer to the STM32 serial driver state
+ *                    (struct stm32_serial_s)
+ *
+ * Returned Value:
+ *   None
  *
  ****************************************************************************/
 
-#ifdef SERIAL_HAVE_DMA
-static void stm32serial_dmarxcallback(DMA_HANDLE handle, uint8_t status,
-                                        void *arg)
+static void stm32serial_dmarxcallback(DMA_HANDLE handle,
+                                      uint8_t status,
+                                      void *arg)
 {
-  struct stm32_serial_s *priv = (struct stm32_serial_s *)arg;
+  struct stm32_serial_s *priv = arg;
 
-  if (priv->rxenable && stm32serial_dmarxavailable(&priv->dev))
-    {
-      uart_recvchars(&priv->dev);
+  /* pull whatever is in the buffer now */
+
+  uart_recvchars(&priv->dev);
+
+  /* If it really was a full‑buffer event, signal “done” so the
+   * serial core can rearm/restart the DMA behind the scenes:
+   */
 
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
-      if (priv->iflow)
-        {
-          /* Re-enable RX DMA. */
+  /* If you had paused the DMA on RTS flow control, restart it now */
 
-          stm32serial_dmaiflowrestart(priv);
-        }
-#endif
+  if (priv->iflow)
+    {
+      stm32serial_dmaiflowrestart(priv);
     }
+#endif
 
-  /* Get the masked USART status word to check and clear error flags.
-   *
-   * When wake-up from low power mode was not fast enough, UART is resumed
-   * too late and sometimes exactly when character was coming over UART,
-   * resulting to frame error.
-   * If error flag is not cleared, Rx DMA will be stuck. Clearing errors
-   * will release Rx DMA.
+  /* Clear any USART framing/overrun errors so RX‑DMA
+   * doesn’t get stuck waiting for the UART to clear them.
    */
 
-  priv->sr = stm32serial_getreg(priv, STM32_USART_ISR_OFFSET);
-
-  if ((priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE)) != 0)
+  priv->sr = getreg32(priv->usartbase + STM32_USART_ISR_OFFSET);
+  if (priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE))
     {
       stm32serial_putreg(priv, STM32_USART_ICR_OFFSET,
-                           (USART_ICR_NCF | USART_ICR_ORECF |
-                            USART_ICR_FECF));
+                        USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF);
     }
 }
-#endif
 
 /****************************************************************************
  * Name: stm32serial_pmnotify
diff --git a/arch/arm/src/stm32h5/stm32_uart.h 
b/arch/arm/src/stm32h5/stm32_uart.h
index 297d978e61..93914500e7 100644
--- a/arch/arm/src/stm32h5/stm32_uart.h
+++ b/arch/arm/src/stm32h5/stm32_uart.h
@@ -443,8 +443,7 @@
     defined(CONFIG_UART8_RXDMA)   || defined(CONFIG_UART9_RXDMA)  || \
     defined(CONFIG_USART10_RXDMA)  || defined(CONFIG_USART11_RXDMA) || \
     defined(CONFIG_USART12_RXDMA)
-#  define SERIAL_HAVE_DMA 0
-#  warning Serial DMA has not been implemented for STM32H5 chips.
+#  define SERIAL_HAVE_DMA 1
 #endif
 
 /* Is DMA used on the console UART? */

Reply via email to