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

acassis 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 0c1f9d482db Added DMA support for H5. Also added ADC DMA support.
0c1f9d482db is described below

commit 0c1f9d482dbb8a9d6247335d7484afaad24baec2
Author: kywwilson11 <kwil...@2g-eng.com>
AuthorDate: Tue Jul 8 15:55:05 2025 -0500

    Added DMA support for H5. Also added ADC DMA support.
    
    Added logic to set hasdma to false. This is needed to enable or not enable 
interrupts on a per ADC basis. Made other minor formatting changes.
    
    Fixed build issues with non ADC/DMA configurations.
---
 arch/arm/src/stm32h5/Kconfig                       | 123 ++--
 arch/arm/src/stm32h5/Make.defs                     |   4 +
 arch/arm/src/stm32h5/hardware/stm32_gpdma.h        |  10 +-
 .../arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h | 218 ++++++
 arch/arm/src/stm32h5/stm32_adc.c                   | 195 +++++-
 arch/arm/src/stm32h5/stm32_adc.h                   | 143 ++--
 arch/arm/src/stm32h5/stm32_dma.c                   | 763 +++++++++++++++++++++
 arch/arm/src/stm32h5/stm32_dma.h                   | 307 +++++++++
 arch/arm/src/stm32h5/stm32h5xx_rcc.c               |   4 +-
 9 files changed, 1589 insertions(+), 178 deletions(-)

diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig
index 0af61ae1b98..d480668e4f5 100644
--- a/arch/arm/src/stm32h5/Kconfig
+++ b/arch/arm/src/stm32h5/Kconfig
@@ -881,6 +881,75 @@ config ARCH_BOARD_STM32H5_CUSTOM_CLOCKCONFIG
        ---help---
                Enables special, board-specific STM32 clock configuration.
 
+menu "ADC Configuration"
+       depends on STM32H5_ADC
+
+config STM32H5_ADC_MAX_SAMPLES
+       int "The maximum number of channels that can be sampled"
+       default 16
+       ---help---
+               The maximum number of samples which can be handled without
+               overrun depends on various factors. This is the user's
+               responsibility to correctly select this value.
+               Since the interface to update the sampling time is available
+               for all supported devices, the user can change the default
+               values in the board initialization logic and avoid ADC overrun.
+
+config STM32H5_ADC1_DMA
+       bool "ADC1 DMA Enable"
+       depends on STM32H5_ADC1 && STM32H5_DMA
+       default n
+       ---help---
+               If DMA is selected, then the ADC may be configured to support 
DMA
+               transfer, which is necessary if multiple channels are read or if
+               very high trigger frequencies are used.
+
+config STM32H5_ADC1_DMA_BATCH
+       int "ADC1 DMA number of conversions"
+       depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
+       default 1
+       ---help---
+               This option allows you to select the number of regular group 
conversions
+               that will trigger a DMA callback transerring data to the 
upper-half driver.
+               By default, this value is 1, which means that data is 
transferred after
+               each group conversion.
+
+config STM32H5_ADC1_DMA_CFG
+       bool "ADC1 DMA configuration"
+       depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
+       default n
+       ---help---
+               0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode
+
+config STM32H5_ADC2_DMA
+       bool "ADC2 DMA Enable"
+       depends on STM32H5_ADC2 && STM32H5_DMA
+       default n
+       ---help---
+               If DMA is selected, then the ADC may be configured to support 
DMA
+               transfer, which is necessary if multiple channels are read or if
+               very high trigger frequencies are used.
+
+config STM32H5_ADC2_DMA_BATCH
+       int "ADC2 DMA number of conversions"
+       depends on STM32H5_ADC2 && STM32H5_ADC2_DMA
+       default 1
+       ---help---
+               This option allows you to select the number of regular group 
conversions
+               that will trigger a DMA callback transerring data to the 
upper-half driver.
+               By default, this value is 1, which means that data is 
transferred after
+               each group conversion.
+
+config STM32H5_ADC2_DMA_CFG
+       int "ADC2 DMA configuration"
+       depends on STM32H5_ADC2_DMA && STM32H5_DMA
+       range 0 1
+       default 0
+       ---help---
+               0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode
+
+endmenu # ADC Configuration
+
 menu "SPI Configuration"
        depends on STM32H5_SPI
 
@@ -4550,60 +4619,6 @@ endif # STM32H5_SERIALDRIVER
 
 endmenu # U[S]ART Configuration
 
-menu "ADC Configuration"
-       depends on STM32H5_ADC
-
-config STM32H5_ADC_MAX_SAMPLES
-       int "The maximum number of channels that can be sampled"
-       default 16
-       ---help---
-               The maximum number of samples which can be handled without
-               overrun depends on various factors. This is the user's
-               responsibility to correctly select this value.
-               Since the interface to update the sampling time is available
-               for all supported devices, the user can change the default
-               values in the board initialization logic and avoid ADC overrun.
-
-config STM32H5_ADC1_DMA
-       bool "ADC1 DMA (not supported yet)"
-       depends on STM32H5_ADC1 && EXPERIMENTAL
-       default n
-       ---help---
-               If DMA is selected, then the ADC may be configured to support
-               DMA transfer, which is necessary if multiple channels are read
-               or if very high trigger frequencies are used.
-
-config STM32H5_ADC1_DMA_BATCH
-       int "ADC1 DMA number of conversions"
-       depends on STM32H5_ADC1 && STM32H5_ADC1_DMA
-       default 1
-       ---help---
-               This option allows you to select the number of regular group 
conversions
-               that will trigger a DMA callback transerring data to the 
upper-half driver.
-               By default, this value is 1, which means that data is 
transferred after
-               each group conversion.
-
-config STM32H5_ADC2_DMA
-       bool "ADC2 DMA (not supported yet)"
-       depends on STM32H5_ADC2 && EXPERIMENTAL
-       default n
-       ---help---
-               If DMA is selected, then the ADC may be configured to support
-               DMA transfer, which is necessary if multiple channels are read
-               or if very high trigger frequencies are used.
-
-config STM32H5_ADC2_DMA_BATCH
-       int "ADC2 DMA number of conversions"
-       depends on STM32H5_ADC2 && STM32H5_ADC2_DMA
-       default 1
-       ---help---
-               This option allows you to select the number of regular group 
conversions
-               that will trigger a DMA callback transerring data to the 
upper-half driver.
-               By default, this value is 1, which means that data is 
transferred after
-               each group conversion.
-
-endmenu
-
 menu "Ethernet MAC Configuration"
        depends on STM32H5_ETHMAC
 
diff --git a/arch/arm/src/stm32h5/Make.defs b/arch/arm/src/stm32h5/Make.defs
index 61ca2130741..c2c5430145b 100644
--- a/arch/arm/src/stm32h5/Make.defs
+++ b/arch/arm/src/stm32h5/Make.defs
@@ -88,6 +88,10 @@ ifeq ($(CONFIG_STM32H5_ETHMAC),y)
 CHIP_CSRCS += stm32_ethernet.c
 endif
 
+ifeq ($(CONFIG_STM32H5_DMA),y)
+CHIP_CSRCS += stm32_dma.c
+endif
+
 # Required chip type specific files
 
 ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y)
diff --git a/arch/arm/src/stm32h5/hardware/stm32_gpdma.h 
b/arch/arm/src/stm32h5/hardware/stm32_gpdma.h
index 1e4b2760085..47125c3173d 100644
--- a/arch/arm/src/stm32h5/hardware/stm32_gpdma.h
+++ b/arch/arm/src/stm32h5/hardware/stm32_gpdma.h
@@ -30,6 +30,12 @@
 #include <nuttx/config.h>
 #include "chip.h"
 
+#if defined(CONFIG_STM32H5_STM32H56XXX) || defined(CONFIG_STM32H5_STM32H57XXX)
+#  include "stm32h56x_dmasigmap.h"
+#else
+# error "Unsupported STM32 H5 DMA map"
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -455,6 +461,8 @@
 #define GPDMA_CXCR_PRIO_SHIFT         (22)      /* Bits 22-23: Priority level 
of ch x GPDMA transfer */
 #define GPDMA_CXCR_PRIO_MASK          (0b11 << GPDMA_CXCR_PRIO_SHIFT)
 
+#define GPDMA_CXCR_ALLINTS            
(GPDMA_CXCR_TOIE|GPDMA_CXCR_SUSPEI|GPDMA_CXCR_USEIE|GPDMA_CXCR_ULEIE|GPDMA_CXCR_DTEIE|GPDMA_CXCR_HTIE|GPDMA_CXCR_TCIE)
+
 /* Channel x transfer register 1 */
 
 #define GPDMA_CXTR1_SDW_LOG2_SHIFT    (0)
@@ -485,7 +493,7 @@
 #define GPDMA_CXTR1_DBL_1(l)          ((l) - 1 << GPDMA_CXTR1_DBL_1_SHIFT)
 
 #define GPDMA_CXTR1_DBX               (1 << 26) /* Destination byte exchange */
-#define GPDMA_CXTR1_DHX               (1 << 17) /* Destination half-word 
exchange */
+#define GPDMA_CXTR1_DHX               (1 << 27) /* Destination half-word 
exchange */
 #define GPDMA_CXTR1_DAP               (1 << 30) /* Destination allocated port 
*/
 #define GPDMA_CXTR1_DSEC              (1 << 31) /* Security attribute of 
transfer to the destination */
 
