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 8def1764a4 arch/stm32h5: add basic ADC support
8def1764a4 is described below

commit 8def1764a4c66620c5629ff50dbd0250f1d037b9
Author: stbenn <[email protected]>
AuthorDate: Wed Nov 13 13:50:27 2024 -0600

    arch/stm32h5: add basic ADC support
    
    Adds ADC support with minimal feature set (no DMA or Timers etc). A new 
nucleo-h563zi configuration was added to
    provide easy testing with the adc example NSH addon.
    
    Fix Kconfig spacing to tabs
---
 arch/arm/src/stm32h5/Kconfig                       |  241 ++--
 arch/arm/src/stm32h5/Make.defs                     |    4 +
 arch/arm/src/stm32h5/hardware/stm32h56xxx_pinmap.h |   42 +
 arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h     |    2 +-
 arch/arm/src/stm32h5/stm32.h                       |    2 +
 arch/arm/src/stm32h5/stm32_adc.c                   | 1369 ++++++++++++++++++++
 .../arm/src/stm32h5/stm32_adc.h                    |  102 +-
 arch/arm/src/stm32h5/stm32h5xx_rcc.c               |    9 +
 .../stm32h5/nucleo-h563zi/configs/adc/defconfig    |   56 +
 boards/arm/stm32h5/nucleo-h563zi/include/board.h   |   22 +
 boards/arm/stm32h5/nucleo-h563zi/src/Makefile      |    4 +
 .../arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h  |   11 +
 .../src/{nucleo-h563zi.h => stm32_adc.c}           |  145 ++-
 .../arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c  |    8 +
 14 files changed, 1774 insertions(+), 243 deletions(-)

diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig
index e6425fda5a..177f7fbc00 100644
--- a/arch/arm/src/stm32h5/Kconfig
+++ b/arch/arm/src/stm32h5/Kconfig
@@ -30,7 +30,7 @@ endchoice # STM32 H5 Chip Selection
 config STM32H5_STM32H5XXXX
        bool
        default n
-        select ARCH_HAVE_FPU
+               select ARCH_HAVE_FPU
 
 config STM32H5_STM32H56XXX
        bool
@@ -64,12 +64,12 @@ choice
                that designates the FLASH size.
 
                        Designator  Size in KiB
-                            8          64
-                            B         128
-                            C         256
-                            E         512
-                            G        1024
-                            I        2048
+                                8          64
+                                B         128
+                                C         256
+                                E         512
+                                G        1024
+                                I        2048
 
                This configuration option defaults to using the configuration 
based on that designator
                or the default smaller size if there is no last character 
designator is present in the
@@ -198,6 +198,7 @@ menu "STM32H5 Peripheral Selection"
 # These "hidden" settings determine if a peripheral option is available
 # for the selected MCU
 
+
 config STM32H5_HAVE_ETHERNET
        bool
        default n
@@ -265,8 +266,22 @@ config STM32H5_USART
        bool
        default n
 
+config STM32H5_ADC
+  bool
+  default n
+
 # These are the peripheral selections proper
 
+config STM32H5_ADC1
+  bool "ADC1"
+  default n
+  select STM32H5_ADC
+
+config STM32H5_ADC2
+  bool "ADC2"
+  default n
+  select STM32H5_ADC
+
 config STM32H5_ETHMAC
        bool "Ethernet MAC"
        default n
@@ -367,8 +382,8 @@ config STM32H5_LPUART1
        select STM32H5_USART
 
 config STM32H5_I2C
-        bool
-        default n
+               bool
+               default n
 
 config STM32H5_I2C1
        bool "I2C1"
@@ -1092,119 +1107,119 @@ menu "I2C Configuration"
 menu "Clock Selection"
 
 choice
-        depends on STM32H5_I2C1
-        prompt "I2C1 Input Clock Selection"
-        default STM32H5_I2C1_CLK_PCLK1
+       depends on STM32H5_I2C1
+       prompt "I2C1 Input Clock Selection"
+       default STM32H5_I2C1_CLK_PCLK1
 config STM32H5_I2C1_CLK_CSI
-        bool "CSI"
+       bool "CSI"
 config STM32H5_I2C1_CLK_HSI
-        bool "HSI"
+       bool "HSI"
 config STM32H5_I2C1_CLK_PCLK1
-        bool "PCLK1"
+       bool "PCLK1"
 config STM32H5_I2C1_CLK_PLL3R
-        bool "PLL3R"
+       bool "PLL3R"
 endchoice
 choice
-        depends on STM32H5_I2C2
-        prompt "I2C2 Input Clock Selection"
-        default STM32H5_I2C2_CLK_PCLK1
+       depends on STM32H5_I2C2
+       prompt "I2C2 Input Clock Selection"
+       default STM32H5_I2C2_CLK_PCLK1
 config STM32H5_I2C2_CLK_CSI
-        bool "CSI"
+       bool "CSI"
 config STM32H5_I2C2_CLK_HSI
-        bool "HSI"
+       bool "HSI"
 config STM32H5_I2C2_CLK_PCLK1
-        bool "PCLK1"
+       bool "PCLK1"
 config STM32H5_I2C2_CLK_PLL3R
-        bool "PLL3R"
+       bool "PLL3R"
 endchoice
 choice
-        depends on STM32H5_I2C3
-        prompt "I2C3 Input Clock Selection"
-        default STM32H5_I2C3_CLK_PCLK3
+       depends on STM32H5_I2C3
+       prompt "I2C3 Input Clock Selection"
+       default STM32H5_I2C3_CLK_PCLK3
 config STM32H5_I2C3_CLK_CSI
-        bool "CSI"
+       bool "CSI"
 config STM32H5_I2C3_CLK_HSI
-        bool "HSI"
+       bool "HSI"
 config STM32H5_I2C3_CLK_PCLK3
-        bool "PCLK3"
+       bool "PCLK3"
 config STM32H5_I2C3_CLK_PLL3R
-        bool "PLL3R"
+       bool "PLL3R"
 endchoice
 choice
-        depends on STM32H5_I2C4
-        prompt "I2C4 Input Clock Selection"
-        default STM32H5_I2C4_CLK_PCLK3
+       depends on STM32H5_I2C4
+       prompt "I2C4 Input Clock Selection"
+       default STM32H5_I2C4_CLK_PCLK3
 config STM32H5_I2C4_CLK_CSI
-        bool "CSI"
+       bool "CSI"
 config STM32H5_I2C4_CLK_HSI
-        bool "HSI"
+       bool "HSI"
 config STM32H5_I2C4_CLK_PCLK3
-        bool "PCLK3"
+       bool "PCLK3"
 config STM32H5_I2C4_CLK_PLL3R
-        bool "PLL3R"
+       bool "PLL3R"
 endchoice
 
 endmenu
 
 menu "Rise/Fall Override"
 config STM32H5_I2C1_RF_OVERRIDE
-        bool "I2C1"
-        default n
-        depends on STM32H5_I2C1
+       bool "I2C1"
+       default n
+       depends on STM32H5_I2C1
 config STM32H5_I2C2_RF_OVERRIDE
-        bool "I2C2"
-        default n
-        depends on STM32H5_I2C2
+       bool "I2C2"
+       default n
+       depends on STM32H5_I2C2
 config STM32H5_I2C3_RF_OVERRIDE
-        bool "I2C3"
-        default n
-        depends on STM32H5_I2C3
+       bool "I2C3"
+       default n
+       depends on STM32H5_I2C3
 config STM32H5_I2C4_RF_OVERRIDE
-        bool "I2C4"
-        default n
-        depends on STM32H5_I2C4
+       bool "I2C4"
+       default n
+       depends on STM32H5_I2C4
 
 menu "Rise/Fall Values"
 config STM32H5_I2C1_RISE
-        int "I2C1 Rise Time (ns)"
-        range 0 1000
-        default 20
-        depends on STM32H5_I2C1_RF_OVERRIDE
+       int "I2C1 Rise Time (ns)"
+       range 0 1000
+       default 20
+       depends on STM32H5_I2C1_RF_OVERRIDE
 config STM32H5_I2C1_FALL
-        int "I2C1 Fall Time (ns)"
-        range 0 300
-        default 20
-        depends on STM32H5_I2C1_RF_OVERRIDE
+       int "I2C1 Fall Time (ns)"
+       range 0 300
+       default 20
+       depends on STM32H5_I2C1_RF_OVERRIDE
 config STM32H5_I2C2_RISE
-        int "I2C2 Rise Time (ns)"
-        range 0 1000
-        default 20
-        depends on STM32H5_I2C2_RF_OVERRIDE
+       int "I2C2 Rise Time (ns)"
+       range 0 1000
+       default 20
+       depends on STM32H5_I2C2_RF_OVERRIDE
 config STM32H5_I2C2_FALL
