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;
}