diff --git a/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h 
b/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
new file mode 100644
index 00000000000..9a654032261
--- /dev/null
+++ b/arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+ * arch/arm/src/stm32h5/hardware/stm32h56x_dmasigmap.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H
+#define __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H
+
+/* This file is valid for STM32H562/563/573 devices */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* GPDMA Request Number */
+
+#define GPDMA_REQ_ADC1              (0)
+#define GPDMA_REQ_ADC2              (1)
+#define GPDMA_REQ_DAC1_CH1          (2)
+#define GPDMA_REQ_DAC1_CH2          (3)
+#define GPDMA_REQ_TIM6_UPD          (4)
+#define GPDMA_REQ_TIM7_UPD          (5)
+#define GPDMA_REQ_SPI1_RX           (6)
+#define GPDMA_REQ_SPI1_TX           (7)
+#define GPDMA_REQ_SPI2_RX           (8)
+#define GPDMA_REQ_SPI2_TX           (9)
+#define GPDMA_REQ_SPI3_RX           (10)
+#define GPDMA_REQ_SPI3_TX           (11)
+#define GPDMA_REQ_I2C1_RX           (12)
+#define GPDMA_REQ_I2C1_TX           (13)
+                                 /* (14) RESERVED */
+#define GPDMA_REQ_I2C2_RX           (15)
+#define GPDMA_REQ_I2C2_TX           (16)
+                                 /* (17) RESERVED */
+#define GPDMA_REQ_I2C3_RX           (18)
+#define GPDMA_REQ_I2C3_TX           (19)
+                                 /* (20) RESERVED */
+#define GPDMA_REQ_USART1_RX         (21)
+#define GPDMA_REQ_USART1_TX         (22)
+#define GPDMA_REQ_USART2_RX         (23)
+#define GPDMA_REQ_USART2_TX         (24)
+#define GPDMA_REQ_USART3_RX         (25)
+#define GPDMA_REQ_USART3_TX         (26)
+#define GPDMA_REQ_UART4_RX          (27)
+#define GPDMA_REQ_UART4_TX          (28)
+#define GPDMA_REQ_UART5_RX          (29)
+#define GPDMA_REQ_UART5_TX          (30)
+#define GPDMA_REQ_USART6_RX         (31)
+#define GPDMA_REQ_USART6_TX         (32)
+#define GPDMA_REQ_UART7_RX          (33)
+#define GPDMA_REQ_UART7_TX          (34)
+#define GPDMA_REQ_UART8_RX          (35)
+#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_UART12_RX         (43)
+#define GPDMA_REQ_UART12_TX         (44)
+#define GPDMA_REQ_LPUART1_RX        (45)
+#define GPDMA_REQ_LPUART1_TX        (46)
+#define GPDMA_REQ_SPI4_RX           (47)
+#define GPDMA_REQ_SPI4_TX           (48)
+#define GPDMA_REQ_SPI5_RX           (49)
+#define GPDMA_REQ_SPI5_TX           (50)
+#define GPDMA_REQ_SPI6_RX           (51)
+#define GPDMA_REQ_SPI6_TX           (52)
+#define GPDMA_REQ_SAI1_A            (53)
+#define GPDMA_REQ_SAI1_B            (54)
+#define GPDMA_REQ_SAI2_A            (55)
+#define GPDMA_REQ_SAI2_B            (56)
+#define GPDMA_REQ_OSPI1             (57)
+#define GPDMA_REQ_TIM1_CC1          (58)
+#define GPDMA_REQ_TIM1_CC2          (59)
+#define GPDMA_REQ_TIM1_CC3          (60)
+#define GPDMA_REQ_TIM1_CC4          (61)
+#define GPDMA_REQ_TIM1_UPD          (62)
+#define GPDMA_REQ_TIM1_TRG          (63)
+#define GPDMA_REQ_TIM1_COM          (64)
+#define GPDMA_REQ_TIM8_CC1          (65)
+#define GPDMA_REQ_TIM8_CC2          (66)
+#define GPDMA_REQ_TIM8_CC3          (67)
+#define GPDMA_REQ_TIM8_CC4          (68)
+#define GPDMA_REQ_TIM8_UPD          (69)
+#define GPDMA_REQ_TIM8_TIG          (70)
+#define GPDMA_REQ_TIM8_COM          (71)
+#define GPDMA_REQ_TIM2_CC1          (72)
+#define GPDMA_REQ_TIM2_CC2          (73)
+#define GPDMA_REQ_TIM2_CC3          (74)
+#define GPDMA_REQ_TIM2_CC4          (75)
+#define GPDMA_REQ_TIM2_UPD          (76)
+#define GPDMA_REQ_TIM3_CC1          (77)
+#define GPDMA_REQ_TIM3_CC2          (78)
+#define GPDMA_REQ_TIM3_CC3          (79)
+#define GPDMA_REQ_TIM3_CC4          (80)
+#define GPDMA_REQ_TIM3_UPD          (81)
+#define GPDMA_REQ_TIM3_TRG          (82)
+#define GPDMA_REQ_TIM4_CC1          (83)
+#define GPDMA_REQ_TIM4_CC2          (84)
+#define GPDMA_REQ_TIM4_CC3          (85)
+#define GPDMA_REQ_TIM4_CC4          (86)
+#define GPDMA_REQ_TIM4_UPD          (87)
+#define GPDMA_REQ_TIM5_CC1          (88)
+#define GPDMA_REQ_TIM5_CC2          (89)
+#define GPDMA_REQ_TIM5_CC3          (90)
+#define GPDMA_REQ_TIM5_CC4          (91)
+#define GPDMA_REQ_TIM5_UPD          (92)
+#define GPDMA_REQ_TIM5_TRG          (93)
+#define GPDMA_REQ_TIM15_CC1         (94)
+#define GPDMA_REQ_TIM15_UPD         (95)
+#define GPDMA_REQ_TIM15_TRG         (96)
+#define GPDMA_REQ_TIM15_COM         (97)
+#define GPDMA_REQ_TIM16_CC1         (98)
+#define GPDMA_REQ_TIM16_UPD         (99)
+#define GPDMA_REQ_TIM17_CC1         (100)
+#define GPDMA_REQ_TIM17_UPD         (101)
+#define GPDMA_REQ_LPTIM1_IC1        (102)
+#define GPDMA_REQ_LPTIM1_IC2        (103)
+#define GPDMA_REQ_LPTIM1_UE         (104)
+#define GPDMA_REQ_LPTIM2_IC1        (105)
+#define GPDMA_REQ_LPTIM2_IC2        (106)
+#define GPDMA_REQ_LPTIM2_UE         (107)
+#define GPDMA_REQ_DCMI_PSSI         (108)
+#define GPDMA_REQ_AES_OUT           (109)
+#define GPDMA_REQ_AES_IN            (110)
+#define GPDMA_REQ_HASH_IN           (111)
+#define GPDMA_REQ_UCPD1_RX          (112)
+#define GPDMA_REQ_UCPD1_TX          (113)
+#define GPDMA_REQ_CORDIC_R          (114)
+#define GPDMA_REQ_CORDIC_W          (115)
+#define GPDMA_REQ_FMAC_R            (116)
+#define GPDMA_REQ_FMAC_W            (117)
+#define GPDMA_REQ_SAES_OUT          (118)
+#define GPDMA_REQ_SAES_IN           (119)
+#define GPDMA_REQ_I3C1_RX           (120)
+#define GPDMA_REQ_I3C1_TX           (121)
+#define GPDMA_REQ_I3C1_TC           (122)
+#define GPDMA_REQ_I3C1_RS           (123)
+#define GPDMA_REQ_I2C4_RX           (124)
+#define GPDMA_REQ_I2C4_TX           (125)
+                                 /* (126) RESERVED */
+#define GPDMA_REQ_LPTIM3_IC1        (127)
+#define GPDMA_REQ_LPTIM3_IC2        (128)
+#define GPDMA_REQ_LPTIM3_UE         (129)
+#define GPDMA_REQ_LPTIM5_IC1        (130)
+#define GPDMA_REQ_LPTIM5_IC2        (131)
+#define GPDMA_REQ_LPTIM5_UE         (132)
+#define GPDMA_REQ_LPTIM6_IC1        (133)
+#define GPDMA_REQ_LPTIM6_IC2        (134)
+#define GPDMA_REQ_LPTIM6_UE         (135)
+
+/* GPDMA Trigger Number */
+
+#define GPDMA_TRIG_EXTI0            (0)
+#define GPDMA_TRIG_EXTI1            (1)
+#define GPDMA_TRIG_EXTI2            (2)
+#define GPDMA_TRIG_EXTI3            (3)
+#define GPDMA_TRIG_EXTI4            (4)
+#define GPDMA_TRIG_EXTI5            (5)
+#define GPDMA_TRIG_EXTI6            (6)
+#define GPDMA_TRIG_EXTI7            (7)
+#define GPDMA_TRIG_TAMP_TRG1        (8)
+#define GPDMA_TRIG_TAMP_TRG2        (9)
+#define GPDMA_TRIG_TAMP_TRG4        (10)
+#define GPDMA_TRIG_LPTIM1_CH1       (11)
+#define GPDMA_TRIG_LPTIM1_CH2       (12)
+#define GPDMA_TRIG_LPTIM2_CH1       (13)
+#define GPDMA_TRIG_LPTIM2_CH2       (14)
+#define GPDMA_TRIG_RTC_ALRA_TRG     (15)
+#define GPDMA_TRIG_RTC_ALRB_TRG     (16)
+#define GPDMA_TRIG_RTC_WUT_TRG      (17)
+#define GPDMA_TRIG_GPDMA1_CH0_TC    (18)
+#define GPDMA_TRIG_GPDMA1_CH1_TC    (19)
+#define GPDMA_TRIG_GPDMA1_CH2_TC    (20)
+#define GPDMA_TRIG_GPDMA1_CH3_TC    (21)
+#define GPDMA_TRIG_GPDMA1_CH4_TC    (22)
+#define GPDMA_TRIG_GPDMA1_CH5_TC    (23)
+#define GPDMA_TRIG_GPDMA1_CH6_TC    (24)
+#define GPDMA_TRIG_GPDMA1_CH7_TC    (25)
+#define GPDMA_TRIG_GPDMA2_CH0_TC    (26)
+#define GPDMA_TRIG_GPDMA2_CH1_TC    (27)
+#define GPDMA_TRIG_GPDMA2_CH2_TC    (28)
+#define GPDMA_TRIG_GPDMA2_CH3_TC    (29)
+#define GPDMA_TRIG_GPDMA2_CH4_TC    (30)
+#define GPDMA_TRIG_GPDMA2_CH5_TC    (31)
+#define GPDMA_TRIG_GPDMA2_CH6_TC    (32)
+#define GPDMA_TRIG_GPDMA2_CH7_TC    (33)
+#define GPDMA_TRIG_TIM2_TRGO        (34)
+#define GPDMA_TRIG_TIM15_TRG0       (35)
+#define GPDMA_TRIG_TIM12_TRGO       (36)
+#define GPDMA_TRIG_LPTIM3_CH1       (37)
+#define GPDMA_TRIG_LPTIM3_CH2       (38)
+#define GPDMA_TRIG_LPTIM4_AIT       (39)
+#define GPDMA_TRIG_LPTIM5_CH1       (40)
+#define GPDMA_TRIG_LPTIM5_CH2       (41)
+#define GPDMA_TRIG_LPTIM6_CH1       (42)
+#define GPDMA_TRIG_LPTIM6_CH2       (43)
+
+#endif /* __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56X_DMASIGMAP_H */
\ No newline at end of file
diff --git a/arch/arm/src/stm32h5/stm32_adc.c b/arch/arm/src/stm32h5/stm32_adc.c
index 2217ea7a197..391dcd6412d 100644
--- a/arch/arm/src/stm32h5/stm32_adc.c
+++ b/arch/arm/src/stm32h5/stm32_adc.c
@@ -3,8 +3,6 @@
  *
  * SPDX-License-Identifier: Apache-2.0
  *