-        int "I2C2 Fall Time (ns)"
-        range 0 300
-        default 20
-        depends on STM32H5_I2C2_RF_OVERRIDE
+       int "I2C2 Fall Time (ns)"
+       range 0 300
+       default 20
+       depends on STM32H5_I2C2_RF_OVERRIDE
 config STM32H5_I2C3_RISE
-        int "I2C3 Rise Time (ns)"
-        range 0 1000
-        default 20
-        depends on STM32H5_I2C3_RF_OVERRIDE
+       int "I2C3 Rise Time (ns)"
+       range 0 1000
+       default 20
+       depends on STM32H5_I2C3_RF_OVERRIDE
 config STM32H5_I2C3_FALL
-        int "I2C3 Fall Time (ns)"
-        range 0 300
-        default 20
-        depends on STM32H5_I2C3_RF_OVERRIDE
+       int "I2C3 Fall Time (ns)"
+       range 0 300
+       default 20
+       depends on STM32H5_I2C3_RF_OVERRIDE
 config STM32H5_I2C4_RISE
-        int "I2C4 Rise Time (ns)"
-        range 0 1000
-        default 20
-        depends on STM32H5_I2C4_RF_OVERRIDE
+       int "I2C4 Rise Time (ns)"
+       range 0 1000
+       default 20
+       depends on STM32H5_I2C4_RF_OVERRIDE
 config STM32H5_I2C4_FALL
-        int "I2C4 Fall Time (ns)"
-        range 0 300
-        default 20
-        depends on STM32H5_I2C4_RF_OVERRIDE
+       int "I2C4 Fall Time (ns)"
+       range 0 300
+       default 20
+       depends on STM32H5_I2C4_RF_OVERRIDE
 endmenu
 endmenu
 
@@ -1212,51 +1227,51 @@ menu "Filtering"
 
 menu "Digital Filters"
 config STM32H5_I2C1_DNF
-        int "I2C1 Digital Noise Filter"
-        range 0 15
-        default 0
-        depends on STM32H5_I2C1
+       int "I2C1 Digital Noise Filter"
+       range 0 15
+       default 0
+       depends on STM32H5_I2C1
 config STM32H5_I2C2_DNF
-        int "I2C2 Digital Noise Filter"
-        range 0 15
-        default 0
-        depends on STM32H5_I2C2
+       int "I2C2 Digital Noise Filter"
+       range 0 15
+       default 0
+       depends on STM32H5_I2C2
 config STM32H5_I2C3_DNF
-        int "I2C3 Digital Noise Filter"
-        range 0 15
-        default 0
-        depends on STM32H5_I2C3
+       int "I2C3 Digital Noise Filter"
+       range 0 15
+       default 0
+       depends on STM32H5_I2C3
 config STM32H5_I2C4_DNF
-        int "I2C4 Digital Noise Filter"
-        range 0 15
-        default 0
-        depends on STM32H5_I2C4
+       int "I2C4 Digital Noise Filter"
+       range 0 15
+       default 0
+       depends on STM32H5_I2C4
 endmenu
 
 menu "Analog Filters"
 config STM32H5_I2C1_ANFOFF
-        int "Turn off I2C1 Analog Filter (0=on, 1=off)"
-        default 1
-        range 0 1
-        depends on STM32H5_I2C1
+       int "Turn off I2C1 Analog Filter (0=on, 1=off)"
+       default 1
+       range 0 1
+       depends on STM32H5_I2C1
 
 config STM32H5_I2C2_ANFOFF
-        int "Turn off I2C2 Analog Filter (0=on, 1=off)"
-        default 1
-        range 0 1
-        depends on STM32H5_I2C2
+       int "Turn off I2C2 Analog Filter (0=on, 1=off)"
+       default 1
+       range 0 1
+       depends on STM32H5_I2C2
 
 config STM32H5_I2C3_ANFOFF
-        int "Turn off I2C3 Analog Filter (0=on, 1=off)"
-        default 1
-        range 0 1
-        depends on STM32H5_I2C3
+       int "Turn off I2C3 Analog Filter (0=on, 1=off)"
+       default 1
+       range 0 1
+       depends on STM32H5_I2C3
 
 config STM32H5_I2C4_ANFOFF
-        int "Turn off I2C4 Analog Filter (0=on, 1=off)"
-        default 1
-        range 0 1
-        depends on STM32H5_I2C4
+       int "Turn off I2C4 Analog Filter (0=on, 1=off)"
+       default 1
+       range 0 1
+       depends on STM32H5_I2C4
 endmenu
 
 endmenu
diff --git a/arch/arm/src/stm32h5/Make.defs b/arch/arm/src/stm32h5/Make.defs
index 1c3e72053f..f7ec1a3de7 100644
--- a/arch/arm/src/stm32h5/Make.defs
+++ b/arch/arm/src/stm32h5/Make.defs
@@ -48,6 +48,10 @@ ifeq ($(CONFIG_STM32H5_I2C),y)
 CHIP_CSRCS += stm32_i2c.c
 endif
 
+ifeq ($(CONFIG_ADC),y)
+CHIP_CSRCS += stm32_adc.c
+endif
+
 # Required chip type specific files
 
 ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y)
diff --git a/arch/arm/src/stm32h5/hardware/stm32h56xxx_pinmap.h 
b/arch/arm/src/stm32h5/hardware/stm32h56xxx_pinmap.h
index c857bb18e0..9a1cb9cd8c 100644
--- a/arch/arm/src/stm32h5/hardware/stm32h56xxx_pinmap.h
+++ b/arch/arm/src/stm32h5/hardware/stm32h56xxx_pinmap.h
@@ -196,5 +196,47 @@
 #define GPIO_LPUART1_CTS_1     (GPIO_ALT|GPIO_AF3|GPIO_PORTA|GPIO_PIN11)
 #define GPIO_LPUART1_RTS_DE_1  (GPIO_ALT|GPIO_AF3|GPIO_PORTA|GPIO_PIN12)
 
+/* ADC1 */
+
+#define GPIO_ADC1_IN0_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN0)
+#define GPIO_ADC1_IN1_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_ADC1_IN2_0   (GPIO_ANALOG | GPIO_PORTF | GPIO_PIN11)
+#define GPIO_ADC1_IN3_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN6)
+#define GPIO_ADC1_IN4_0   (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN4)
+#define GPIO_ADC1_IN5_0   (GPIO_ANALOG | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_ADC1_IN6_0   (GPIO_ANALOG | GPIO_PORTF | GPIO_PIN12)
+#define GPIO_ADC1_IN7_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_ADC1_IN8_0   (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN5)
+#define GPIO_ADC1_IN9_0   (GPIO_ANALOG | GPIO_PORTB | GPIO_PIN0)
+#define GPIO_ADC1_IN10_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN0)
+#define GPIO_ADC1_IN11_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN1)
+#define GPIO_ADC1_IN12_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN2)
+#define GPIO_ADC1_IN13_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN3)
+#define GPIO_ADC1_IN14_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_ADC1_IN15_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_ADC1_IN18_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN4)
+#define GPIO_ADC1_IN19_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN5)
+
+/* ADC2 */
+
+#define GPIO_ADC2_IN0_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN0)
+#define GPIO_ADC2_IN1_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_ADC2_IN2_0   (GPIO_ANALOG | GPIO_PORTF | GPIO_PIN13)
+#define GPIO_ADC2_IN3_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN6)
+#define GPIO_ADC2_IN4_0   (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN4)
+#define GPIO_ADC2_IN5_0   (GPIO_ANALOG | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_ADC2_IN6_0   (GPIO_ANALOG | GPIO_PORTF | GPIO_PIN14)
+#define GPIO_ADC2_IN7_0   (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_ADC2_IN8_0   (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN5)
+#define GPIO_ADC2_IN9_0   (GPIO_ANALOG | GPIO_PORTB | GPIO_PIN0)
+#define GPIO_ADC2_IN10_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN0)
+#define GPIO_ADC2_IN11_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN1)
+#define GPIO_ADC2_IN12_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN2)
+#define GPIO_ADC2_IN13_0  (GPIO_ANALOG | GPIO_PORTC | GPIO_PIN3)
+#define GPIO_ADC2_IN14_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_ADC2_IN15_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_ADC2_IN18_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN4)
+#define GPIO_ADC2_IN19_0  (GPIO_ANALOG | GPIO_PORTA | GPIO_PIN5)
+
 #endif /* CONFIG_STM32H5_STM32H563XX*/
 #endif /* __ARCH_ARM_SRC_STM32H5_HARDWARE_STM32H56XXX_PINMAP_H */
diff --git a/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h 
b/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h
index b5ced0a7a9..87ec024577 100644
--- a/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h
+++ b/arch/arm/src/stm32h5/hardware/stm32h5xxx_rcc.h
@@ -1130,7 +1130,7 @@
 #  define RCC_CCIPR5_ADCDACSEL_PLL2RCK    (2 << RCC_CCIPR5_ADCDACSEL_SHIFT)
 #  define RCC_CCIPR5_ADCDACSEL_HSECK      (3 << RCC_CCIPR5_ADCDACSEL_SHIFT)
 #  define RCC_CCIPR5_ADCDACSEL_HSEKERCK   (4 << RCC_CCIPR5_ADCDACSEL_SHIFT)
-#  define RCC_CCIPR5_ADCDACSEL_CSIKERCK   (4 << RCC_CCIPR5_ADCDACSEL_SHIFT)
+#  define RCC_CCIPR5_ADCDACSEL_CSIKERCK   (5 << RCC_CCIPR5_ADCDACSEL_SHIFT)
 
 #define RCC_CCIPR5_DACSEL                 (1 << 3)
 
diff --git a/arch/arm/src/stm32h5/stm32.h b/arch/arm/src/stm32h5/stm32.h
index d1c0b94c9f..13aa6742bc 100644
--- a/arch/arm/src/stm32h5/stm32.h
+++ b/arch/arm/src/stm32h5/stm32.h
@@ -43,4 +43,6 @@
 #include "stm32_uart.h"
 #include "stm32_lowputc.h"
 #include "stm32_i2c.h"
+#include "stm32_adc.h"
+
 #endif /* __ARCH_ARM_SRC_STM32H5_STM32_H */