- * SPDX-License-Identifier: Apache-2.0
- *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.  The
@@ -49,6 +47,9 @@
 #include "stm32_adc.h"
 #include "stm32_tim.h"
 #include "stm32_rcc.h"
+#include "stm32_dma.h"
+
+/* ADC "upper half" support must be enabled */
 
 #ifdef CONFIG_ADC
 
@@ -64,11 +65,6 @@
 
 /* ADC Channels/DMA *********************************************************/
 
-#ifdef ADC_HAVE_DMA
-#  error "STM32H5 ADC does not have DMA support."
-#  undef ADC_HAVE_DMA
-#endif
-
 #define ADC_SMPR_DEFAULT    ADC_SMPR_640p5
 #define ADC_SMPR1_DEFAULT   ((ADC_SMPR_DEFAULT << ADC_SMPR1_SMP0_SHIFT) | \
                              (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP1_SHIFT) | \
@@ -105,10 +101,10 @@ struct stm32_dev_s
   uint8_t cchannels;    /* Number of configured channels */
   uint8_t intf;         /* ADC interface number */
   uint8_t current;      /* Current ADC channel being converted */
+  bool     hasdma;      /* True: This ADC supports DMA */
 #ifdef ADC_HAVE_DMA
-  uint8_t dmachan;      /* DMA channel needed by this ADC */
-  bool    hasdma;       /* True: This ADC supports DMA */
   uint16_t dmabatch;    /* Number of conversions for DMA batch */
+  bool     circular;    /* 0 = one-shot, 1 = circular */
 #endif
 #ifdef ADC_HAVE_TIMER
   uint8_t trigger;      /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3,
@@ -187,6 +183,13 @@ static void adc_timstart(struct stm32_dev_s *priv, bool 
enable);
 static int  adc_timinit(struct stm32_dev_s *priv);
 #endif
 
+#ifdef ADC_HAVE_DMA
+static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t status,
+                                void *arg);
+static void adc_dmacfg(struct stm32_dev_s *priv,
+                               struct stm32_gpdma_cfg_s *cfg);
+#endif
+
 /* ADC Interrupt Handler */
 
 static int adc_interrupt(struct adc_dev_s *dev, uint32_t regval);
@@ -245,10 +248,16 @@ static struct stm32_dev_s g_adcpriv1 =
   .freq        = CONFIG_STM32H5_ADC1_SAMPLE_FREQUENCY,
 #endif
 #ifdef ADC1_HAVE_DMA
-  .dmachan     = ADC1_DMA_CHAN,
   .hasdma      = true,
   .r_dmabuffer = g_adc1_dmabuffer,
-  .dmabatch    = CONFIG_STM32H5_ADC1_DMA_BATCH
+  .dmabatch    = CONFIG_STM32H5_ADC1_DMA_BATCH,
+#  ifdef CONFIG_STM32H5_ADC1_DMA_CFG
+  .circular    = true,
+#  else
+  .circular    = false,
+#  endif
+#else
+  .hasdma      = false,
 #endif
 };
 
@@ -262,6 +271,12 @@ static struct adc_dev_s g_adcdev1 =
 /* ADC2 state */
 
 #ifdef CONFIG_STM32H5_ADC2
+
+#ifdef ADC2_HAVE_DMA
+static uint16_t g_adc2_dmabuffer[CONFIG_STM32H5_ADC_MAX_SAMPLES *
+                                 CONFIG_STM32H5_ADC2_DMA_BATCH];
+#endif
+
 static struct stm32_dev_s g_adcpriv2 =
 {
   .irq         = STM32_IRQ_ADC2,
@@ -279,6 +294,18 @@ static struct stm32_dev_s g_adcpriv2 =
   .pclck       = ADC2_TIMER_PCLK_FREQUENCY,
   .freq        = CONFIG_STM32H5_ADC2_SAMPLE_FREQUENCY,
 #endif
+#ifdef ADC2_HAVE_DMA
+  .hasdma      = true,
+  .r_dmabuffer = g_adc2_dmabuffer,
+  .dmabatch    = CONFIG_STM32H5_ADC2_DMA_BATCH,
+#  ifdef CONFIG_STM32H5_ADC2_DMA_CFG
+  .circular    = true,
+#  else
+  .circular    = false,
+#  endif
+#else
+  .hasdma      = false,
+#endif
 };
 
 static struct adc_dev_s g_adcdev2 =
@@ -777,6 +804,104 @@ static void adc_reset(struct adc_dev_s *dev)
   adc_rccreset(priv, false);
 }
 
+/****************************************************************************
+ * Name: adc_dmaconvcallback
+ *
+ * Description:
+ *   Callback for DMA.  Called from the DMA transfer complete interrupt after
+ *   all channels have been converted and transferred with DMA.
+ *
+ * Input Parameters:
+ *
+ *   handle - handle to DMA
+ *   status -
+ *   arg - adc device
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+ #ifdef ADC_HAVE_DMA
+static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t status, void *arg)
+{
+  struct adc_dev_s   *dev  = (struct adc_dev_s *)arg;
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  struct stm32_gpdma_cfg_s dmacfg;
+  int i;
+
+  /* Verify that the upper-half has bound its callback */
+
+  if (priv->cb != NULL)
+    {
+      DEBUGASSERT(priv->cb->au_receive != NULL);
+
+      /* Deliver one sample per configured channel */
+
+      for (i = 0; i < priv->rnchannels * priv->dmabatch; i++)
+        {
+          priv->cb->au_receive(dev,
+                              priv->chanlist[priv->current],
+                              priv->r_dmabuffer[i]);
+          priv->current++;
+          if (priv->current >= priv->rnchannels)
+            {
+              priv->current = 0;
+            }
+        }
+    }
+
+  /* Restart DMA for the next conversion series */
+
+  if (priv->circular == 0)
+    {
+      adc_dmacfg(priv, &dmacfg);
+      stm32_dmasetup(priv->dma, &dmacfg);
+      stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
+      adc_startconv(priv, true);
+    }
+}
+
+/****************************************************************************
+ * Name: adc_dmacfg
+ *
+ * Description:
+ *   Generate the required DMA configuration structure for oneshot mode based
+ *   on the ADC configuration.
+ *
+ * Input Parameters:
+ *   priv     - ADC instance structure
+ *   cfg      - DMA configuration structure
+ *   circular - 0 = oneshot, 1 = circular
+ *
+ * Returned Value:
+ *   None
+ ****************************************************************************/
+
+static void adc_dmacfg(struct stm32_dev_s *priv,
+                       struct stm32_gpdma_cfg_s *cfg)
+{
+  const uint32_t sdw_log2 = 1;  /* Always 16-bit half-word for ADC_DR */
+
+  cfg->src_addr   = priv->base + STM32_ADC_DR_OFFSET;
+  cfg->dest_addr  = (uintptr_t)priv->r_dmabuffer;
+
+  cfg->request    = (priv->base == STM32_ADC1_BASE)
+                     ? GPDMA_REQ_ADC1
+                     : GPDMA_REQ_ADC2;
+
+  cfg->priority   = GPMDACFG_PRIO_LH;
+
+  cfg->mode       = priv->circular ? GPDMACFG_MODE_CIRC : 0;
+
+  cfg->ntransfers = priv->cchannels * priv->dmabatch * (1u << sdw_log2);
+
+  cfg->tr1        = (sdw_log2 << GPDMA_CXTR1_SDW_LOG2_SHIFT)
+                  | (sdw_log2 << GPDMA_CXTR1_DDW_LOG2_SHIFT)
+                  | GPDMA_CXTR1_DINC;  /* dest-inc, source fixed */
+}
+#endif
+
 /****************************************************************************
  * Name: adc_setup
  *
@@ -795,6 +920,9 @@ static void adc_reset(struct adc_dev_s *dev)
 static int adc_setup(struct adc_dev_s *dev)
 {
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+#ifdef ADC_HAVE_DMA
+  struct stm32_gpdma_cfg_s dmacfg;
+#endif
   int ret;
   irqstate_t flags;
   uint32_t clrbits;
@@ -842,15 +970,29 @@ static int adc_setup(struct adc_dev_s *dev)
 #ifdef ADC_HAVE_DMA
   if (priv->hasdma)
     {
-      /* Enable One shot DMA */
+      /* Enable One-shot or Circular DMA.
+       * WARNING: This doesn't work in dual-ADC modes. [RM0481] ADC_CFGR
+       * register description (pg. 1122) - "In dual-ADC modes, this bit is
+       * not relevant and replaced by control bit DMACFG of the ADC_CCR
+       * register"
+       */
 
       setbits |= ADC_CFGR_DMAEN;