diff --git a/arch/arm/src/stm32h5/stm32_adc.c b/arch/arm/src/stm32h5/stm32_adc.c
new file mode 100644
index 0000000000..8d52d1c86d
--- /dev/null
+++ b/arch/arm/src/stm32h5/stm32_adc.c
@@ -0,0 +1,1369 @@
+/****************************************************************************
+ * arch/arm/src/stm32h5/stm32_adc.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 <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+#include <string.h>
+
+#include <arch/board/board.h>
+#include <nuttx/nuttx.h>
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/analog/adc.h>
+#include <nuttx/analog/ioctl.h>
+#include <nuttx/power/pm.h>
+
+#include "chip.h"
+#include "stm32_adc.h"
+#include "stm32_rcc.h"
+
+#ifdef CONFIG_ADC
+
+#if defined(CONFIG_STM32H5_ADC1) || defined(CONFIG_STM32H5_ADC2)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_PM
+#pragma message "Power Management not implemented in H5 ADC driver. "
+#endif
+
+/* ADC Channels/DMA *********************************************************/
+
+#define ADC_MAX_CHANNELS_DMA   20
+#define ADC_MAX_CHANNELS_NODMA 20
+
+#ifdef ADC_HAVE_DMA
+#  error "STM32H5 ADC does not have DMA support."
+#  undef ADC_HAVE_DMA
+#endif
+
+#ifdef ADC_HAVE_DMA
+#  define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_DMA
+#else
+#  define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_NODMA
+#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) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP2_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP3_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP4_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP5_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP6_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP7_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP8_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR1_SMP9_SHIFT))
+#define ADC_SMPR2_DEFAULT   ((ADC_SMPR_DEFAULT << ADC_SMPR2_SMP10_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP11_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP12_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP13_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP14_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP15_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP16_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP17_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP18_SHIFT) | \
+                             (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP19_SHIFT))
+
+#define ADC_EXTERNAL_CHAN_MAX  18
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes the state of one ADC block */
+
+struct stm32_dev_s
+{
+  const struct adc_callback_s *cb;
+  uint8_t irq;          /* Interrupt generated by this ADC block */
+  uint8_t nchannels;    /* Number of channels */
+  uint8_t cchannels;    /* Number of configured channels */
+  uint8_t intf;         /* ADC interface number */
+  uint8_t current;      /* Current ADC channel being converted */
+#ifdef ADC_HAVE_DMA
+  uint8_t dmachan;      /* DMA channel needed by this ADC */
+  bool    hasdma;       /* True: This ADC supports DMA */
+#endif
+#ifdef ADC_HAVE_TIMER
+  uint8_t trigger;      /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3,
+                         * 3=CC4, 4=TRGO, 5=TRGO2 */
+#endif
+  xcpt_t   isr;         /* Interrupt handler for this ADC block */
+  uint32_t base;        /* Base address of registers unique to this ADC
+                         * block */
+  uint32_t mbase;       /* Base address of master ADC (allows for access to
+                         * shared common registers) */
+  bool     initialized; /* Keeps track of the initialization status of the ADC 
*/
+#ifdef ADC_HAVE_TIMER
+  uint32_t tbase;       /* Base address of timer used by this ADC block */
+  uint32_t trcc_enr;    /* RCC ENR Register */
+  uint32_t trcc_en;     /* RCC EN Bit in ENR Register */
+  uint32_t extsel;      /* EXTSEL value used by this ADC block */
+  uint32_t pclck;       /* The PCLK frequency that drives this timer */
+  uint32_t freq;        /* The desired frequency of conversions */
+#endif
+
+#ifdef CONFIG_PM
+  struct pm_callback_s pm_callback;
+#endif
+
+#ifdef ADC_HAVE_DMA
+  DMA_HANDLE dma;       /* Allocated DMA channel */
+
+  /* DMA transfer buffer */
+
+  uint16_t dmabuffer[ADC_MAX_SAMPLES];
+#endif
+
+  /* List of selected ADC channels to sample */
+
+  uint8_t  chanlist[ADC_MAX_SAMPLES];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* ADC Register access */
+
+static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset);
+static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value);
+static void adc_modifyreg(struct stm32_dev_s *priv, int offset,
+                              uint32_t clrbits, uint32_t setbits);
+
+/* ADC Miscellaneous Helpers */
+
+static void adc_rccreset(struct stm32_dev_s *priv, bool reset);
+static void adc_setupclock(struct stm32_dev_s *priv);
+static void adc_enable(struct stm32_dev_s *priv);
+static uint32_t adc_sqrbits(struct stm32_dev_s *priv, int first,
+                            int last, int offset);
+static int  adc_set_ch(struct adc_dev_s *dev, uint8_t ch);
+static bool adc_internal(struct stm32_dev_s * priv, uint32_t *adc_ccr);
+static void adc_startconv(struct stm32_dev_s *priv, bool enable);
+static void adc_wdog_enable(struct stm32_dev_s *priv);
+
+/* ADC Interrupt Handler */
+
+static int adc_interrupt(struct adc_dev_s *dev, uint32_t regval);
+static int adc12_interrupt(int irq, void *context, void *arg);
+
+/* ADC Driver Methods */
+
+static int  adc_bind(struct adc_dev_s *dev,
+                     const struct adc_callback_s *callback);
+static void adc_reset(struct adc_dev_s *dev);
+static int  adc_setup(struct adc_dev_s *dev);
+static void adc_shutdown(struct adc_dev_s *dev);
+static void adc_rxint(struct adc_dev_s *dev, bool enable);
+static int  adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* ADC interface operations */
+
+static const struct adc_ops_s g_adcops =
+{
+  .ao_bind      = adc_bind,
+  .ao_reset     = adc_reset,
+  .ao_setup     = adc_setup,
+  .ao_shutdown  = adc_shutdown,
+  .ao_rxint     = adc_rxint,
+  .ao_ioctl     = adc_ioctl,
+};
+
+/* ADC1 state */
+
+#ifdef CONFIG_STM32H5_ADC1
+static struct stm32_dev_s g_adcpriv1 =
+{
+  .irq         = STM32_IRQ_ADC1,
+  .isr         = adc12_interrupt,
+  .intf        = 1,
+  .base        = STM32_ADC1_BASE,
+  .mbase       = STM32_ADC1_BASE,
+  .initialized = false,
+};
+
+static struct adc_dev_s g_adcdev1 =
+{
+  .ad_ops       = &g_adcops,
+  .ad_priv      = &g_adcpriv1,
+};
+#endif
+
+/* ADC2 state */
+
+#ifdef CONFIG_STM32H5_ADC2
+static struct stm32_dev_s g_adcpriv2 =
+{
+  .irq         = STM32_IRQ_ADC2,
+  .isr         = adc12_interrupt,
+  .intf        = 2,
+  .base        = STM32_ADC2_BASE,
+  .mbase       = STM32_ADC2_BASE,
+  .initialized = false,
+};
+
+static struct adc_dev_s g_adcdev2 =
+{
+  .ad_ops       = &g_adcops,
+  .ad_priv      = &g_adcpriv2,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: adc_getreg
+ *
+ * Description:
+ *   Read the value of an ADC register.
+ *
+ * Input Parameters:
+ *   priv   - A reference to the ADC block status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   The current contents of the specified register
+ *
+ ****************************************************************************/
+
+static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset)
+{
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: adc_putreg
+ *
+ * Description:
+ *   Write a value to an ADC register.
+ *
+ * Input Parameters:
+ *   priv   - A reference to the ADC block status
+ *   offset - The offset to the register to write to
+ *   value  - The value to write to the register
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void adc_putreg(struct stm32_dev_s *priv, int offset,
+                       uint32_t value)
+{
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: adc_modifyreg
+ *
+ * Description:
+ *   Modify the value of an ADC register (not atomic).
+ *
+ * Input Parameters:
+ *   priv    - A reference to the ADC block status
+ *   offset  - The offset to the register to modify
+ *   clrbits - The bits to clear
+ *   setbits - The bits to set
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void adc_modifyreg(struct stm32_dev_s *priv, int offset,
+                          uint32_t clrbits, uint32_t setbits)
+{
+  adc_putreg(priv, offset, (adc_getreg(priv, offset) & ~clrbits) | setbits);
+}
+
+/****************************************************************************
+ * Name: adc_getregm
+ *
+ * Description:
+ *   Read the value of an ADC register from the associated ADC master.
+ *
+ * Input Parameters:
+ *   priv   - A reference to the ADC block status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   The current contents of the specified register in the ADC master.
+ *
+ ****************************************************************************/
+
+static uint32_t adc_getregm(struct stm32_dev_s *priv, int offset)
+{
+  return getreg32(priv->mbase + offset);
+}
+
+/****************************************************************************
+ * Name: adc_putregm
+ *
+ * Description:
+ *   Write a value to an ADC register in the associated ADC master.
+ *
+ * Input Parameters:
+ *   priv   - A reference to the ADC block status
+ *   offset - The offset to the register to write to
+ *   value  - The value to write to the register
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void adc_putregm(struct stm32_dev_s *priv, int offset,
+                        uint32_t value)
+{
+  putreg32(value, priv->mbase + offset);
+}
+
+/****************************************************************************
+ * Name: adc_modifyregm
+ *
+ * Description:
+ *   Modify the value of an ADC register in the associated ADC master
+ *  (not atomic).
+ *
+ * Input Parameters:
+ *   priv    - A reference to the ADC block status
+ *   offset  - The offset to the register to modify
+ *   clrbits - The bits to clear
+ *   setbits - The bits to set
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void adc_modifyregm(struct stm32_dev_s *priv, int offset,
+                           uint32_t clrbits, uint32_t setbits)
+{
+  adc_putregm(priv, offset,
+              (adc_getregm(priv, offset) & ~clrbits) | setbits);
+}
+
+/****************************************************************************
+ * Name: adc_enable
+ *
+ * Description:
+ *   Enables the specified ADC peripheral.
+ *
+ * Input Parameters:
+ *   priv - A reference to the ADC block status
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_enable(struct stm32_dev_s *priv)
+{
+  uint32_t regval;
+
+  regval = adc_getreg(priv, STM32_ADC_CR_OFFSET);
+
+  /* Exit deep power down mode and enable voltage regulator */
+
+  regval &= ~ADC_CR_DEEPPWD;
+  adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);
+
+  regval = adc_getreg(priv, STM32_ADC_CR_OFFSET);
+  regval |= ADC_CR_ADVREGEN;
+  adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);
+
+  /* Wait for voltage regulator to power up */
+
+  up_udelay(20);
+
+  /* Enable ADC calibration. ADCALDIF == 0 so this is only for
+   * single-ended conversions, not for differential ones.
+   */
+
+  regval |= ADC_CR_ADCAL;
+  adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);
+
+  /* Wait for calibration to complete */
+
+  while (adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_ADCAL);
+
+  /* Enable ADC
+   * Note: ADEN bit cannot be set during ADCAL=1 and 4 ADC clock cycle
+   * after the ADCAL bit is cleared by hardware. If we are using SYSCLK
+   * as ADC clock source, this is the same as time taken to execute 4
+   * ARM instructions.
+   */
+
+  regval  = adc_getreg(priv, STM32_ADC_CR_OFFSET);
+  regval |= ADC_CR_ADEN;
+  adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);
+
+  /* Wait for hardware to be ready for conversions */
+
+  while (!(adc_getreg(priv, STM32_ADC_ISR_OFFSET) & ADC_INT_ADRDY));
+
+  adc_modifyreg(priv, STM32_ADC_ISR_OFFSET, 0, ADC_INT_ADRDY);
+}
+
+/****************************************************************************
+ * Name: adc_bind
+ *
+ * Description:
+ *   Bind the upper-half driver callbacks to the lower-half implementation.
+ *   This must be called early in order to receive ADC event notifications.
+ *
+ ****************************************************************************/
+
+static int adc_bind(struct adc_dev_s *dev,
+                    const struct adc_callback_s *callback)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  DEBUGASSERT(priv != NULL);
+  priv->cb = callback;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: adc_wdog_enable
+ *
+ * Description:
+ *   Enable analog watchdog 1. Sets continuous and overrun mode. Turns on
+ *   AWD1 interrupt and disables end of conversion interrupt.
+ ****************************************************************************/
+
+static void adc_wdog_enable(struct stm32_dev_s *priv)
+{
+  uint32_t regval;
+
+  /* Initialize analog watchdog */
+
+  regval = adc_getreg(priv, STM32_ADC_CFGR_OFFSET);
+  regval |= ADC_CFGR_AWD1EN | ADC_CFGR_CONT | ADC_CFGR_OVRMOD;
+  adc_putreg(priv, STM32_ADC_CFGR_OFFSET, regval);
+
+  /* Switch to analog watchdog interrupt */
+
+  regval = adc_getreg(priv, STM32_ADC_IER_OFFSET);
+  regval |= ADC_INT_AWD1;
+  regval &= ~ADC_INT_EOC;
+  adc_putreg(priv, STM32_ADC_IER_OFFSET, regval);
+}
+
+/****************************************************************************
+ * Name: adc_startconv
+ *
+ * Description:
+ *   Start (or stop) the ADC conversion process
+ *
+ * Input Parameters:
+ *   priv - A reference to the ADC block status
+ *   enable - True: Start conversion
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_startconv(struct stm32_dev_s *priv, bool enable)
+{
+  uint32_t regval;
+
+  ainfo("enable: %d\n", enable ? 1 : 0);
+
+  regval = adc_getreg(priv, STM32_ADC_CR_OFFSET);
+  if (enable)
+    {
+      /* Start conversion of regular channels */
+
+      regval |= ADC_CR_ADSTART;
+    }
+  else
+    {
+      /* Disable the conversion of regular channels */
+
+      regval |= ADC_CR_ADSTP;
+    }
+
+  adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);
+}
+
+/****************************************************************************
+ * Name: adc_rccreset
+ *
+ * Description:
+ *   Deinitializes the ADCx peripheral registers to their default
+ *   reset values. It could set all the ADCs configured.
+ *
+ * Input Parameters:
+ *   priv - A reference to the ADC block status
+ *   reset - Condition, set or reset
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_rccreset(struct stm32_dev_s *priv, bool reset)
+{
+  irqstate_t flags;
+  uint32_t regval;
+
+  /* First must disable interrupts because the AHB2RSTR register is used by
+   * several different drivers.
+   */
+
+  flags = enter_critical_section();
+
+  /* Set or clear the adc reset bit in the AHB2 reset register */
+
+  regval = getreg32(STM32_RCC_AHB2RSTR);
+
+  if (reset)
+    {
+      regval |= RCC_AHB2RSTR_ADCRST;
+    }
+  else
+    {
+      regval &= ~RCC_AHB2RSTR_ADCRST;
+    }
+
+  putreg32(regval, STM32_RCC_AHB2RSTR);
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: adc_shutdown
+ *
+ * Description:
+ *   Disable the ADC.  This method is called when the ADC device is closed.
+ *   This method reverses the operation the setup method.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_shutdown(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  /* Stop the ADC */
+
+  adc_startconv(priv, false);
+
+  /* Disable ADC interrupts and detach the ADC interrupt handler */
+
+  up_disable_irq(priv->irq);
+  irq_detach(priv->irq);
+
+  /* Disable and reset the ADC module */
+
+  adc_reset(dev);
+
+  priv->initialized = false;
+}
+
+/****************************************************************************
+ * Name: adc_rxint
+ *
+ * Description:
+ *   Call to enable or disable RX interrupts.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_rxint(struct adc_dev_s *dev, bool enable)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t regval;
+
+  ainfo("intf: %d enable: %d\n", priv->intf, enable ? 1 : 0);
+
+  regval = adc_getreg(priv, STM32_ADC_IER_OFFSET);
+  if (enable)
+    {
+      /* Enable end of conversion and overrun interrupts */
+
+      regval |= ADC_INT_EOC | ADC_INT_OVR;
+    }
+  else
+    {
+      /* Disable all interrupts */
+
+      regval &= ~ADC_INT_MASK;
+    }
+
+  adc_putreg(priv, STM32_ADC_IER_OFFSET, regval);
+}
+
+/****************************************************************************
+ * Name: adc_setupclock
+ *
+ ****************************************************************************/
+
+static void adc_setupclock(struct stm32_dev_s *priv)
+{
+  uint32_t max_clock = 75000000;
+  uint32_t setbits = 0;
+
+#ifndef STM32_ADC_CLK_FREQUENCY
+#error "board.h must define STM32_ADC_CLK_FREQUENCY"
+#endif
+
+  if (STM32_ADC_CLK_FREQUENCY <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_NOT_DIV;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 2 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV2;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 4 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV4;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 6 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV6;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 8 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV8;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 10 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV10;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 12 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV12;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 16 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV16;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 32 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV32;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 64 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV64;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 128 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV128;
+    }
+  else if (STM32_ADC_CLK_FREQUENCY / 256 <= max_clock)
+    {
+      setbits = ADC_CCR_PRESC_DIV256;
+    }
+  else
+    {
+      aerr("ERROR: source clock too high\n");
+    }
+
+  adc_modifyreg(priv, STM32_ADC_CCR_OFFSET, ADC_CCR_PRESC_MASK, setbits);
+}
+
+/****************************************************************************
+ * Name: adc_reset
+ *
+ * Description:
+ *   Reset the ADC device.  Called early to initialize the hardware. This
+ *   is called, before adc_setup() and on error conditions.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_reset(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  ainfo("intf: ADC%d\n", priv->intf);
+
+  /* Enable ADC reset state */
+
+  adc_rccreset(priv, true);
+
+  /* Release ADC from reset state */
+
+  adc_rccreset(priv, false);
+}
+
+/****************************************************************************
+ * Name: adc_setup
+ *
+ * Description:
+ *   Configure the ADC. This method is called the first time that the ADC
+ *   device is opened.  This will occur when the port is first opened.
+ *   This setup includes configuring and attaching ADC interrupts.
+ *   Interrupts are all disabled upon return.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int adc_setup(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  int ret;
+  irqstate_t flags;
+  uint32_t clrbits;
+  uint32_t setbits;
+
+  /* Attach the ADC interrupt */
+
+  ret = irq_attach(priv->irq, priv->isr, NULL);
+  if (ret < 0)
+    {
+      ainfo("irq_attach failed: %d\n", ret);
+      return ret;
+    }
+
+  flags = enter_critical_section();
+
+  /* Make sure that the ADC device is in the powered up, reset state.
+   * Since reset is shared between ADC1 and ADC2, don't reset one if the
+   * other has already been reset. (We only need to worry about this if both
+   * ADC1 and ADC2 are enabled.)
+   */
+
+#if defined(CONFIG_STM32H5_ADC1) && defined(CONFIG_STM32H5_ADC2)
+  if ((dev == &g_adcdev1 &&
+      !((struct stm32_dev_s *)g_adcdev2.ad_priv)->initialized) ||
+     (dev == &g_adcdev2 &&
+      !((struct stm32_dev_s *)g_adcdev1.ad_priv)->initialized))
+#endif
+    {
+      adc_reset(dev);
+    }
+
+  /* Initialize the same sample time for each ADC.
+   * During sample cycles channel selection bits must remain unchanged.
+   */
+
+  adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, ADC_SMPR1_DEFAULT);
+  adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, ADC_SMPR2_DEFAULT);
+
+  /* Set the resolution of the conversion. */
+
+  clrbits = ADC_CFGR_RES_MASK | ADC_CFGR_DMACFG | ADC_CFGR_DMAEN;
+  setbits = ADC_CFGR_RES_12BIT;
+
+#ifdef ADC_HAVE_DMA
+  if (priv->hasdma)
+    {
+      /* Enable One shot DMA */
+
+      setbits |= ADC_CFGR_DMAEN;
+    }
+#endif
+
+  /* Disable continuous mode */
+
+  clrbits |= ADC_CFGR_CONT;
+
+  /* Disable external trigger for regular channels */
+
+  clrbits |= ADC_CFGR_EXTEN_MASK;
+  setbits |= ADC_CFGR_EXTEN_NONE;
+
+  /* Set overrun mode to preserve the data register */
+
+  clrbits |= ADC_CFGR_OVRMOD;
+
+  /* Set CFGR configuration */
+
+  adc_modifyreg(priv, STM32_ADC_CFGR_OFFSET, clrbits, setbits);
+
+  /* Set CFGR2 configuration to align right no oversample */
+
+  clrbits = ADC_CFGR2_ROVSE | ADC_CFGR2_JOVSE | ADC_CFGR2_OVSS_MASK \
+          | ADC_CFGR2_OVSR_MASK;
+  setbits = 0;
+
+  adc_modifyreg(priv, STM32_ADC_CFGR2_OFFSET, clrbits, setbits);
+
+  /* Configuration of the channel conversions */
+
+  adc_set_ch(dev, 0);
+
+  /* ADC CCR configuration */
+
+  clrbits = ADC_CCR_PRESC_MASK | ADC_CCR_VREFEN |
+            ADC_CCR_TSEN | ADC_CCR_VBATEN;
+  setbits = ADC_CCR_CKMODE_ASYCH;
+
+  adc_internal(priv, &setbits);
+
+  adc_modifyregm(priv, STM32_ADC_CCR_OFFSET, clrbits, setbits);
+
+  adc_setupclock(priv);
+
+#ifdef ADC_HAVE_DMA
+
+  /* Enable DMA */
+
+  if (priv->hasdma)
+    {
+      /* Stop and free DMA if it was started before */
+
+      if (priv->dma != NULL)
+        {
+          stm32_dmastop(priv->dma);
+          stm32_dmafree(priv->dma);
+        }
+
+      priv->dma = stm32_dmachannel(priv->dmachan);
+
+      stm32_dmasetup(priv->dma,
+                       priv->base + STM32_ADC_DR_OFFSET,
+                       (uint32_t)priv->dmabuffer,
+                       priv->nchannels,
+                       ADC_DMA_CONTROL_WORD);
+
+      stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
+    }
+
+#endif
+
+  /* Set ADEN to wake up the ADC from Power Down. */
+
+  adc_enable(priv);
+
+#ifdef ADC_HAVE_TIMER
+  if (priv->tbase != 0)
+    {
+      ret = adc_timinit(priv);
+      if (ret < 0)
+        {
+          aerr("ERROR: adc_timinit failed: %d\n", ret);
+        }
+
+      adc_startconv(priv, ret < 0 ? false : true);
+    }
+#endif
+
+  leave_critical_section(flags);
+
+  ainfo("ISR:   0x%08" PRIx32 " CR:    0x%08" PRIx32 " "
+        "CFGR:  0x%08" PRIx32 " CFGR2: 0x%08" PRIx32 "\n",
+        adc_getreg(priv, STM32_ADC_ISR_OFFSET),
+        adc_getreg(priv, STM32_ADC_CR_OFFSET),
+        adc_getreg(priv, STM32_ADC_CFGR_OFFSET),
+        adc_getreg(priv, STM32_ADC_CFGR2_OFFSET));
+  ainfo("SQR1:  0x%08" PRIx32 " SQR2:  0x%08" PRIx32 " "
+        "SQR3:  0x%08" PRIx32 " SQR4:  0x%08" PRIx32 "\n",
+        adc_getreg(priv, STM32_ADC_SQR1_OFFSET),
+        adc_getreg(priv, STM32_ADC_SQR2_OFFSET),
+        adc_getreg(priv, STM32_ADC_SQR3_OFFSET),
+        adc_getreg(priv, STM32_ADC_SQR4_OFFSET));
+  ainfo("CCR:   0x%08" PRIx32 "\n", adc_getregm(priv, STM32_ADC_CCR_OFFSET));
+
+  /* Enable the ADC interrupt */
+
+  ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
+  up_enable_irq(priv->irq);
+
+  priv->initialized = true;
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: adc_sqrbits
+ ****************************************************************************/
+
+static uint32_t adc_sqrbits(struct stm32_dev_s *priv, int first,
+                            int last, int offset)
+{
+  uint32_t bits = 0;
+  int i;
+
+  for (i = first - 1;
+       i < priv->nchannels && i < last;
+       i++, offset += ADC_SQ_OFFSET)
+    {
+      bits |= (uint32_t)priv->chanlist[i] << offset;
+    }
+
+  return bits;
+}
+
+/****************************************************************************
+ * Name: adc_internal
+ ****************************************************************************/
+
+static bool adc_internal(struct stm32_dev_s * priv, uint32_t *adc_ccr)
+{
+  int i;
+  bool internal = false;
+
+  if (priv->intf == 3)
+    {
+      for (i = 0; i < priv->nchannels; i++)
+        {
+          if (priv->chanlist[i] > ADC_EXTERNAL_CHAN_MAX)
+            {
+              internal = true;
+              switch (priv->chanlist[i])
+                {
+                  case 17:
+                    *adc_ccr |= ADC_CCR_VBATEN;
+                    break;
+
+                  case 18:
+                    *adc_ccr |= ADC_CCR_TSEN;
+                    break;
+
+                  case 19:
+                     *adc_ccr |= ADC_CCR_VREFEN;
+                    break;
+                }
+            }
+        }
+    }
+
+  return internal;
+}
+
+/****************************************************************************
+ * Name: adc_set_ch
+ *
+ * Description:
+ *   Sets the ADC channel.
+ *
+ * Input Parameters:
+ *   dev - pointer to device structure used by the driver
+ *   ch  - ADC channel number + 1. 0 reserved for all configured channels
+ *
+ * Returned Value:
+ *   int - errno
+ *
+ ****************************************************************************/
+
+static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t bits;
+  int i;
+
+  if (ch == 0)
+    {
+      priv->current   = 0;
+      priv->nchannels = priv->cchannels;
+    }
+  else
+    {
+      for (i = 0; i < priv->cchannels && priv->chanlist[i] != ch - 1; i++);
+
+      if (i >= priv->cchannels)
+        {
+          return -ENODEV;
+        }
+
+      priv->current   = i;
+      priv->nchannels = 1;
+    }
+
+  DEBUGASSERT(priv->nchannels <= ADC_MAX_SAMPLES);
+
+  bits = adc_sqrbits(priv, ADC_SQR4_FIRST, ADC_SQR4_LAST,
+                     ADC_SQR4_SQ_OFFSET);
+  adc_modifyreg(priv, STM32_ADC_SQR4_OFFSET, ~ADC_SQR4_RESERVED, bits);
+
+  bits = adc_sqrbits(priv, ADC_SQR3_FIRST, ADC_SQR3_LAST,
+                     ADC_SQR3_SQ_OFFSET);
+  adc_modifyreg(priv, STM32_ADC_SQR3_OFFSET, ~ADC_SQR3_RESERVED, bits);
+
+  bits = adc_sqrbits(priv, ADC_SQR2_FIRST, ADC_SQR2_LAST,
+                     ADC_SQR2_SQ_OFFSET);
+  adc_modifyreg(priv, STM32_ADC_SQR2_OFFSET, ~ADC_SQR2_RESERVED, bits);
+
+  bits = ((uint32_t)priv->nchannels - 1) << ADC_SQR1_L_SHIFT |
+         adc_sqrbits(priv, ADC_SQR1_FIRST, ADC_SQR1_LAST,
+                     ADC_SQR1_SQ_OFFSET);
+  adc_modifyreg(priv, STM32_ADC_SQR1_OFFSET, ~ADC_SQR1_RESERVED, bits);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: adc_ioctl
+ *
+ * Description:
+ *   All ioctl calls will be routed through this method.
+ *
+ * Input Parameters:
+ *   dev - pointer to device structure used by the driver
+ *   cmd - command
+ *   arg - arguments passed with command
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t regval;
+  uint32_t tmp;
+  int ret = OK;
+
+  switch (cmd)
+    {
+      case ANIOC_TRIGGER:
+        {
+          adc_startconv(priv, true);
+        }
+        break;
+
+      case ANIOC_GET_NCHANNELS:
+        {
+          /* Return the number of configured channels */
+
+          ret = priv->cchannels;
+        }
+        break;
+
+      case ANIOC_WDOG_UPPER: /* Set watchdog upper threshold */
+        {
+          regval = adc_getreg(priv, STM32_ADC_TR1_OFFSET);
+
+          /* Verify new upper threshold greater than lower threshold */
+
+          tmp = (regval & ADC_TR1_LT1_MASK) >> ADC_TR1_LT1_SHIFT;
+          if (arg < tmp)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          /* Set the watchdog threshold register */
+
+          regval = ((arg << ADC_TR1_HT1_SHIFT) & ADC_TR1_HT1_MASK);
+          adc_putreg(priv, STM32_ADC_TR1_OFFSET, regval);
+
+          /* Ensure analog watchdog is enabled */
+
+          adc_wdog_enable(priv);
+        }
+        break;
+
+      case ANIOC_WDOG_LOWER: /* Set watchdog lower threshold */
+        {
+          regval = adc_getreg(priv, STM32_ADC_TR1_OFFSET);
+
+          /* Verify new lower threshold less than upper threshold */
+
+          tmp = (regval & ADC_TR1_HT1_MASK) >> ADC_TR1_HT1_SHIFT;
+          if (arg > tmp)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          /* Set the watchdog threshold register */
+
+          regval = ((arg << ADC_TR1_LT1_SHIFT) & ADC_TR1_LT1_MASK);
+          adc_putreg(priv, STM32_ADC_TR1_OFFSET, regval);
+
+          /* Ensure analog watchdog is enabled */
+
+          adc_wdog_enable(priv);
+        }
+        break;
+
+      default:
+        aerr("ERROR: Unknown cmd: %d\n", cmd);
+        ret = -ENOTTY;
+        break;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: adc_interrupt
+ *
+ * Description:
+ *   Common ADC interrupt handler.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int adc_interrupt(struct adc_dev_s *dev, uint32_t adcisr)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  int32_t value;
+
+  /* Identifies the AWD interrupt */
+
+  if ((adcisr & ADC_INT_AWD1) != 0)
+    {
+      value  = adc_getreg(priv, STM32_ADC_DR_OFFSET);
+      value &= ADC_DR_MASK;
+
+      awarn("WARNING: Analog Watchdog, Value (0x%03" PRIx32 ") "
+            "out of range!\n", value);
+
+      /* Stop ADC conversions to avoid continuous interrupts */
+
+      adc_startconv(priv, false);
+
+      /* Clear the interrupt. This register only accepts write 1's so its
+       * safe to only set the 1 bit without regard for the rest of the
+       * register
+       */
+
+      adc_putreg(priv, STM32_ADC_ISR_OFFSET, ADC_INT_AWD1);
+    }
+
+  /* OVR: Overrun */
+
+  if ((adcisr & ADC_INT_OVR) != 0)
+    {
+      /* In case of a missed ISR - due to interrupt saturation -
+       * the upper half needs to be informed to terminate properly.
+       */
+
+      awarn("WARNING: Overrun has occurred!\n");
+
+      /* To make use of already sampled data the conversion needs to be
+       * stopped first before reading out the data register.
+       */
+
+      adc_startconv(priv, false);
+
+      while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_ADSTART) != 0);
+
+      /* Verify that the upper-half driver has bound its callback functions */
+
+      if ((priv->cb != NULL) && (priv->cb->au_reset != NULL))
+        {
+          /* Notify upper-half driver about the overrun */
+
+          priv->cb->au_reset(dev);
+        }
+
+      /* Clear the interrupt. This register only accepts write 1's so its
+       * safe to only set the 1 bit without regard for the rest of the
+       * register
+       */
+
+      adc_putreg(priv, STM32_ADC_ISR_OFFSET, ADC_INT_OVR);
+    }
+
+  /* EOC: End of conversion */
+
+  if ((adcisr & ADC_INT_EOC) != 0)
+    {
+      /* Read from the ADC_DR register until 8 stage FIFO is empty.
+       * The FIFO is first mentioned in STM32H7 Reference Manual
+       * rev. 7, though, not yet indicated in the block diagram!
+       */
+
+      do
+        {
+          /* Read the converted value and clear EOC bit
+           * (It is cleared by reading the ADC_DR)
+           */
+
+          value  = adc_getreg(priv, STM32_ADC_DR_OFFSET);
+          value &= ADC_DR_MASK;
+
+          /* Verify that the upper-half driver has bound its
+           * callback functions
+           */
+
+          if (priv->cb != NULL)
+            {
+              /* Hand the ADC data to the ADC driver.  The ADC receive()
+               * method accepts 3 parameters:
+               *
+               * 1) The first is the ADC device instance for this ADC block.
+               * 2) The second is the channel number for the data, and
+               * 3) The third is the converted data for the channel.
+               */
+
+              DEBUGASSERT(priv->cb->au_receive != NULL);
+              priv->cb->au_receive(dev, priv->chanlist[priv->current],
+                                   value);
+            }
+
+          /* Set the channel number of the next channel that will
+           * complete conversion
+           */
+
+          priv->current++;
+
+          if (priv->current >= priv->nchannels)
+            {
+              /* Restart the conversion sequence from the beginning */
+
+              priv->current = 0;
+            }
+        }
+      while ((adc_getreg(priv, STM32_ADC_ISR_OFFSET) & ADC_INT_EOC) != 0);
+
+      /* We dont't add EOC to the bits to clear. It will cause a race
+       * condition.  EOC should only be cleared by reading the ADC_DR
+       */
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: adc12_interrupt
+ *
+ * Description:
+ *   ADC1/2 interrupt handler
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_STM32H5_ADC1) || defined(CONFIG_STM32H5_ADC2)
+static int adc12_interrupt(int irq, void *context, void *arg)
+{
+  uint32_t regval;
+  uint32_t pending;
+
+#ifdef CONFIG_STM32H5_ADC1
+  regval  = getreg32(STM32_ADC1_ISR);
+  pending = regval & ADC_INT_MASK;
+  if (pending != 0)
+    {
+      adc_interrupt(&g_adcdev1, regval);
+    }
+#endif
+
+#ifdef CONFIG_STM32H5_ADC2
+  regval  = getreg32(STM32_ADC2_ISR);
+  pending = regval & ADC_INT_MASK;
+  if (pending != 0)
+    {
+      adc_interrupt(&g_adcdev2, regval);
+    }
+#endif
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32h5_adc_initialize
+ */
+
+struct adc_dev_s *stm32h5_adc_initialize(int intf,
+                                         const uint8_t *chanlist,
+                                         int cchannels)
+{
+  struct adc_dev_s *dev;
+  struct stm32_dev_s *priv;
+
+  ainfo("intf: %d cchannels: %d\n", intf, cchannels);
+
+  switch (intf)
+    {
+#ifdef CONFIG_STM32H5_ADC1
+      case 1:
+        ainfo("ADC1 selected\n");
+        dev = &g_adcdev1;
+        break;
+#endif
+#ifdef CONFIG_STM32H5_ADC2
+      case 2:
+        ainfo("ADC2 selected\n");
+        dev = &g_adcdev2;
+        break;
+#endif
+      default:
+        aerr("ERROR: No ADC interface defined\n");
+        return NULL;
+    }
+
+  /* Configure the selected ADC */
+
+  priv = (struct stm32_dev_s *)dev->ad_priv;
+  priv->cb = NULL;
+
+  DEBUGASSERT(cchannels <= ADC_MAX_SAMPLES);
+  if (cchannels > ADC_MAX_SAMPLES)
+    {
+      cchannels = ADC_MAX_SAMPLES;
+    }
+
+  priv->cchannels = cchannels;
+  memcpy(priv->chanlist, chanlist, cchannels);
+
+#ifdef CONFIG_PM
+  if (pm_register(&priv->pm_callback) != OK)
+    {
+      aerr("ADC Power management registration failed\n");
+      return NULL;
+    }
+#endif
+
+  return dev;
+}
+#endif /* CONFIG_STM32H5_ADC1 || CONFIG_STM32H5_ADC2 */
+#endif /* CONFIG_ADC */
\ No newline at end of file
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c 
b/arch/arm/src/stm32h5/stm32_adc.h
similarity index 54%
copy from boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
copy to arch/arm/src/stm32h5/stm32_adc.h
index 7710041673..22f2ee1d69 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
+++ b/arch/arm/src/stm32h5/stm32_adc.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
+ * arch/arm/src/stm32h5/stm32_adc.h
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,88 +20,66 @@
  *
  ****************************************************************************/
 
+#ifndef __ARCH_ARM_SRC_STM32H5_STM32_ADC_H
+#define __ARCH_ARM_SRC_STM32H5_STM32_ADC_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/analog/adc.h>
+#include "chip.h"
+#include "hardware/stm32_adc.h"
 
-#include <sys/mount.h>
-#include <sys/types.h>
-#include <debug.h>
-
-#include <nuttx/input/buttons.h>
-#include <nuttx/leds/userled.h>
-#include <nuttx/board.h>
-
-#include "nucleo-h563zi.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
 
-#include <arch/board/board.h>
+#if defined(CONFIG_STM32H5_ADC1) || defined(CONFIG_STM32H5_ADC2)
 
 /****************************************************************************
- * Pre-processor Definitions
+ * Public Types
  ****************************************************************************/
 
 /****************************************************************************
- * Public Functions
+ * Public Function Prototypes
  ****************************************************************************/
 
+#ifndef __ASSEMBLY__
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
 /****************************************************************************
- * Name: stm32_bringup
+ * Name: stm32h5_adc_initialize
  *
  * Description:
- *   Perform architecture-specific initialization
+ *    Initialize the ADC.
  *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
+ * Input Parameters:
+ *    intf      - Could be {1,2} for ADC1, ADC2
+ *    chanlist  - The list of channels
+ *    nchannels - Number of channels
  *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ * Returned Value:
+ *    Valid ADC device structure reference on success; a NULL on failure
  *
  ****************************************************************************/
 
-int stm32_bringup(void)
-{
-  int ret;
-
-#ifdef CONFIG_FS_PROCFS
-  /* Mount the procfs file system */
-
-  ret = mount(NULL, "/proc", "procfs", 0, NULL);
-  if (ret < 0)
-    {
-      ferr("ERROR: Failed to mount procfs at /proc: %d\n", ret);
-    }
-#endif
-
-#if !defined(CONFIG_ARCH_LEDS) && defined(CONFIG_USERLED_LOWER)
-  /* Register the LED driver */
-
-  ret = userled_lower_initialize("/dev/userleds");
-  if (ret < 0)
-    {
-      syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret);
-    }
-#endif
-
-#ifdef CONFIG_INPUT_BUTTONS
-#ifdef CONFIG_INPUT_BUTTONS_LOWER
-  iinfo("Initializing button driver\n");
-
-  /* Register the BUTTON driver */
-
-  ret = btn_lower_initialize("/dev/buttons");
-  if (ret < 0)
-    {
-      ierr("ERROR: btn_lower_initialize() failed: %d\n", ret);
-    }
-#else
-  /* Enable BUTTON support for some other purpose */
-
-  board_button_initialize();
+struct adc_dev_s;
+struct adc_dev_s *stm32h5_adc_initialize(int intf,
+                                         const uint8_t *chanlist,
+                                         int nchannels);
+#undef EXTERN
+#ifdef __cplusplus
+}
 #endif