-    }
-#endif
-
-  /* Disable continuous mode */
 
+      if (priv->circular)
+        {
+          setbits |= ADC_CFGR_DMACFG;
+          setbits |= ADC_CFGR_CONT;
+        }
+      else
+        {
+          clrbits |= ADC_CFGR_DMACFG;
+          clrbits |= ADC_CFGR_CONT;
+        }
+    }
+#else
   clrbits |= ADC_CFGR_CONT;
+#endif
 
   /* Disable external trigger for regular channels */
 
@@ -903,17 +1045,14 @@ static int adc_setup(struct adc_dev_s *dev)
           stm32_dmafree(priv->dma);
         }
 
-      priv->dma = stm32_dmachannel(priv->dmachan);
+      priv->dma = stm32_dmachannel(GPDMA_TTYPE_P2M);
 
-      stm32_dmasetup(priv->dma,
-                     priv->base + STM32_ADC_DR_OFFSET,
-                     (uint32_t)priv->r_dmabuffer,
-                     priv->rnchannels * priv->dmabatch,
-                     ADC_DMA_CONTROL_WORD);
+      adc_dmacfg(priv, &dmacfg);
+
+      stm32_dmasetup(priv->dma, &dmacfg);
 
       stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
     }
-
 #endif
 
   /* Set ADEN to wake up the ADC from Power Down. */
@@ -949,10 +1088,14 @@ static int adc_setup(struct adc_dev_s *dev)
         adc_getreg(priv, STM32_ADC_SQR4_OFFSET));
   ainfo("CCR:   0x%08" PRIx32 "\n", adc_getregm(priv, STM32_ADC_CCR_OFFSET));
 
-  /* Enable the ADC interrupt */
+  if (!priv->hasdma)
+    {
+      /* Enable the ADC interrupt */
 
-  ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
-  up_enable_irq(priv->irq);
+      ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
+
+      up_enable_irq(priv->irq);
+    }
 
   priv->initialized = true;
 
diff --git a/arch/arm/src/stm32h5/stm32_adc.h b/arch/arm/src/stm32h5/stm32_adc.h
index 646048c1fd1..eec3fc4e5fc 100644
--- a/arch/arm/src/stm32h5/stm32_adc.h
+++ b/arch/arm/src/stm32h5/stm32_adc.h
@@ -43,52 +43,58 @@
 /* Timer devices may be used for different purposes.  One special purpose is
  * to control periodic ADC sampling.  If CONFIG_STM32H5_TIMn is defined then
  * CONFIG_STM32H5_TIMn_ADC must also be defined to indicate that timer "n"
- * is intended to be used for that purpose. Timers 1,2,3,6 and 15 may be
- * used on STM32H5X3, while STM32H5X6 adds support for timers 4 and 8 as
- * well.
+ * is intended to be used for that purpose.
  */
 
 #ifndef CONFIG_STM32H5_TIM1
 #  undef CONFIG_STM32H5_TIM1_ADC
 #  undef CONFIG_STM32H5_TIM1_ADC1
 #  undef CONFIG_STM32H5_TIM1_ADC2
-#  undef CONFIG_STM32H5_TIM1_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM2
 #  undef CONFIG_STM32H5_TIM2_ADC
 #  undef CONFIG_STM32H5_TIM2_ADC1
 #  undef CONFIG_STM32H5_TIM2_ADC2
-#  undef CONFIG_STM32H5_TIM2_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM3
 #  undef CONFIG_STM32H5_TIM3_ADC
 #  undef CONFIG_STM32H5_TIM3_ADC1
 #  undef CONFIG_STM32H5_TIM3_ADC2
-#  undef CONFIG_STM32H5_TIM3_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM4
 #  undef CONFIG_STM32H5_TIM4_ADC
 #  undef CONFIG_STM32H5_TIM4_ADC1
 #  undef CONFIG_STM32H5_TIM4_ADC2
-#  undef CONFIG_STM32H5_TIM4_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM6
 #  undef CONFIG_STM32H5_TIM6_ADC
 #  undef CONFIG_STM32H5_TIM6_ADC1
 #  undef CONFIG_STM32H5_TIM6_ADC2
-#  undef CONFIG_STM32H5_TIM6_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM8
 #  undef CONFIG_STM32H5_TIM8_ADC
 #  undef CONFIG_STM32H5_TIM8_ADC1
 #  undef CONFIG_STM32H5_TIM8_ADC2
-#  undef CONFIG_STM32H5_TIM8_ADC3
 #endif
 #ifndef CONFIG_STM32H5_TIM15
 #  undef CONFIG_STM32H5_TIM15_ADC
 #  undef CONFIG_STM32H5_TIM15_ADC1
 #  undef CONFIG_STM32H5_TIM15_ADC2
-#  undef CONFIG_STM32H5_TIM15_ADC3
+#endif
+
+/* DMA support */
+
+#undef ADC_HAVE_DMA
+#if defined(CONFIG_STM32H5_ADC1_DMA) || defined(CONFIG_STM32H5_ADC2_DMA)
+#  define ADC_HAVE_DMA 1
+#endif
+
+#if defined(CONFIG_STM32H5_ADC1_DMA)
+#  define ADC1_HAVE_DMA 1
+#endif
+
+#if defined(CONFIG_STM32H5_ADC2_DMA)
+#  define ADC2_HAVE_DMA 1
 #endif
 
 /* Timer configuration:  If a timer trigger is specified, then get
@@ -213,72 +219,19 @@
 #  undef ADC_HAVE_TIMER
 #endif
 
-/* Timer 1 */
-
-#define ADC1_EXTSEL_T1CC1      ADC_CFGR_EXTSEL_T1CC1
-#define ADC1_EXTSEL_T1CC2      ADC_CFGR_EXTSEL_T1CC2
-#define ADC1_EXTSEL_T1CC3      ADC_CFGR_EXTSEL_T1CC3
-#define ADC1_EXTSEL_T1CC4      ADC_CFGR_EXTSEL_T1CC4
-#define ADC1_EXTSEL_T1TRGO     ADC_CFGR_EXTSEL_T1TRGO
-#define ADC1_EXTSEL_T1TRGO2    ADC_CFGR_EXTSEL_T1TRGO2
-#define ADC2_EXTSEL_T1CC1      ADC_CFGR_EXTSEL_T1CC1
-#define ADC2_EXTSEL_T1CC2      ADC_CFGR_EXTSEL_T1CC2
-#define ADC2_EXTSEL_T1CC3      ADC_CFGR_EXTSEL_T1CC3
-#define ADC2_EXTSEL_T1CC4      ADC_CFGR_EXTSEL_T1CC4
-#define ADC2_EXTSEL_T1TRGO     ADC_CFGR_EXTSEL_T1TRGO
-#define ADC2_EXTSEL_T1TRGO2    ADC_CFGR_EXTSEL_T1TRGO2
-
-/* Timer 2 */
-
-#define ADC1_EXTSEL_T2CC2      ADC_CFGR_EXTSEL_T2CC2
-#define ADC1_EXTSEL_T2TRGO     ADC_CFGR_EXTSEL_T2TRGO
-#define ADC2_EXTSEL_T2CC2      ADC_CFGR_EXTSEL_T2CC2
-#define ADC2_EXTSEL_T2TRGO     ADC_CFGR_EXTSEL_T2TRGO
-
-/* Timer 3 */
-
-#define ADC1_EXTSEL_T3CC4      ADC_CFGR_EXTSEL_T3CC4
-#define ADC1_EXTSEL_T3TRGO     ADC_CFGR_EXTSEL_T3TRGO
-#define ADC2_EXTSEL_T3CC4      ADC_CFGR_EXTSEL_T3CC4
-#define ADC2_EXTSEL_T3TRGO     ADC_CFGR_EXTSEL_T3TRGO
-
-/* Timer 4 */
-
-#define ADC1_EXTSEL_T4CC4      ADC_CFGR_EXTSEL_T4CC4
-#define ADC1_EXTSEL_T4TRGO     ADC_CFGR_EXTSEL_T4TRGO
-#define ADC2_EXTSEL_T4CC4      ADC_CFGR_EXTSEL_T4CC4
-#define ADC2_EXTSEL_T4TRGO     ADC_CFGR_EXTSEL_T4TRGO
-
-/* Timer 6 */
-
-#define ADC1_EXTSEL_T6TRGO     ADC_CFGR_EXTSEL_T6TRGO
-#define ADC2_EXTSEL_T6TRGO     ADC_CFGR_EXTSEL_T6TRGO
-
-/* Timer 8 */
-
-#define ADC1_EXTSEL_T8TRGO     ADC_CFGR_EXTSEL_T8TRGO
-#define ADC1_EXTSEL_T8TRGO2    ADC_CFGR_EXTSEL_T8TRGO2
-#define ADC2_EXTSEL_T8TRGO     ADC_CFGR_EXTSEL_T8TRGO
-#define ADC2_EXTSEL_T8TRGO2    ADC_CFGR_EXTSEL_T8TRGO2
-
-/* Timer 15 */
-
-#define ADC1_EXTSEL_T15TRGO    ADC_CFGR_EXTSEL_T15TRGO
-#define ADC2_EXTSEL_T15TRGO    ADC_CFGR_EXTSEL_T15TRGO
-
 #if defined(CONFIG_STM32H5_TIM1_ADC1)
 #  if CONFIG_STM32H5_ADC1_TIMTRIG == 0
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC1
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC2
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC2
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC3
+#    define ADC1_EXTSEL_VALUE ADC_CFGR__EXTSEL_T1CC3
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC4
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC4
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO2
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO2
 #  else
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM1)"
 #  endif
@@ -286,13 +239,13 @@
 #  if CONFIG_STM32H5_ADC1_TIMTRIG == 0
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC2
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2CC2
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
 #  else
@@ -306,9 +259,9 @@
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC4
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3CC4
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
 #  else
@@ -322,9 +275,9 @@
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC4
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4CC4
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CRFT_EXTSEL_T4TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
 #  else
@@ -340,7 +293,7 @@
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T6TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
 #  else
@@ -356,9 +309,9 @@
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO2
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO2
 #  else
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM8)"
 #  endif
@@ -372,7 +325,7 @@
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
-#    define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T15TRGO
+#    define ADC1_EXTSEL_VALUE ADC_CFGR_EXTSEL_T15TRGO
 #  elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
 #  else
@@ -382,17 +335,17 @@
 
 #if defined(CONFIG_STM32H5_TIM1_ADC2)
 #  if CONFIG_STM32H5_ADC2_TIMTRIG == 0
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC1
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC1
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC2
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC2
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC3
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC3
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC4
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1CC4
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO2
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T1TRGO2
 #  else
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM1)"
 #  endif
@@ -400,13 +353,13 @@
 #  if CONFIG_STM32H5_ADC2_TIMTRIG == 0
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC2
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2CC2
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T2TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
 #  else
@@ -420,9 +373,9 @@
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC4
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3CC4
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T3TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
 #  else
@@ -436,9 +389,9 @@
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC4
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4CC4
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T4TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
 #  else
@@ -454,7 +407,7 @@
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T6TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
 #  else
@@ -470,9 +423,9 @@
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO2
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T8TRGO2
 #  else
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM8)"
 #  endif
@@ -486,7 +439,7 @@
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
-#    define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T15TRGO
+#    define ADC2_EXTSEL_VALUE ADC_CFGR_EXTSEL_T15TRGO
 #  elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
 #    error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
 #  else