-#endif /* CONFIG_INPUT_BUTTONS */
+#endif /* __ASSEMBLY__ */
 
-  UNUSED(ret);
-  return OK;
-}
+#endif /* CONFIG_STM32H5_ADC1 || CONFIG_STM32H5_ADC2*/
+#endif /* __ARCH_ARM_SRC_STM32H5_STM32_ADC_H */
diff --git a/arch/arm/src/stm32h5/stm32h5xx_rcc.c 
b/arch/arm/src/stm32h5/stm32h5xx_rcc.c
index bb154e5d95..9a60ff7bdf 100644
--- a/arch/arm/src/stm32h5/stm32h5xx_rcc.c
+++ b/arch/arm/src/stm32h5/stm32h5xx_rcc.c
@@ -1195,6 +1195,15 @@ void stm32_stdclockconfig(void)
         }
 
 #endif /* STM32_USE_LSE */
+
+      /* Configure ADC source clock */
+
+#if defined(STM32_RCC_CCIPR5_ADCDACSEL)
+      regval = getreg32(STM32_RCC_CCIPR5);
+      regval &= ~RCC_CCIPR5_ADCDACSEL_MASK;
+      regval |= STM32_RCC_CCIPR5_ADCDACSEL;
+      putreg32(regval, STM32_RCC_CCIPR5);
+#endif
     }
 }
 #endif
diff --git a/boards/arm/stm32h5/nucleo-h563zi/configs/adc/defconfig 
b/boards/arm/stm32h5/nucleo-h563zi/configs/adc/defconfig
new file mode 100644
index 0000000000..68d3fd6ab9
--- /dev/null
+++ b/boards/arm/stm32h5/nucleo-h563zi/configs/adc/defconfig
@@ -0,0 +1,56 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ADC=y
+CONFIG_ANALOG=y
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nucleo-h563zi"
+CONFIG_ARCH_BOARD_NUCLEO_H563ZI=y
+CONFIG_ARCH_BUTTONS=y
+CONFIG_ARCH_CHIP="stm32h5"
+CONFIG_ARCH_CHIP_STM32H563ZI=y
+CONFIG_ARCH_CHIP_STM32H5=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARMV8M_STACKCHECK=y
+CONFIG_BOARD_LOOPSPERMSEC=9251
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_EXAMPLES_ADC=y
+CONFIG_EXAMPLES_ADC_NSAMPLES=10
+CONFIG_EXAMPLES_ADC_SWTRIG=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_DISABLE_IFUPDOWN=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=655360
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_READLINE_TABCOMPLETION=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_STM32H5_ADC1=y
+CONFIG_STM32H5_USART3=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_USART3_SERIAL_CONSOLE=y
diff --git a/boards/arm/stm32h5/nucleo-h563zi/include/board.h 
b/boards/arm/stm32h5/nucleo-h563zi/include/board.h
index 4265582512..e75c8115c3 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/include/board.h
+++ b/boards/arm/stm32h5/nucleo-h563zi/include/board.h
@@ -87,6 +87,20 @@
 #define STM32_PLL1Q_FREQUENCY     (STM32_VCO1_FRQ / 2)
 #define STM32_PLL1R_FREQUENCY     (STM32_VCO1_FRQ / 2)
 