diff --git a/arch/arm/src/stm32h5/stm32_dma.c b/arch/arm/src/stm32h5/stm32_dma.c
new file mode 100644
index 00000000000..2745c5b464a
--- /dev/null
+++ b/arch/arm/src/stm32h5/stm32_dma.c
@@ -0,0 +1,763 @@
+/****************************************************************************
+ * arch/arm/src/stm32h5/stm32_dma.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/signal.h>
+
+#include "arm_internal.h"
+#include "sched/sched.h"
+#include "stm32_dma.h"
+#include "hardware/stm32_gpdma.h"
+#include "hardware/stm32_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For GPDMA peripheral, each channel has channel specific addresses that are
+ * at a base offset based on channel. Channel reg references will be based
+ * off this in this file.
+ */
+
+#define CH_BASE_OFFSET(ch)  (0x80*(ch)) 
+#define CH_CXLBAR_OFFSET     0x50
+#define CH_CXFCR_OFFSET      0x5C
+#define CH_CXSR_OFFSET       0x60
+#define CH_CXCR_OFFSET       0x64
+#define CH_CXTR1_OFFSET      0x90
+#define CH_CXTR2_OFFSET      0x94
+#define CH_CXBR1_OFFSET      0x98
+#define CH_CXSAR_OFFSET      0x9C
+#define CH_CXDAR_OFFSET      0xA0
+#define CH_CXTR3_OFFSET      0xA4
+#define CH_CXBR2_OFFSET      0xA8
+#define CH_CXLLR_OFFSET      0xCC
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_gpdma_lli_s
+{
+  uint32_t tr1;   /* GPDMA_CxTR1 value */
+  uint32_t tr2;   /* GPDMA_CxTR2 value */
+  uint32_t br1;   /* GPDMA_CxBR1 value (block size in bytes) */
+  uint32_t sar;   /* GPDMA_CxSAR (source address) */
+  uint32_t dar;   /* GPDMA_CxDAR (dest address) */
+  uint32_t llr;   /* GPDMA_CxLLR (pointer+update bits) */
+}
+__attribute__ ((aligned(32)));
+
+struct gpdma_ch_s
+{
+  uint8_t            dma_instance; /* GPDMA1 or GPDMA2 */
+  uint8_t            channel;
+  uint8_t            irq;
+  enum gpdma_ttype_e type;
+  bool               free;         /* Is this channel free to use. */
+  uint32_t           base;         /* Channel base address */
+  dma_callback_t     callback;
+  void              *arg;
+  struct stm32_gpdma_cfg_s cfg;   /* Configuration passed at channel setup */
+  struct stm32_gpdma_lli_s lli[2];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline uint32_t gpdmach_getreg(struct gpdma_ch_s *chan,
+                                      uint32_t offset);
+static inline void gpdmach_putreg(struct gpdma_ch_s *chan, uint32_t offset,
+                                  uint32_t value);
+static inline void gpdmach_modifyreg32(struct gpdma_ch_s *chan,
+                                       uint32_t offset, uint32_t clrbits,
+                                       uint32_t setbits);
+static void gpdma_ch_abort(struct gpdma_ch_s *chan);
+static void gpdma_ch_disable(struct gpdma_ch_s *chan);
+
+static int gpdma_setup(struct gpdma_ch_s *chan,
+                       struct stm32_gpdma_cfg_s *cfg);
+static int gpdma_setup_circular(struct gpdma_ch_s *chan,
+                                struct stm32_gpdma_cfg_s *cfg);
+static int gpdma_dmainterrupt(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32H5_DMA1
+static struct gpdma_ch_s g_chan[] =
+{
+  {
+    .dma_instance = 1,
+    .channel = 0,
+    .irq = STM32_IRQ_GPDMA1_CH0,
+    .free = true,
+    .base = STM32_DMA1_BASE + CH_BASE_OFFSET(0)
+  },
+  {
+    .dma_instance = 1,
+    .channel = 1,
+    .irq = STM32_IRQ_GPDMA1_CH1,
+    .free = true,
+    .base = STM32_DMA1_BASE + CH_BASE_OFFSET(1)
+  },
+  {
+    .dma_instance = 1,
+    .channel = 2,
+    .irq = STM32_IRQ_GPDMA1_CH2,
+    .free = true,
+    .base = STM32_DMA1_BASE + CH_BASE_OFFSET(2)
+  },
+  {
+    .dma_instance = 1,
+    .channel = 3,
+    .irq = STM32_IRQ_GPDMA1_CH3,
+    .free = true,
+    .base = STM32_DMA1_BASE + CH_BASE_OFFSET(3)
+  },
+#endif
+#ifdef CONFIG_STM32H5_DMA2
+  {
+    .dma_instance = 2,
+    .channel = 0,
+    .irq = STM32_IRQ_GPDMA2_CH0,
+    .free = true,
+    .base = STM32_DMA2_BASE + CH_BASE_OFFSET(0)
+  },
+  {
+    .dma_instance = 2,
+    .channel = 1,
+    .irq = STM32_IRQ_GPDMA2_CH1,
+    .free = true,
+    .base = STM32_DMA2_BASE + CH_BASE_OFFSET(1)
+  },
+  {
+    .dma_instance = 2,
+    .channel = 2,
+    .irq = STM32_IRQ_GPDMA2_CH2,
+    .free = true,
+    .base = STM32_DMA2_BASE + CH_BASE_OFFSET(2)
+  },
+  {
+    .dma_instance = 2,
+    .channel = 3,
+    .irq = STM32_IRQ_GPDMA2_CH3,
+    .free = true,
+    .base = STM32_DMA2_BASE + CH_BASE_OFFSET(3)
+  }
+#endif
+};
+
+static uint32_t circ_addr_1;
+
+static uint32_t circ_addr_1;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline uint32_t gpdmach_getreg(struct gpdma_ch_s *chan,
+                                      uint32_t offset)
+{
+  return getreg32(chan->base + offset);
+}
+
+static inline void gpdmach_putreg(struct gpdma_ch_s *chan, uint32_t offset,
+                                  uint32_t value)
+{
+  putreg32(value, chan->base + offset);
+}
+
+static inline void gpdmach_modifyreg32(struct gpdma_ch_s *chan,
+                                       uint32_t offset, uint32_t clrbits,
+                                       uint32_t setbits)
+{
+  modifyreg32(chan->base + offset, clrbits, setbits);
+}
+
+/****************************************************************************
+ * Name: gpdma_dmainterrupt
+ *
+ * Description:
+ *   DMA interrupt handler.
+ *
+ ****************************************************************************/
+
+static int gpdma_dmainterrupt(int irq, void *context, void *arg)
+{
+  struct gpdma_ch_s *chan = NULL;
+  uint32_t status;
+
+  /* Get the channel that generated the interrupt */
+
+  if (irq >= STM32_IRQ_GPDMA1_CH0 && irq <= STM32_IRQ_GPDMA1_CH7)
+    {
+      chan = &g_chan[irq - STM32_IRQ_GPDMA1_CH0];
+    }
+  else if (irq >= STM32_IRQ_GPDMA2_CH0 && irq <= STM32_IRQ_GPDMA2_CH7)
+    {
+      chan = &g_chan[irq - STM32_IRQ_GPDMA2_CH0 + 4];
+    }
+  else
+    {
+      DEBUGPANIC();
+    }
+
+  /* Get the interrupt status for this channel */
+
+  status = (gpdmach_getreg(chan, CH_CXSR_OFFSET) >> 8) & 0x7f;
+
+  /* Clear the fetched channel interrupts by setting bits in the flag
+   * clear register
+   */
+
+  gpdmach_putreg(chan, CH_CXFCR_OFFSET, ~0);
+
+  /* Invoke the callback */
+
+  if (chan->callback)
+    {
+      chan->callback(chan, (uint8_t)status, chan->arg);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: gpdma_ch_abort
+ *
+ * Description:
+ *   For the given channel, suspend and abort any ongoing channel transfers.
+ *   Returns after the abort has complete and taken effect.
+ *
+ ****************************************************************************/
+
+static void gpdma_ch_abort(struct gpdma_ch_s *chan)
+{
+  if ((gpdmach_getreg(chan, CH_CXCR_OFFSET) & GPDMA_CXCR_EN) == 0)
+    {
+      return;
+    }
+
+  /* 1. Software writes 1 to the GPDMA_CxCR.SUSP bit */
+
+  gpdmach_putreg(chan, CH_CXCR_OFFSET, GPDMA_CXCR_SUSP);
+
+  /* 2. Polls suspend flag GPDMA_CxSR.SUSPF until SUSPF = 1, or waits for an
+   *    interrupt previously enabled by writing 1 to GPDMA_CxCR.SUSPIE.
+   */
+
+  while ((gpdmach_getreg(chan, CH_CXSR_OFFSET) & GPDMA_CXSR_SUSPF) == 0)
+    {
+    }
+
+  /* 3. Reset chan by writing 1 to GPDMA_CxCR.RESET */
+
+  gpdmach_putreg(chan, CH_CXCR_OFFSET, GPDMA_CXCR_RESET);
+
+  /* 4. Wait for GPDMA_CxCR.EN and GPDMA_CxCR.SUSP bits to be reset */
+
+  while ((gpdmach_getreg(chan, CH_CXCR_OFFSET) &
+         (GPDMA_CXCR_EN | GPDMA_CXCR_SUSP)) != 0)
+    {
+    }
+}
+
+/****************************************************************************
+ * Name: gpdma_ch_disable
+ *
+ * Description:
+ *   Disable the DMA channel.
+ *
+ ****************************************************************************/
+
+static void gpdma_ch_disable(struct gpdma_ch_s *chan)
+{
+  DEBUGASSERT(chan != NULL);
+
+  gpdma_ch_abort(chan);
+
+  /* Disable and clear all interrupts. */
+
+  gpdmach_modifyreg32(chan, CH_CXCR_OFFSET, GPDMA_CXCR_ALLINTS, 0);
+  gpdmach_modifyreg32(chan, CH_CXFCR_OFFSET, 0, ~0);
+}
+
+/****************************************************************************
+ * Name: gpdma_setup
+ *
+ * Assumptions:
+ *   - EN bit not set. Channel must have been aborted before this is called.
+ *
+ ****************************************************************************/
+
+static int gpdma_setup(struct gpdma_ch_s *chan,
+                       struct stm32_gpdma_cfg_s *cfg)
+{
+  uint32_t reg;
+
+  /* Make sure not to use linked list mode. */
+
+  gpdmach_modifyreg32(chan, CH_CXLLR_OFFSET, ~0, 0);
+  gpdmach_putreg(chan, CH_CXLBAR_OFFSET, 0);
+
+  /* Set source and destination addresses. */
+
+  gpdmach_putreg(chan, CH_CXSAR_OFFSET, cfg->src_addr);
+  gpdmach_putreg(chan, CH_CXDAR_OFFSET, cfg->dest_addr);
+
+  /* Set the channel priority according to configuration. */
+
+  gpdmach_modifyreg32(chan, CH_CXCR_OFFSET, GPDMA_CXCR_PRIO_MASK,
+                      cfg->priority << GPDMA_CXCR_PRIO_SHIFT);
+
+  /* Set channels TR1 register based on configuration provided. */
+
+  gpdmach_putreg(chan, CH_CXTR1_OFFSET, cfg->tr1);
+
+  /* Assemble the required config for TR2 */
+
+  reg = (uint32_t)cfg->request &
+        (GPDMA_CXTR2_REQSEL_MASK | GPDMA_CXTR2_DREQ | GPDMA_CXTR2_SWREQ);
+  gpdmach_putreg(chan, CH_CXTR2_OFFSET, reg);
+
+  /* Calculate block number of data bytes to transfer, update BR1 */
+
+  reg = cfg->ntransfers;
+
+  if (cfg->mode & GPDMACFG_MODE_CIRC)
+    {
+      /* This only targets peripheral to memory, with memory increment */
+
+      circ_addr_1 = cfg->dest_addr;
+      gpdmach_putreg(chan, CH_CXLBAR_OFFSET,
+                    (uint32_t)&circ_addr_1 & (0xffff << 16));
+
+      reg = GPDMA_CXLLR_UDA | ((uint32_t)&circ_addr_1 & GPDMA_CXLLR_LA_MASK);
+      gpdmach_putreg(chan, CH_CXLLR_OFFSET, reg);
+    }
+
+  gpdmach_putreg(chan, CH_CXBR1_OFFSET, reg);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: gpdma_setup_circular
+ *
+ * Description:
+ *   Circular DMA requires linked list items (LLI) to setup properly. This
+ *   function handles LLI allocation and handling necessary to implement
+ *   circular DMA.
+ *
+ ****************************************************************************/
+
+static int gpdma_setup_circular(struct gpdma_ch_s *chan,
+                                struct stm32_gpdma_cfg_s *cfg)
+{
+  struct stm32_gpdma_lli_s *lli = chan->lli;
+
+  lli[0].tr1 = cfg->tr1;
+  lli[0].tr2 = (2U << GPDMA_CXTR2_TCEM_SHIFT)
+             | (cfg->request & GPDMA_CXTR2_REQSEL_MASK);
+  lli[0].br1 = cfg->ntransfers;
+  lli[0].sar = cfg->src_addr;
+  lli[0].dar = cfg->dest_addr;
+  lli[0].llr = (GPDMA_CXLLR_UT1  /* reload TR1 */
+             | GPDMA_CXLLR_UT2   /* reload TR2 */
+             | GPDMA_CXLLR_UB1   /* reload BR1 */
+             | GPDMA_CXLLR_USA   /* reload SAR */
+             | GPDMA_CXLLR_UDA   /* reload DAR */
+             | GPDMA_CXLLR_ULL)  /* reload LLR */
+             | (((uint32_t)&lli[1]) & GPDMA_CXLLR_LA_MASK);
+
+  lli[1].tr1 = lli[0].tr1;
+  lli[1].tr2 = lli[0].tr2;
+  lli[1].br1 = lli[0].br1;
+  lli[1].sar = lli[0].sar;
+  lli[1].dar = lli[0].dar;
+  lli[1].llr = (lli[0].llr & ~GPDMA_CXLLR_LA_MASK)
+             | (((uint32_t)&lli[0]) & GPDMA_CXLLR_LA_MASK);
+
+  gpdmach_putreg(chan, CH_CXSAR_OFFSET,   lli[0].sar);
+  gpdmach_putreg(chan, CH_CXDAR_OFFSET,   lli[0].dar);
+  gpdmach_putreg(chan, CH_CXTR1_OFFSET,   lli[0].tr1);
+  gpdmach_putreg(chan, CH_CXTR2_OFFSET,   lli[0].tr2);
+  gpdmach_putreg(chan, CH_CXBR1_OFFSET,   lli[0].br1);
+  gpdmach_putreg(chan, CH_CXLBAR_OFFSET,  (uint32_t)&lli[0]);
+  gpdmach_putreg(chan, CH_CXLLR_OFFSET,   lli[0].llr);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_dma_initialize
+ *
+ * Description:
+ *   Initialize the DMA subsystem
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void weak_function arm_dma_initialize(void)
+{
+  struct gpdma_ch_s *chan;
+  int i;
+
+  /* Initialize each DMA stream */
+
+  for (i = 0; i < sizeof(g_chan) / sizeof(struct gpdma_ch_s); i++)
+    {
+      chan = &g_chan[i];
+
+      /* Attach DMA interrupt vectors */
+
+      irq_attach(chan->irq, gpdma_dmainterrupt, chan);
+
+      /* Disable the DMA channel */
+
+      gpdma_ch_disable(chan);
+
+      /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */
+
+      up_enable_irq(chan->irq);
+    }
+}
+
+/****************************************************************************
+ * Name: stm32_dmachannel
+ *
+ ****************************************************************************/
+
+DMA_HANDLE stm32_dmachannel(enum gpdma_ttype_e type)
+{
+  /* On the H5, peripherals can kind of be mapped to any number of different
+   * channels.
+   *
+   * P2M and M2P should be on channels with 8 byte FIFOs. GPDMA1/2 CH[0-3]
+   *
+   * Linear M2M should be on channels with 32 byte FIFOs. GPDMA1/2 CH[4-5]
+   * Some peripherals (e.g. OCTOSPI) can also use these for burst transfers.
+   *
+   * 2D addressed transfers should be on GPDMA1/2 CH[6-7]
+   *
+   * Note: Currently, only P2M and M2P modes are supported and implemented.
+   */
+
+  DMA_HANDLE handle = NULL;
+  irqstate_t flags;
+  int i;
+
+  /* Currently no support for M2M or 2D addressing modes.
+   * TODO: Remove when support is added!
+   */
+
+  DEBUGASSERT(type != GPDMA_TTYPE_M2M_LINEAR);
+  DEBUGASSERT(type != GPDMA_TTYPE_2D);
+
+  flags = enter_critical_section();
+
+  if (type == GPDMA_TTYPE_M2P || type == GPDMA_TTYPE_P2M)
+    {
+      for (i = 0; i < (sizeof(g_chan) / sizeof(struct gpdma_ch_s)); i++)
+        {
+          struct gpdma_ch_s *chan = &g_chan[i];
+
+          if (chan->free && chan->channel <= 3)
+            {
+              chan->free = false;
+              chan->type = type;
+              handle = (DMA_HANDLE)chan;
+              break;
+            }
+        }
+    }
+
+  leave_critical_section(flags);
+
+  if (handle == NULL)
+    {
+      /* Failed to allocate channel. */
+
+      dmainfo("No available DMA chan for transfer type=%" PRIu8 "\n",
+              type);
+    }
+
+  return handle;
+}
+
+/****************************************************************************
+ * Name: stm32_dmafree
+ *
+ * Description:
+ *   Release a DMA channel and unmap DMAMUX if required.
+ *
+ *   NOTE:  The 'handle' used in this argument must NEVER be used again
+ *   until stm32_dmachannel() is called again to re-gain access to the
+ *   channel.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   - The caller holds the DMA channel.
+ *   - There is no DMA in progress
+ *
+ ****************************************************************************/
+
+void stm32_dmafree(DMA_HANDLE handle)
+{
+  struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
+
+  DEBUGASSERT(handle != NULL);
+
+  chan->free = true;
+}
+
+/****************************************************************************
+ * Name: stm32_dmasetup
+ *
+ * Description:
+ *   Configure DMA before using
+ *
+ * Input Parameters:
+ *   TODO: Figure out what the input parameter needs to be!!! H7 and F7 have
+ *         very different implementations.
+ *
+ ****************************************************************************/
+
+void stm32_dmasetup(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg)
+{
+  struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
+
+  DEBUGASSERT(handle != NULL);
+
+  /* Store the configuration so it can be referenced later by start. */
+
+  chan->cfg = *cfg;
+
+  /* Drivers using DMA should manage channel usage. If a DMA request is not
+   * made on an error or an abort occurs, the driver should stop the DMA. If
+   * it fails to do so, we can not just hang waiting on the HW that will not
+   * change state.
+   *
+   * If at the end of waiting the HW is still not ready, there is a HW
+   * or software usage problem.
+   */
+
+  gpdma_ch_disable(chan);
+
+  /*  if ((gpdmach_getreg(chan, CH_CXCR_OFFSET) & GPDMA_CXCR_EN) != 0)
+   *    {
+   *      gpdma_ch_abort(chan);
+   *    }
+   */
+
+  /* Clear any unhandled flags from previous transactions */
+
+  /* gpdmach_putreg(chan, CH_CXFCR_OFFSET, 0x7f << 8); */
+
+  if (cfg->mode & GPDMACFG_MODE_CIRC)
+    {
+      gpdma_setup_circular(chan, cfg);
+    }
+  else
+    {
+      gpdma_setup(chan, cfg);
+    }
+}
+
+/****************************************************************************
+ * Name: stm32_dmastart
+ *
+ * Description:
+ *   Start the DMA transfer.
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *   - No DMA in progress
+ *
+ ****************************************************************************/
+
+void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
+                    bool half)
+{
+  struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
+  uint32_t cr;
+
+  DEBUGASSERT(handle != NULL);
+
+  /* Save the callback info. This will be invoked when the DMA completes */
+
+  chan->callback = callback;
+  chan->arg = arg;
+
+  /* Activate channel by setting ENABLE bin in the GPDMA_CXCR register.
+   * As soon as the channel is enabled, it can serve any DMA request from the
+   * peripheral connected to the stream.
+   */
+
+  cr = gpdmach_getreg(chan, CH_CXCR_OFFSET);
+  cr |= GPDMA_CXCR_EN;
+
+  /* In normal mode, interrupt at either half or full completion. In circular
+   * mode, always interrupt on wrap and optionally interrupt at halfway.
+   */
+
+  if (chan->cfg.mode & (GPDMACFG_MODE_CIRC))
+    {
+      /* In circular mode, when transfer completes it resets and starts
+       * again. The transfer-complete interrupt is thus always enabled, and
+       * the half-complete interrupt can be used to determine when the buffer
+       * is half-full.
+       */
+
+      cr |= ((half ? GPDMA_CXCR_HTIE : 0) |
+                          GPDMA_CXCR_TCIE |
+                          GPDMA_CXCR_DTEIE);
+    }
+  else
+    {
+      /* Once half of the bytes are transferred, the half-transfer flag
+       * (HTIF) is set and an interrupt is generated if the
+       * Half-Transfer Interrupt Enable bit (HTIE) is set. At the end of the
+       * transfer, the Transfer Complete Flag (TCIF) is set and an interrupt
+       * is generated if the Transfer Complete Interrupt Enable bit (TCIE) is
+       * set.
+       */
+
+      cr |= (half ? (GPDMA_CXCR_HTIE | GPDMA_CXCR_DTEIE) :
+                    (GPDMA_CXCR_TCIE | GPDMA_CXCR_DTEIE));
+    }
+
+  gpdmach_putreg(chan, CH_CXCR_OFFSET, cr);
+}
+
+/****************************************************************************
+ * Name: stm32_dmastop
+ *
+ * Description:
+ *   Cancel the DMA. After stm32_dmastop() is called, the DMA channel is
+ *   reset and stm32_dmasetup() must be called before stm32_dmastart() can be
+ *   called again.
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+void stm32_dmastop(DMA_HANDLE handle)
+{
+  struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
+  gpdma_ch_disable(chan);
+
+  /* gpdma_ch_abort(chan); */
+}
+
+#ifdef CONFIG_STM32H5_DMACAPABLE
+/****************************************************************************
+ * Name: stm32_dmacapable
+ *
+ * Description:
+ *   Check if the DMA controller can transfer data to/from given memory
+ *   address. This depends on the internal connections in the ARM bus matrix
+ *   of the processor. Note that this only applies to memory addresses, it
+ *   will return false for any peripheral address.
+ *
+ * Input Parameters:
+ *   cfg - DMA transfer configuration
+ *
+ * Returned Value:
+ *   True, if transfer is possible.
+ *
+ * NOTE: No implementation yet.
+ *
+ ****************************************************************************/
+
+bool stm32_dmacapable(DMA_HANDLE handle, stm32_gpdma_cfg_s *cfg)
+{
+# warning "stm32_dma_capable not implemented yet"
+  return false;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_DMA_INFO
+/****************************************************************************
+ * Name: stm32_dmadump
+ *
+ * Description:
+ *   Dump previously sampled DMA register contents
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ * NOTE: No implementation yet.
+ *
+ ****************************************************************************/
+
+static void stm32_dmadump(DMA_HANDLE handle, const char *msg)
+{
+#  warning "stm32_dma_dump not implemented yet!"
+}
+#endif
+
+#ifdef CONFIG_DEBUG_DMA_INFO
+/****************************************************************************
+ * Name: stm32_dmasample
+ *
+ * Description:
+ *   Sample DMA register contents
+ *
+ * Input Parameters:
+ *   TODO: Figure these out!! Not sure if I need the struct like F7 or not?
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs)
+{
+  #warning "stm32_dmasample() not implemented yet!"
+}
+#endif
\ No newline at end of file
diff --git a/arch/arm/src/stm32h5/stm32_dma.h b/arch/arm/src/stm32h5/stm32_dma.h
index abdaa2e81ef..63e554dca2b 100644
--- a/arch/arm/src/stm32h5/stm32_dma.h
+++ b/arch/arm/src/stm32h5/stm32_dma.h
@@ -30,12 +30,150 @@
 #include <nuttx/config.h>
 #include <sys/types.h>
 
+#include <stdint.h>
+
 #include "hardware/stm32_gpdma.h"
 
+#ifdef CONFIG_DEBUG_DMA_INFO
+#  error "CONFIG_DEBUG_DMA_INFO not yet implemented."
+#  undef CONFIG_DEBUG_DMA_INFO
+#endif
+
+#ifdef CONFIG_STM32H5_DMACAPABLE
+#  error "CONFIG_STM32H5_DMACAPABLE not yet implemented."
+#  undef CONFIG_STM32H5_DMACAPABLE
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* These definitions provide the bit encoding of the 'status' parameter
+ * passed to the DMA callback function (see dma_callback_t).
+ */
+
+#define DMA_STATUS_TCF        (1 << 0) /* Transfer Complete */
+#define DMA_STATUS_HTF        (1 << 1) /* Half Transfer */
+#define DMA_STATUS_DTEF       (1 << 2) /* Data transfer error */
+#define DMA_STATUS_ULEF       (1 << 3) /* Update link transfer error */
+#define DMA_STATUS_USEF       (1 << 4) /* User setting error */
+#define DMA_STATUS_SUSPF      (1 << 5) /* Completed suspension flag */
+#define DMA_STATUS_TOF        (1 << 6) /* Trigger overrun flag */
+
+#define DMA_STATUS_ERROR      (DMA_STATUS_DTEF | DMA_STATUS_ULEF | 
DMA_STATUS_USEF | DMA_STATUS_TOF)
+#define DMA_STATUS_SUCCESS    (DMA_STATUS_TCF | DMA_STATUS_HTEF)
+
+/* GPDMA Mode Flags: WARNING!! NOT YET IMPLEMENTED! */
+
+#define GPDMACFG_MODE_CIRC    (1 << 0)  /* Enable Circular mode */
+#define GPDMACFG_MODE_PFC     (1 << 1)  /* Enable Peripheral flow control */
+#define GPDMACFG_MODE_DB      (1 << 2)  /* Enable Double buffer mode */
+
+/* Channel priority level
+ * Refer to PRIO field in GPDMA_CxCR register description (RM0481)
+ */
+
+#define GPDMACFG_PRIO_LL      (0)   /* Low priority, low weight */
+#define GPDMACFG_PRIO_LM      (1)   /* Low priority, mid weight */
+#define GPMDACFG_PRIO_LH      (2)   /* Low priority, high weight */
+#define GPDMACFG_PRIO_H       (3)   /* High priority */
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
+/* GPDMA transfer type enumeration */
+
+enum gpdma_ttype_e
+{
+  /* Peripheral-to-memory transfer */
+
+  GPDMA_TTYPE_P2M = 0,
+
+  /* Memory-to-peripheral transfer */
+
+  GPDMA_TTYPE_M2P,
+
+  /* Memory-to-memory transfer, linear addressing */
+
+  GPDMA_TTYPE_M2M_LINEAR,
+
+  /* 2D Addressing needed (NOT IMPLEMENTED YET) */
+
+  GPDMA_TTYPE_2D
+};
+
+#ifdef CONFIG_DEBUG_DMA_INFO
+struct stm32_gpdma_reg_s
+{
+  uint32_t cxlbar;
+  uint32_t cxfcr;
+  uint32_t cxsr;
+  uint32_t cxcr;
+  uint32_t cxtr1;
+  uint32_t cxtr2;
+  uint32_t cxbr1;
+  uint32_t cxsar;
+  uint32_t cxdar;
+  uint32_t cxtr3;
+  uint32_t cxbr2;
+  uint32_t cxllr;
+};
+#endif
+
+struct stm32_gpdma_cfg_s
+{
+  uint32_t src_addr;
+  uint32_t dest_addr;
+
+  /* CxTR1 register for specified channel. */
+
+  uint32_t tr1;
+
+  /* request: Accepts GPDMA_CXTR2_SWREQ, GPDMA_CXTR2_DREQ, and
+   * GPDMA_CXTR2_REQSEL(r) for r given by GPDMA_REQ_x
+   * macros defined in hardware/stm32h56x_dmasigmap.h
+   */
+
+  uint16_t request;
+
+  /* Number of transfers, in units of the data width
+   * specified in tr1.
+   */
+
+  uint16_t ntransfers;
+
+  /* Priority level: refer to GPDMACFG_PRIO defines above */
+
+  uint8_t  priority;
+
+  /* mode flags, refer to GPDMACFG_MODE_X defines above. */
+
+  uint8_t  mode;
+};
+
+/* DMA_HANDLE Provides an opaque reference that can be used to represent a
+ * DMA stream.
+ */
+
+typedef void *DMA_HANDLE;
+
+/* Description:
+ *   This is the type of the callback that is used to inform the user of the
+ *   completion of the DMA.  NOTE:  The DMA module does *NOT* perform any
+ *   cache operations.  It is the responsibility of the DMA client to
+ *   invalidate DMA buffers after completion of the DMA RX operations.
+ *
+ * Input Parameters:
+ *   handle - Refers to the DMA channel or stream
+ *   status - A bit encoded value that provides the completion status.  See
+ *            the DMA_STATUS_* definitions above.
+ *   arg    - A user-provided value that was provided when stm32_dmastart()
+ *            was called.
+ */
+
+typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg);
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -55,6 +193,175 @@ extern "C"
  * Public Function Prototypes
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: stm32_dmachannel
+ *
+ * Description:
+ *   Allocate a DMA channel based on provided transfer type. The driver will
+ *   return the first available DMA channel compatible with the transfer type
+ *
+ * Input Parameters:
+ *   type - Type of DMA transfer required
+ *
+ * Returned Value:
+ *   On success, this function returns a non-NULL, void* DMA channel handle.
+ *   NULL is returned on any failure.  This function can fail only if no DMA
+ *   channel is available.
+ *
+ * Assumptions:
+ *   - The caller does not hold he DMA channel.
+ *   - The caller can wait for the DMA channel to be freed if it is no
+ *     available.
+ *
+ ****************************************************************************/
+
+DMA_HANDLE stm32_dmachannel(enum gpdma_ttype_e type);
+
+/****************************************************************************
+ * Name: stm32_dmafree
+ *
+ * Description:
+ *   Release a DMA channel.
+ *
+ *   NOTE:  The 'handle' used in this argument must NEVER be used again
+ *   until stm32_dmachannel() is called again to re-gain access to the
+ *   channel.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   - The caller holds the DMA channel.
+ *   - There is no DMA in progress
+ *
+ ****************************************************************************/
+
+void stm32_dmafree(DMA_HANDLE handle);
+
+/****************************************************************************
+ * Name: stm32_dmasetup
+ *
+ * Description:
+ *   Configure DMA before using
+ *
+ * Input Parameters:
+ *   TODO: Figure out what the input parameter needs to be!!! H7 and F7 have
+ *         very different implementations.
+ *
+ ****************************************************************************/
+
+void stm32_dmasetup(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg);
+
+/****************************************************************************
+ * Name: stm32_dmastart
+ *
+ * Description:
+ *   Start the DMA transfer.  NOTE:  The DMA module does *NOT* perform any
+ *   cache operations.  It is the responsibility of the DMA client to clean
+ *   DMA buffers after starting of the DMA TX operations.
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *   - No DMA in progress
+ *
+ ****************************************************************************/
+
+void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg,
+                    bool half);
+
+/****************************************************************************
+ * Name: stm32_dmastop
+ *
+ * Description:
+ *   Cancel the DMA.  After stm32_dmastop() is called, the DMA channel is
+ *   reset and stm32_dmasetup() must be called before stm32_dmastart() can be
+ *   called again
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+void stm32_dmastop(DMA_HANDLE handle);
+
+/****************************************************************************
+ * Name: stm32_dmaresidual
+ *
+ * Description:
+ *   Returns the number of bytes remaining to be transferred
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+size_t stm32_dmaresidual(DMA_HANDLE handle);
+
+/****************************************************************************
+ * Name: stm32_dmacapable
+ *
+ * Description:
+ *   Check if the DMA controller can transfer data to/from given memory
+ *   address with the given configuration. This depends on the internal
+ *   connections in the ARM bus matrix of the processor. Note that this only
+ *   applies to memory addresses, it will return false for any peripheral
+ *   address.
+ *
+ * Input Parameters:
+ *
+ *   maddr - starting memory address
+ *   count - number of unit8 or uint16 or uint32 items as defined by MSIZE
+ *           of ccr.
+ *   ccr   - DMA stream configuration register
+ *
+ * Returned Value:
+ *   True, if transfer is possible.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32H5_DMACAPABLE
+bool stm32_dmacapable(DMA_HANDLE handle, struct stm32_gpdma_cfg_s *cfg);
+#else
+#  define stm32_dmacapable(handle, cfg) (true)
+#endif
+
+/****************************************************************************
+ * Name: stm32_dmasample
+ *
+ * Description:
+ *   Sample DMA register contents
+ *
+ * Input Parameters:
+ *   TODO: Figure these out!! Not sure if I need the struct like F7 or not?
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_DMA_INFO
+void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs);
+#else
+#  define stm32_dmasample(handle,regs)
+#endif
+
+/****************************************************************************
+ * Name: stm32_dmadump
+ *
+ * Description:
+ *   Dump previously sampled DMA register contents
+ *
+ * Assumptions:
+ *   - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_DMA_INFO
+void stm32_dmadump(DMA_HANDLE handle, const char *msg);
+#else
+#  define stm32_dmadump(handle,msg)
+#endif
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/arch/arm/src/stm32h5/stm32h5xx_rcc.c 
b/arch/arm/src/stm32h5/stm32h5xx_rcc.c
index a72f2b89d31..7421c9f75e8 100644
--- a/arch/arm/src/stm32h5/stm32h5xx_rcc.c
+++ b/arch/arm/src/stm32h5/stm32h5xx_rcc.c
@@ -89,13 +89,13 @@ static inline void rcc_enableahb1(void)
 
   regval = getreg32(STM32_RCC_AHB1ENR);
 
-#ifdef CONFIG_STM32H5_GPDMA1
+#ifdef CONFIG_STM32H5_DMA1
   /* DMA 1 clock enable */
 
   regval |= RCC_AHB1ENR_GPDMA1EN;
 #endif
 
-#ifdef CONFIG_STM32H5_GPDMA2
+#ifdef CONFIG_STM32H5_DMA2
   /* DMA 2 clock enable */
 
   regval |= RCC_AHB1ENR_GPDMA2EN;

Reply via email to