+/* PLL2 config: Needed to use 2 ADC at max speed. */
+
+#define STM32_PLLCFG_PLL2CFG      (RCC_PLL2CFGR_PLL2SRC_HSI | \
+                                   RCC_PLL2CFGR_PLL2RGE_4_8M | \
+                                   RCC_PLL2CFGR_PLL2M(8) | \
+                                   RCC_PLL2CFGR_PLL2REN)
+#define STM32_PLLCFG_PLL2N         RCC_PLL2DIVR_PLL2N(75)
+#define STM32_PLLCFG_PLL2R         RCC_PLL2DIVR_PLL2R(4)
+#define STM32_PLLCFG_PLL2DIVR     (STM32_PLLCFG_PLL2N | \
+                                   STM32_PLLCFG_PLL2R)
+
+#define STM32_VCO2_FRQ            ((STM32_HSI_FREQUENCY / 8) * 75)
+#define STM32_PLL2R_FREQUENCY     (STM32_VCO2_FRQ / 4)
+
 /* Enable CLK48; get it from HSI48 */
 
 #if defined(CONFIG_STM32H5_USBFS) || defined(CONFIG_STM32H5_RNG)
@@ -180,6 +194,14 @@
 #define GPIO_ETH_RMII_CRS_DV  (GPIO_ETH_RMII_CRS_DV_0 | GPIO_SPEED_100MHz)  /* 
PA7 */
 #define GPIO_ETH_RMII_REF_CLK (GPIO_ETH_RMII_REF_CLK_0 | GPIO_SPEED_100MHz) /* 
PA1 */
 
+/* ADC Clock Source *********************************************************/
+
+#define STM32_RCC_CCIPR5_ADCDACSEL RCC_CCIPR5_ADCDACSEL_PLL2RCK
+#define STM32_ADC_CLK_FREQUENCY    STM32_PLL2R_FREQUENCY
+
+#define GPIO_ADC1_IN3   (GPIO_ADC1_IN3_0)
+#define GPIO_ADC1_IN10  (GPIO_ADC1_IN10_0)
+
 /* USART3: Connected to Arduino connector D0/D1 (or to STLink VCP if solder
  * bridges SB123 to SB130 are re-worked accordingly).
  */
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/Makefile 
b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile
index d3a10830e3..36de09b447 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/Makefile
+++ b/boards/arm/stm32h5/nucleo-h563zi/src/Makefile
@@ -39,4 +39,8 @@ ifeq ($(CONFIG_BOARDCTL),y)
 CSRCS += stm32_appinit.c
 endif
 
+ifeq ($(CONFIG_ADC),y)
+CSRCS += stm32_adc.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h 
b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
index 9e009a9f75..670551ad73 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
+++ b/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
@@ -118,5 +118,16 @@
 
 int stm32_bringup(void);
 
+/****************************************************************************
+ * Name: stm32_adc_setup
+ *
+ * Description:
+ *   Initialize ADC and register the ADC driver.
+ ****************************************************************************/
+
+#ifdef CONFIG_ADC
+int stm32_adc_setup(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H */
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h 
b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_adc.c
similarity index 50%
copy from boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
copy to boards/arm/stm32h5/nucleo-h563zi/src/stm32_adc.c
index 9e009a9f75..f96559874e 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
+++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_adc.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm/stm32h5/nucleo-h563zi/src/nucleo-h563zi.h
+ * boards/arm/stm32h5/nucleo-h563zi/src/stm32_adc.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,103 +20,114 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H
-#define __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/compiler.h>
-#include <stdint.h>
 
-#include "stm32_gpio.h"
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+#include <arch/board/board.h>
 
-/* Configuration ************************************************************/
+#include <nuttx/analog/adc.h>
 
-#define HAVE_PROC             1
-#define HAVE_RTC_DRIVER       1
+#include "stm32.h"
 
-#if !defined(CONFIG_FS_PROCFS)
-#  undef HAVE_PROC
-#endif
+#if defined(CONFIG_ADC) && defined(CONFIG_STM32H5_ADC1)
 
-#if defined(HAVE_PROC) && defined(CONFIG_DISABLE_MOUNTPOINT)
-#  warning Mountpoints disabled.  No procfs support
-#  undef HAVE_PROC
-#endif
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
 
-/* Check if we can support the RTC driver */
+/* Configuration ************************************************************/
 
-#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER)
-#  undef HAVE_RTC_DRIVER
-#endif
+/* The number of ADC channels in the conversion list */
 
-/* NUCLEO-H563ZI GPIOs ******************************************************/
+#define ADC1_NCHANNELS 2
 
-/* LED  I/O  Color
- * LD1  PB0  Green
- * LD2  PF4  Yellow
- * LD3  PG4  Red
- *
- * - When the I/O is LOW, the LED is on.
- * - When the I/O is HIGH value, the LED is off
- */
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
 
-#define GPIO_LD1        (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \
-                         GPIO_OUTPUT_SET | GPIO_PORTB | GPIO_PIN0)
-#define GPIO_LD2       (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \
-                         GPIO_OUTPUT_SET | GPIO_PORTF | GPIO_PIN4)
-#define GPIO_LD3       (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_2MHZ | \
-                         GPIO_OUTPUT_SET | GPIO_PORTG | GPIO_PIN4)
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
 
-/* Button definitions *******************************************************/
+/* Identifying number of each ADC channel (even if NCHANNELS is less ) */
 
-/* B1 USER: the user button is connected to the I/O PC13 (pin 2) of the STM32
- * microcontroller.
- */
+static const uint8_t g_chanlist1[2] =
+{
+  3,
+  10
+};
 
-#define MIN_IRQBUTTON   BUTTON_USER
-#define MAX_IRQBUTTON   BUTTON_USER
-#define NUM_IRQBUTTONS  1
+/* Configurations of pins used by each ADC channel */
 
-#define GPIO_BTN_USER   (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI | \
-                         GPIO_PORTC | GPIO_PIN13)
+static const uint32_t g_pinlist1[2]  =
+{
+  GPIO_ADC1_IN3,
+  GPIO_ADC1_IN10,
+};
 
 /****************************************************************************
- * Public Types
+ * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Public Data
+ * Public Functions
  ****************************************************************************/
 
-#ifndef __ASSEMBLY__
-
 /****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Name: stm32_bringup
+ * Name: stm32_adc_setup
  *
  * Description:
- *   Perform architecture-specific initialization
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=y :
- *     Called from board_late_initialize().
- *
- *   CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_BOARDCTL=y :
- *     Called from the NSH library
+ *   Initialize ADC and register the ADC driver.
  *
  ****************************************************************************/
 
-int stm32_bringup(void);
+int stm32_adc_setup(void)
+{
+  static bool initialized = false;
+  struct adc_dev_s *adc;
+  int ret;
+  int i;
+
+  /* Check if we have already initialized */
+
+  if (!initialized)
+    {
+      /* Configure the pins as analog inputs for the selected channels */
+
+      for (i = 0; i < ADC1_NCHANNELS; i++)
+        {
+          stm32_configgpio(g_pinlist1[i]);
+        }
+
+      /* Call stm32_adcinitialize() to get an instance of the ADC interface */
+
+      adc = stm32h5_adc_initialize(1, g_chanlist1, ADC1_NCHANNELS);
+      if (adc == NULL)
+        {
+          aerr("ERROR: Failed to get ADC interface 1\n");
+          return -ENODEV;
+        }
+
+      /* Register the ADC driver at "/dev/adc0" */
+
+      ret = adc_register("/dev/adc0", adc);
+      if (ret < 0)
+        {
+          aerr("ERROR: adc_register /dev/adc0 failed: %d\n", ret);
+          return ret;
+        }
+
+      initialized = true;
+    }
+
+  return OK;
+}
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM_STM32H5_NUCLEO_H563ZI_SRC_NUCLEO_H563ZI_H */
+#endif
\ No newline at end of file
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c 
b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
index 7710041673..48eeeb4b1b 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
+++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
@@ -102,6 +102,14 @@ int stm32_bringup(void)
 #endif
 #endif /* CONFIG_INPUT_BUTTONS */
 
+#ifdef CONFIG_ADC
+  ret = stm32_adc_setup();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: stm32_adc_setup failed: %d\n", ret);
+    }
+#endif /* CONFIG_ADC*/
+
   UNUSED(ret);
   return OK;
 }

Reply via email to