summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig111
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/SConscript11
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f0/adc_config_v2.h372
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f1/adc_config_v2.h365
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f2/adc_config_v2.h377
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f3/adc_config_v2.h405
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/adc_config_v2.h377
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/dma_config.h26
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/f7/adc_config_v2.h377
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/g0/adc_config_v2.h327
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/g4/adc_config_v2.h412
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/h5/adc_config_v2.h371
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/adc_config_v2.h386
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/h7rs/adc_config_v2.h366
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/l0/adc_config_v2.h336
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/l4/adc_config_v2.h392
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/l5/adc_config_v2.h353
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/mp1/adc_config_v2.h377
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/u5/adc_config_v2.h422
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/wb/adc_config_v2.h368
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/config/wl/adc_config_v2.h332
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.c2231
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.h62
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_msh.c810
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_private.h787
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_trigger.c1175
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_config.h56
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h6
-rw-r--r--bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c518
-rw-r--r--bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml16
-rwxr-xr-xcomponents/drivers/Kconfig1
-rw-r--r--components/drivers/adc/Kconfig121
-rw-r--r--components/drivers/adc/SConscript23
-rw-r--r--components/drivers/adc/adc.c (renamed from components/drivers/misc/adc.c)0
-rw-r--r--components/drivers/adc/adc_v2.c1779
-rw-r--r--components/drivers/adc/adc_v2_internal.h62
-rw-r--r--components/drivers/adc/adc_v2_msh.c1225
-rw-r--r--components/drivers/adc/adc_v2_trigger.c411
-rw-r--r--components/drivers/clock_time/Kconfig11
-rw-r--r--components/drivers/include/drivers/adc_v2.h622
-rw-r--r--components/drivers/include/drivers/adc_v2_trigger.h171
-rw-r--r--components/drivers/include/drivers/clock_time.h34
-rw-r--r--components/drivers/include/rtdevice.h6
-rw-r--r--components/drivers/misc/Kconfig8
-rw-r--r--components/drivers/misc/SConscript3
45 files changed, 16951 insertions, 50 deletions
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig b/bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig
index 0a918c1ccd..633ffd2dd2 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig
@@ -24,6 +24,116 @@ if BSP_USING_USBD
# "ULPI: UTMI+ Low Pin Interface"
endif
+menuconfig BSP_USING_ADC_V2
+ bool "Enable ADC V2"
+ select RT_USING_ADC
+ select RT_USING_ADC_V2
+ default n
+
+if BSP_USING_ADC_V2
+ config BSP_USING_ADC1
+ bool "Enable ADC1"
+ default n
+
+ config BSP_USING_ADC2
+ bool "Enable ADC2"
+ depends on (SOC_SERIES_STM32F1 || SOC_SERIES_STM32F2 || SOC_SERIES_STM32F3 || \
+ SOC_SERIES_STM32F4 || SOC_SERIES_STM32G4 || SOC_SERIES_STM32F7 || \
+ SOC_SERIES_STM32H5 || SOC_SERIES_STM32H7 || SOC_SERIES_STM32H7RS || \
+ SOC_SERIES_STM32L4 || SOC_SERIES_STM32L5 || SOC_SERIES_STM32MP1 || \
+ SOC_SERIES_STM32U5)
+ default n
+
+ config BSP_USING_ADC3
+ bool "Enable ADC3"
+ depends on (SOC_SERIES_STM32F1 || SOC_SERIES_STM32F2 || SOC_SERIES_STM32F3 || \
+ SOC_SERIES_STM32F4 || SOC_SERIES_STM32G4 || SOC_SERIES_STM32F7 || \
+ SOC_SERIES_STM32H7 || SOC_SERIES_STM32L4 || SOC_SERIES_STM32MP1)
+ default n
+
+ config BSP_USING_ADC4
+ bool "Enable ADC4"
+ depends on (SOC_SERIES_STM32F3 || SOC_SERIES_STM32G4 || SOC_SERIES_STM32U5)
+ default n
+
+ config BSP_ADC_USING_TRIGGER
+ bool "Enable ADC V2 trigger backend"
+ select RT_ADC_USING_TRIGGER
+ default n
+ help
+ Enable STM32 ADC V2 trigger selector validation and backend
+ encoding. The ADC backend maps the framework-cached trigger to STM32
+ HAL ADC selector fields. Trigger-source frequency and lifecycle are
+ owned by the ADC trigger framework and timer trigger backend.
+
+ config BSP_ADC_USING_TIMER_TRIGGER
+ bool "Enable ADC V2 timer trigger selector backend"
+ depends on BSP_ADC_USING_TRIGGER
+ depends on BSP_USING_TIM
+ depends on RT_USING_CLOCK_TIME
+ select RT_ADC_TRIGGER_USING_TIMER
+ select RT_USING_CLOCK_TIMER_TRIGGER
+ default n
+ help
+ Enable STM32 TIMx update/TRGO and compare event to ADC external
+ trigger selector mapping for ADC V2 stream pacing. Timer frequency,
+ TRGO/compare setup, and lifecycle are handled through the clock
+ timer trigger backend during ADC stream start and stop.
+
+ config BSP_ADC_USING_ANALOG_COMPARE_TRIGGER
+ bool "Enable ADC V2 analog comparator trigger selector backend"
+ depends on BSP_ADC_USING_TRIGGER
+ select RT_ADC_TRIGGER_USING_COMPARE
+ default n
+ help
+ Enable STM32 COMPx_OUT to ADC external trigger selector mapping for
+ ADC V2. Comparator input, threshold, polarity, and enable state are
+ owned by board code, application code, or a comparator driver.
+
+ config BSP_ADC_USING_STREAM_DMA
+ bool
+
+ config BSP_ADC1_USING_DMA
+ bool "Enable ADC1 stream DMA backend"
+ depends on BSP_USING_ADC1
+ select RT_ADC_USING_STREAM
+ select BSP_ADC_USING_STREAM_DMA
+ default n
+ help
+ Enable the STM32 ADC1 DMA backend for ADC V2 stream sessions.
+
+ This option only enables the board-level DMA backend. The stream
+ framework and buffering policies are controlled by RT_ADC_USING_STREAM,
+ RT_ADC_STREAM_USING_LATEST, and RT_ADC_STREAM_USING_FIFO.
+
+ config BSP_ADC2_USING_DMA
+ bool "Enable ADC2 stream DMA backend"
+ depends on BSP_USING_ADC2
+ select RT_ADC_USING_STREAM
+ select BSP_ADC_USING_STREAM_DMA
+ default n
+ help
+ Enable the STM32 ADC2 DMA backend for ADC V2 stream sessions.
+
+ config BSP_ADC3_USING_DMA
+ bool "Enable ADC3 stream DMA backend"
+ depends on BSP_USING_ADC3
+ select RT_ADC_USING_STREAM
+ select BSP_ADC_USING_STREAM_DMA
+ default n
+ help
+ Enable the STM32 ADC3 DMA backend for ADC V2 stream sessions.
+
+ config BSP_ADC4_USING_DMA
+ bool "Enable ADC4 stream DMA backend"
+ depends on BSP_USING_ADC4
+ select RT_ADC_USING_STREAM
+ select BSP_ADC_USING_STREAM_DMA
+ default n
+ help
+ Enable the STM32 ADC4 DMA backend for ADC V2 stream sessions.
+endif
+
config BSP_USING_CRC
bool "Enable CRC (CRC-32 0x04C11DB7 Polynomial)"
select RT_USING_HWCRYPTO
@@ -59,4 +169,3 @@ config BSP_USING_UDID
bool "Enable UDID (Unique Device Identifier)"
select RT_USING_HWCRYPTO
default n
-
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript b/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript
index 9c5ab5c4ae..be974a8bc8 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript
@@ -46,9 +46,18 @@ if GetDepend(['RT_USING_I2C']):
if GetDepend(['BSP_USING_ETH', 'RT_USING_LWIP']) and not GetDepend(['SOC_STM32H750_ARTPI']):
src += ['drv_eth.c']
-if GetDepend(['RT_USING_ADC']):
+if GetDepend(['RT_USING_ADC']) and not GetDepend(['RT_USING_ADC_V2']):
src += ['drv_adc.c']
+if GetDepend(['BSP_USING_ADC_V2']):
+ src += ['drv_adc_v2.c']
+
+ if GetDepend(['BSP_ADC_USING_TRIGGER']):
+ src += ['drv_adc_v2_trigger.c']
+
+ if GetDepend(['RT_USING_FINSH', 'RT_ADC_V2_USING_MSH']):
+ src += ['drv_adc_v2_msh.c']
+
if GetDepend(['RT_USING_DAC']):
src += ['drv_dac.c']
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f0/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f0/adc_config_v2.h
new file mode 100644
index 0000000000..c1e0fa8732
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f0/adc_config_v2.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f0 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F0 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F0. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F0. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F0. */
+#if defined(ADC_SAMPLETIME_71CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_71CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_71CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F0 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F0 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F0 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F0 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F0 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f1/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f1/adc_config_v2.h
new file mode 100644
index 0000000000..7632d2b2d6
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f1/adc_config_v2.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f1 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F1 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F1. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F1. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F1. */
+#if defined(ADC_SAMPLETIME_55CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_55CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_55CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F1 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F1 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F1 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F1 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F1 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f2/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f2/adc_config_v2.h
new file mode 100644
index 0000000000..994405a859
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f2/adc_config_v2.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f2 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F2 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F2. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F2. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F2. */
+#if defined(ADC_SAMPLETIME_112CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_112CYCLES
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_112CYCLES) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F2 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F2 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_CONFIG_OFFSET 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F2 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F2 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F2 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f3/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f3/adc_config_v2.h
new file mode 100644
index 0000000000..778fec24bb
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f3/adc_config_v2.h
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f3 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F3 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F3. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F3. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F3. */
+#if defined(ADC_SAMPLETIME_181CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_181CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_181CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F3 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F3 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32F3 VREFINT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+/** @brief STM32F3 ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK ((1UL << 0) | (1UL << 1) | (1UL << 2) | (1UL << 3))
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F3 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F3 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F3 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef BSP_USING_ADC4
+/** @brief Default STM32F3 ADC4 V2 object initializer. */
+#define ADC4_V2_CONFIG \
+ { \
+ .name = "adc4", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC4, \
+ }, \
+ ADC4_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC4 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/adc_config_v2.h
new file mode 100644
index 0000000000..d4849e2213
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/adc_config_v2.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f4 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F4 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F4. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F4. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F4. */
+#if defined(ADC_SAMPLETIME_112CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_112CYCLES
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_112CYCLES) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F4 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F4 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_CONFIG_OFFSET 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F4 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F4 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F4 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/dma_config.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/dma_config.h
index 33caf71a2b..abe3fcf2e6 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/dma_config.h
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f4/dma_config.h
@@ -211,7 +211,13 @@ extern "C" {
#endif
/* DMA2 stream0 */
-#if defined(BSP_ADC1_USING_DMA) && !defined(ADC1_DMA_INSTANCE)
+#if defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
+#define SPI1_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler
+#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
+#define SPI1_RX_DMA_INSTANCE DMA2_Stream0
+#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
+#define SPI1_RX_DMA_IRQ DMA2_Stream0_IRQn
+#elif defined(BSP_ADC1_USING_DMA) && !defined(ADC1_DMA_INSTANCE)
#define ADC1_DMA_IRQHandler DMA2_Stream0_IRQHandler
#define ADC1_DMA_RCC RCC_AHB1ENR_DMA2EN
#define ADC1_DMA_INSTANCE DMA2_Stream0
@@ -223,12 +229,6 @@ extern "C" {
#define ADC3_DMA_INSTANCE DMA2_Stream0
#define ADC3_DMA_CHANNEL DMA_CHANNEL_2
#define ADC3_DMA_IRQ DMA2_Stream0_IRQn
-#elif defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
-#define SPI1_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler
-#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
-#define SPI1_RX_DMA_INSTANCE DMA2_Stream0
-#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
-#define SPI1_RX_DMA_IRQ DMA2_Stream0_IRQn
#elif defined(BSP_SPI4_RX_USING_DMA) && !defined(SPI4_RX_DMA_INSTANCE)
#define SPI4_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler
#define SPI4_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
@@ -283,18 +283,18 @@ extern "C" {
#define MEMTOMEM2_DMA_INSTANCE DMA2_Stream2
#define MEMTOMEM2_DMA_CHANNEL DMA_CHANNEL_2
#define MEMTOMEM2_DMA_IRQ DMA2_Stream2_IRQn
-#elif defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
-#define SPI1_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
-#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
-#define SPI1_RX_DMA_INSTANCE DMA2_Stream2
-#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
-#define SPI1_RX_DMA_IRQ DMA2_Stream2_IRQn
#elif defined(BSP_UART1_RX_USING_DMA) && !defined(UART1_RX_DMA_INSTANCE)
#define UART1_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
#define UART1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
#define UART1_RX_DMA_INSTANCE DMA2_Stream2
#define UART1_RX_DMA_CHANNEL DMA_CHANNEL_4
#define UART1_RX_DMA_IRQ DMA2_Stream2_IRQn
+#elif defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
+#define SPI1_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
+#define SPI1_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
+#define SPI1_RX_DMA_INSTANCE DMA2_Stream2
+#define SPI1_RX_DMA_CHANNEL DMA_CHANNEL_3
+#define SPI1_RX_DMA_IRQ DMA2_Stream2_IRQn
#elif defined(BSP_UART6_RX_USING_DMA) && !defined(UART6_RX_DMA_INSTANCE)
#define UART6_DMA_RX_IRQHandler DMA2_Stream2_IRQHandler
#define UART6_RX_DMA_RCC RCC_AHB1ENR_DMA2EN
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/f7/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f7/adc_config_v2.h
new file mode 100644
index 0000000000..7273dafb92
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/f7/adc_config_v2.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32f7 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32F7 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32F7. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32F7. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32F7. */
+#if defined(ADC_SAMPLETIME_112CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_112CYCLES
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_112CYCLES) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32F7 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32F7 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_CONFIG_OFFSET 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32F7 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32F7 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32F7 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/g0/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/g0/adc_config_v2.h
new file mode 100644
index 0000000000..9ea98c5864
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/g0/adc_config_v2.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32g0 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32G0 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32G0. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32G0. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32G0. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32G0. */
+#if defined(ADC_SAMPLETIME_160CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_160CYCLES_5
+#elif defined(ADC_SAMPLETIME_79CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_79CYCLES_5
+#elif defined(ADC_SAMPLETIME_39CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_39CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_160CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32G0 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32G0 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/g4/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/g4/adc_config_v2.h
new file mode 100644
index 0000000000..3556ee0347
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/g4/adc_config_v2.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32g4 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32G4 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32G4. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32G4. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32G4. */
+#if defined(ADC_SAMPLETIME_247CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_247CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_247CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32G4 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32G4 VBAT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+/** @brief STM32G4 ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK ((1UL << 0) | (1UL << 2) | (1UL << 4))
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32G4 VREFINT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+/** @brief STM32G4 ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK ((1UL << 0) | (1UL << 2) | (1UL << 3) | (1UL << 4))
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+#if defined(ADC_CHANNEL_TEMPSENSOR_ADC5)
+/** @brief STM32G4 alternate temperature sensor HAL ADC channel. */
+#define STM32_ADC_TEMP_ALT_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR_ADC5
+/** @brief STM32G4 ADC instances that can sample the alternate temperature sensor channel. */
+#define STM32_ADC_TEMP_ALT_INSTANCE_MASK (1UL << 4)
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR_ADC5) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32G4 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32G4 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32G4 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef BSP_USING_ADC4
+/** @brief Default STM32G4 ADC4 V2 object initializer. */
+#define ADC4_V2_CONFIG \
+ { \
+ .name = "adc4", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC4, \
+ }, \
+ ADC4_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC4 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/h5/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h5/adc_config_v2.h
new file mode 100644
index 0000000000..eca8588e7e
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h5/adc_config_v2.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32h5 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32H5 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32H5. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32H5. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32H5. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32H5. */
+#if defined(ADC_SAMPLETIME_814CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_814CYCLES
+#elif defined(ADC_SAMPLETIME_810CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_810CYCLES_5
+#elif defined(ADC_SAMPLETIME_247CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_247CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_814CYCLES) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32H5 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32H5 VBAT HAL ADC channel for the series-specific route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+#if defined(ADC2)
+/** @brief STM32H5 ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK (1UL << 1)
+#else
+/** @brief STM32H5 ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK (1UL << 0)
+#endif /* defined(ADC2) */
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VBAT_ADC4)
+/** @brief STM32H5 alternate VBAT HAL ADC channel. */
+#define STM32_ADC_VBAT_ALT_HAL_CHANNEL ADC_CHANNEL_VBAT_ADC4
+/** @brief STM32H5 ADC instances that can sample the alternate VBAT channel. */
+#define STM32_ADC_VBAT_ALT_INSTANCE_MASK (1UL << 2)
+#endif /* defined(ADC_CHANNEL_VBAT_ADC4) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32H5 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32H5 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/adc_config_v2.h
new file mode 100644
index 0000000000..707fc29d2d
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/adc_config_v2.h
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32h7 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32H7 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32H7. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32H7. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32H7. */
+#if defined(ADC_SAMPLETIME_810CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_810CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_810CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32H7 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+#if defined(ADC3)
+/** @brief STM32H7 default internal ADC source instance mask. */
+#define STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK (1UL << 2)
+#else
+/** @brief STM32H7 default internal ADC source instance mask. */
+#define STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK 0UL
+#endif /* defined(ADC3) */
+
+#if defined(ADC_CHANNEL_TEMPSENSOR)
+/** @brief STM32H7 temperature sensor HAL ADC channel for the default internal route. */
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR) */
+
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32H7 VBAT HAL ADC channel for the default internal route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32H7 VREFINT HAL ADC channel for the default internal route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32H7 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32H7 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32H7 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7rs/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7rs/adc_config_v2.h
new file mode 100644
index 0000000000..9909efa3e7
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/h7rs/adc_config_v2.h
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32h7rs adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32H7RS ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32H7RS. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32H7RS. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32H7RS. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32H7RS. */
+#if defined(ADC_SAMPLETIME_810CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_810CYCLES_5
+#elif defined(ADC_SAMPLETIME_814CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_814CYCLES
+#elif defined(ADC_SAMPLETIME_387CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_387CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_810CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32H7RS driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32H7RS ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32H7RS ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32H7RS ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/l0/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l0/adc_config_v2.h
new file mode 100644
index 0000000000..437dcb1753
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l0/adc_config_v2.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32l0 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32L0 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32L0. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32L0. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32L0. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32L0. */
+#if defined(ADC_SAMPLETIME_160CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_160CYCLES_5
+#elif defined(ADC_SAMPLETIME_79CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_79CYCLES_5
+#elif defined(ADC_SAMPLETIME_39CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_39CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_160CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32L0 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32L0 legacy internal ADC source logical channel overrides. */
+#if !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_LOGICAL_OVERRIDE 16
+#define STM32_ADC_VREF_LOGICAL_OVERRIDE 17
+#define STM32_ADC_VBAT_LOGICAL_OVERRIDE 18
+#endif /* !defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) && !defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32L0 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/l4/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l4/adc_config_v2.h
new file mode 100644
index 0000000000..98d9e62136
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l4/adc_config_v2.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32l4 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32L4 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32L4. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32L4. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32L4. */
+#if defined(ADC_SAMPLETIME_247CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_247CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_247CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32L4 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+#if defined(ADC_CHANNEL_TEMPSENSOR)
+/** @brief STM32L4 temperature sensor HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR
+/** @brief STM32L4 ADC instances that can sample temperature sensor. */
+#define STM32_ADC_TEMP_INSTANCE_MASK ((1UL << 0) | (1UL << 2))
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR) */
+
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32L4 VBAT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+/** @brief STM32L4 ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK ((1UL << 0) | (1UL << 2))
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32L4 VREFINT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+/** @brief STM32L4 ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK ((1UL << 0) | (1UL << 1) | (1UL << 2))
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_SIMPLE_CALIBRATION 1
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32L4 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32L4 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32L4 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/l5/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l5/adc_config_v2.h
new file mode 100644
index 0000000000..88fbfdbea9
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/l5/adc_config_v2.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32l5 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32L5 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32L5. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32L5. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32L5. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32L5. */
+#if defined(ADC_SAMPLETIME_247CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_247CYCLES_5
+#elif defined(ADC_SAMPLETIME_640CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_640CYCLES_5
+#elif defined(ADC_SAMPLETIME_160CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_160CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_247CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32L5 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_SIMPLE_CALIBRATION 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32L5 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32L5 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/mp1/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/mp1/adc_config_v2.h
new file mode 100644
index 0000000000..1789573e4d
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/mp1/adc_config_v2.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32mp1 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32MP1 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32MP1. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32MP1. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32MP1. */
+#if defined(ADC_SAMPLETIME_810CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_810CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_810CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32MP1 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32MP1 VBAT HAL ADC channel for the ADC2 route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+/** @brief STM32MP1 ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK (1UL << 1)
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32MP1 VREFINT HAL ADC channel for the ADC2 route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+/** @brief STM32MP1 ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK (1UL << 1)
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32MP1 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32MP1 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32MP1 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/u5/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/u5/adc_config_v2.h
new file mode 100644
index 0000000000..fbc97bc98f
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/u5/adc_config_v2.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32u5 adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32U5 ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32U5. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32U5. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32U5. */
+#if defined(ADC_SAMPLETIME_814CYCLES)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_814CYCLES
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_814CYCLES) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32U5 driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 internal-channel routing policy for this STM32 series. */
+/** @brief STM32U5 default internal ADC source instance mask. */
+#define STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK ((1UL << 0) | (1UL << 1))
+
+#if defined(ADC_CHANNEL_TEMPSENSOR)
+/** @brief STM32U5 temperature sensor HAL ADC channel for the default internal route. */
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR) */
+
+#if defined(ADC_CHANNEL_VBAT)
+/** @brief STM32U5 VBAT HAL ADC channel for the default internal route. */
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+#endif /* defined(ADC_CHANNEL_VBAT) */
+
+#if defined(ADC_CHANNEL_VREFINT)
+/** @brief STM32U5 VREFINT HAL ADC channel for the multi-instance route. */
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+/** @brief STM32U5 ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK ((1UL << 0) | (1UL << 1) | (1UL << 3))
+#endif /* defined(ADC_CHANNEL_VREFINT) */
+
+#if defined(ADC_CHANNEL_TEMPSENSOR_ADC4)
+/** @brief STM32U5 alternate temperature sensor HAL ADC channel. */
+#define STM32_ADC_TEMP_ALT_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR_ADC4
+/** @brief STM32U5 ADC instances that can sample the alternate temperature sensor channel. */
+#define STM32_ADC_TEMP_ALT_INSTANCE_MASK (1UL << 3)
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR_ADC4) */
+
+#if defined(ADC_CHANNEL_VBAT_ADC4)
+/** @brief STM32U5 alternate VBAT HAL ADC channel. */
+#define STM32_ADC_VBAT_ALT_HAL_CHANNEL ADC_CHANNEL_VBAT_ADC4
+/** @brief STM32U5 ADC instances that can sample the alternate VBAT channel. */
+#define STM32_ADC_VBAT_ALT_INSTANCE_MASK (1UL << 3)
+#endif /* defined(ADC_CHANNEL_VBAT_ADC4) */
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_NEEDS_ANALOG_SUPPLY 1
+#define STM32_ADC_VREF_NEEDS_INSTANCE 1
+
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32U5 ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32U5 ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32U5 ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef BSP_USING_ADC4
+/** @brief Default STM32U5 ADC4 V2 object initializer. */
+#define ADC4_V2_CONFIG \
+ { \
+ .name = "adc4", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC4, \
+ }, \
+ ADC4_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC4 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/wb/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/wb/adc_config_v2.h
new file mode 100644
index 0000000000..6895ecae0c
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/wb/adc_config_v2.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32wb adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32WB ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32WB. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32WB. */
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+
+/** @brief Default ADC resolution for STM32 ADC V2. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32WB. */
+#if defined(ADC_SAMPLETIME_2CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_2CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_2CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32WB driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_SIMPLE_CALIBRATION 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32WB ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef BSP_USING_ADC2
+/** @brief Default STM32WB ADC2 V2 object initializer. */
+#define ADC2_V2_CONFIG \
+ { \
+ .name = "adc2", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC2, \
+ }, \
+ ADC2_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC2 */
+
+#ifdef BSP_USING_ADC3
+/** @brief Default STM32WB ADC3 V2 object initializer. */
+#define ADC3_V2_CONFIG \
+ { \
+ .name = "adc3", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC3, \
+ }, \
+ ADC3_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC3 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/config/wl/adc_config_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/config/wl/adc_config_v2.h
new file mode 100644
index 0000000000..3be4a47f75
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/config/wl/adc_config_v2.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-27 wdfk-prog add stm32wl adc v2 configuration
+ */
+
+/**
+ * @file adc_config_v2.h
+ * @brief STM32WL ADC V2 configuration defaults.
+ */
+
+#ifndef __ADC_CONFIG_V2_H__
+#define __ADC_CONFIG_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtthread.h>
+#include <drivers/adc_v2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Default ADC clock prescaler for STM32WL. */
+#if defined(ADC_CLOCK_SYNC_PCLK_DIV4)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_SYNC_PCLK_DIV4
+#elif defined(ADC_CLOCK_ASYNC_DIV1)
+#define ADC_DEFAULT_CLOCK_PRESCALER ADC_CLOCK_ASYNC_DIV1
+#endif /* defined(ADC_CLOCK_SYNC_PCLK_DIV4) */
+
+/** @brief Default ADC data alignment for STM32WL. */
+#if defined(ADC_DATAALIGN_RIGHT)
+#define ADC_DEFAULT_DATA_ALIGN ADC_DATAALIGN_RIGHT
+#else
+#define ADC_DEFAULT_DATA_ALIGN 0U
+#endif /* defined(ADC_DATAALIGN_RIGHT) */
+
+/** @brief Default ADC resolution for STM32WL. */
+#ifdef ADC_RESOLUTION_12B
+#define ADC_DEFAULT_RESOLUTION ADC_RESOLUTION_12B
+#else
+#define ADC_DEFAULT_RESOLUTION 0U
+#endif /* ADC_RESOLUTION_12B */
+
+/** @brief Default ADC sampling time for STM32WL. */
+#if defined(ADC_SAMPLETIME_160CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_160CYCLES_5
+#elif defined(ADC_SAMPLETIME_247CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_247CYCLES_5
+#elif defined(ADC_SAMPLETIME_640CYCLES_5)
+#define ADC_DEFAULT_SAMPLING_TIME ADC_SAMPLETIME_640CYCLES_5
+#else
+#define ADC_DEFAULT_SAMPLING_TIME 0U
+#endif /* defined(ADC_SAMPLETIME_160CYCLES_5) */
+
+
+/** @brief Maximum regular sequence length supported by the STM32WL driver. */
+#define STM32_ADC_MAX_SEQUENCE 16
+
+/** @brief Whether sequence mode is compiled in. */
+#define STM32_ADC_USING_SEQUENCE 1
+
+/** @brief Whether any ADC instance requests a stream DMA backend. */
+#if defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || \
+ defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA)
+#define STM32_ADC_HAS_STREAM_DMA_BSP 1
+#else
+#define STM32_ADC_HAS_STREAM_DMA_BSP 0
+#endif /* defined(BSP_ADC1_USING_DMA) || defined(BSP_ADC2_USING_DMA) || defined(BSP_ADC3_USING_DMA) || defined(BSP_ADC4_USING_DMA) */
+
+/** @brief Whether stream mode is compiled in through the STM32 DMA-backed backend. */
+#if defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP
+#define STM32_ADC_USING_STREAM 1
+#else
+#define STM32_ADC_USING_STREAM 0
+#endif /* defined(RT_ADC_USING_STREAM) && defined(HAL_DMA_MODULE_ENABLED) && STM32_ADC_HAS_STREAM_DMA_BSP */
+
+/** @brief Whether the compiled STM32 ADC stream backend uses DMA transport. */
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+
+#if STM32_ADC_USING_STREAM
+#if defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ)
+#if defined(ADC1_DMA_REQUEST)
+#define STM32_ADC1_DMA_REQUEST_VALUE ADC1_DMA_REQUEST
+#else
+#define STM32_ADC1_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC1_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_CHANNEL)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ ADC1_DMA_CHANNEL,
+ STM32_ADC1_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC1_DMA_REQUEST)
+#define ADC1_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC1_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC1_DMA_INSTANCE,
+ ADC1_DMA_RCC,
+ ADC1_DMA_IRQ,
+ 0U,
+ ADC1_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC1_DMA_REQUEST) */
+#endif /* defined(BSP_ADC1_USING_DMA) && defined(ADC1_DMA_INSTANCE) && defined(ADC1_DMA_RCC) && defined(ADC1_DMA_IRQ) */
+
+#if defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ)
+#if defined(ADC2_DMA_REQUEST)
+#define STM32_ADC2_DMA_REQUEST_VALUE ADC2_DMA_REQUEST
+#else
+#define STM32_ADC2_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC2_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_CHANNEL)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ ADC2_DMA_CHANNEL,
+ STM32_ADC2_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC2_DMA_REQUEST)
+#define ADC2_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC2_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC2_DMA_INSTANCE,
+ ADC2_DMA_RCC,
+ ADC2_DMA_IRQ,
+ 0U,
+ ADC2_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC2_DMA_REQUEST) */
+#endif /* defined(BSP_ADC2_USING_DMA) && defined(ADC2_DMA_INSTANCE) && defined(ADC2_DMA_RCC) && defined(ADC2_DMA_IRQ) */
+
+#if defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ)
+#if defined(ADC3_DMA_REQUEST)
+#define STM32_ADC3_DMA_REQUEST_VALUE ADC3_DMA_REQUEST
+#else
+#define STM32_ADC3_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC3_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_CHANNEL)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ ADC3_DMA_CHANNEL,
+ STM32_ADC3_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC3_DMA_REQUEST)
+#define ADC3_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC3_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC3_DMA_INSTANCE,
+ ADC3_DMA_RCC,
+ ADC3_DMA_IRQ,
+ 0U,
+ ADC3_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC3_DMA_REQUEST) */
+#endif /* defined(BSP_ADC3_USING_DMA) && defined(ADC3_DMA_INSTANCE) && defined(ADC3_DMA_RCC) && defined(ADC3_DMA_IRQ) */
+
+#if defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ)
+#if defined(ADC4_DMA_REQUEST)
+#define STM32_ADC4_DMA_REQUEST_VALUE ADC4_DMA_REQUEST
+#else
+#define STM32_ADC4_DMA_REQUEST_VALUE 0U
+#endif /* defined(ADC4_DMA_REQUEST) */
+
+#if defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_CHANNEL)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ ADC4_DMA_CHANNEL,
+ STM32_ADC4_DMA_REQUEST_VALUE,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#elif defined(ADC4_DMA_REQUEST)
+#define ADC4_V2_HAS_DMA_CONFIG 1
+static const struct stm32_dma_config ADC4_DMA_CONFIG =
+ STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(ADC4_DMA_INSTANCE,
+ ADC4_DMA_RCC,
+ ADC4_DMA_IRQ,
+ 0U,
+ ADC4_DMA_REQUEST,
+ STM32_DMA_DEFAULT_PRIORITY,
+ STM32_DMA_DEFAULT_PREEMPT_PRIORITY,
+ STM32_DMA_DEFAULT_SUB_PRIORITY);
+#endif /* defined(STM32_DMA_USES_GPDMA) && defined(ADC4_DMA_REQUEST) */
+#endif /* defined(BSP_ADC4_USING_DMA) && defined(ADC4_DMA_INSTANCE) && defined(ADC4_DMA_RCC) && defined(ADC4_DMA_IRQ) */
+
+#endif /* STM32_ADC_USING_STREAM */
+
+#if defined(ADC1_V2_HAS_DMA_CONFIG)
+#define ADC1_V2_DMA_CONFIG_FIELD .dma_rx = &ADC1_DMA_CONFIG,
+#else
+#define ADC1_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC1_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC2_V2_HAS_DMA_CONFIG)
+#define ADC2_V2_DMA_CONFIG_FIELD .dma_rx = &ADC2_DMA_CONFIG,
+#else
+#define ADC2_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC2_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC3_V2_HAS_DMA_CONFIG)
+#define ADC3_V2_DMA_CONFIG_FIELD .dma_rx = &ADC3_DMA_CONFIG,
+#else
+#define ADC3_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC3_V2_HAS_DMA_CONFIG) */
+
+#if defined(ADC4_V2_HAS_DMA_CONFIG)
+#define ADC4_V2_DMA_CONFIG_FIELD .dma_rx = &ADC4_DMA_CONFIG,
+#else
+#define ADC4_V2_DMA_CONFIG_FIELD
+#endif /* defined(ADC4_V2_HAS_DMA_CONFIG) */
+
+
+
+/* ADC V2 HAL feature policy for this STM32 series. */
+#if defined(ADC_DEFAULT_DATA_ALIGN)
+#define STM32_ADC_HAS_INIT_DATA_ALIGN 1
+#endif /* defined(ADC_DEFAULT_DATA_ALIGN) */
+
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+#define STM32_ADC_HAS_INIT_EXT_TRIG_EDGE 1
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+#define STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS 1
+
+#define STM32_ADC_HAS_INIT_NBR_OF_CONVERSION 1
+#define STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION 1
+
+#if defined(ADC_EOC_SINGLE_CONV)
+#define STM32_ADC_HAS_INIT_EOC_SELECTION 1
+#endif /* defined(ADC_EOC_SINGLE_CONV) */
+
+#define STM32_ADC_HAS_SIMPLE_CALIBRATION 1
+
+#ifdef BSP_USING_ADC1
+/** @brief Default STM32WL ADC1 V2 object initializer. */
+#define ADC1_V2_CONFIG \
+ { \
+ .name = "adc1", \
+ .config = \
+ { \
+ .sampling_time = ADC_DEFAULT_SAMPLING_TIME, \
+ .resolution = ADC_DEFAULT_RESOLUTION, \
+ .data_align = ADC_DEFAULT_DATA_ALIGN, \
+ .input_modes = RT_ADC_INPUT_MODE_SINGLE_ENDED, \
+ .oversampling_ratio = 0U, \
+ .oversampling_right_shift = 0U, \
+ }, \
+ .handle = \
+ { \
+ .Instance = ADC1, \
+ }, \
+ ADC1_V2_DMA_CONFIG_FIELD \
+ }
+#endif /* BSP_USING_ADC1 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __ADC_CONFIG_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.c
new file mode 100644
index 0000000000..6c3c8bb528
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.c
@@ -0,0 +1,2231 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32 adc v2 driver implementation
+ */
+
+/**
+ * @file drv_adc_v2.c
+ * @brief STM32 ADC V2 driver implementation.
+ */
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include "drv_config.h"
+#include "drv_adc_v2_private.h"
+
+#if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4)
+
+#define DRV_DEBUG
+#define LOG_TAG "drv.adc"
+#include <drv_log.h>
+
+/**
+ * @brief Apply the STM32 private oversampling configuration to the ADC init structure.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_apply_oversampling(struct stm32_adc *adc)
+{
+#if defined(STM32_ADC_HAS_HW_OVERSAMPLING)
+ if (adc->config.oversampling_ratio == 0U)
+ {
+ adc->handle.Init.OversamplingMode = DISABLE;
+ return RT_EOK;
+ }
+
+ adc->handle.Init.OversamplingMode = ENABLE;
+ adc->handle.Init.Oversampling.Ratio = adc->config.oversampling_ratio;
+ adc->handle.Init.Oversampling.RightBitShift = adc->config.oversampling_right_shift;
+ adc->handle.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
+ adc->handle.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
+ return RT_EOK;
+#else
+ return (adc->config.oversampling_ratio == 0U) ? RT_EOK : -RT_ENOSYS;
+#endif /* defined(STM32_ADC_HAS_HW_OVERSAMPLING) */
+}
+
+/**
+ * @brief STM32 ADC object indexes.
+ */
+enum stm32_adc_index
+{
+#ifdef BSP_USING_ADC1
+ ADC1_INDEX,
+#endif /* BSP_USING_ADC1 */
+#ifdef BSP_USING_ADC2
+ ADC2_INDEX,
+#endif /* BSP_USING_ADC2 */
+#ifdef BSP_USING_ADC3
+ ADC3_INDEX,
+#endif /* BSP_USING_ADC3 */
+#ifdef BSP_USING_ADC4
+ ADC4_INDEX,
+#endif /* BSP_USING_ADC4 */
+};
+
+/**
+ * @brief STM32 ADC device table.
+ */
+static struct stm32_adc stm32_adc_obj[] = {
+#ifdef BSP_USING_ADC1
+ ADC1_V2_CONFIG,
+#endif /* BSP_USING_ADC1 */
+#ifdef BSP_USING_ADC2
+ ADC2_V2_CONFIG,
+#endif /* BSP_USING_ADC2 */
+#ifdef BSP_USING_ADC3
+ ADC3_V2_CONFIG,
+#endif /* BSP_USING_ADC3 */
+#ifdef BSP_USING_ADC4
+ ADC4_V2_CONFIG,
+#endif /* BSP_USING_ADC4 */
+};
+
+/**
+ * @brief ADC hardware channel mapping table.
+ */
+static const uint32_t stm32_adc_channel_table[STM32_ADC_MAX_CHANNELS] = {
+ ADC_CHANNEL_0,
+ ADC_CHANNEL_1,
+ ADC_CHANNEL_2,
+ ADC_CHANNEL_3,
+ ADC_CHANNEL_4,
+ ADC_CHANNEL_5,
+ ADC_CHANNEL_6,
+ ADC_CHANNEL_7,
+ ADC_CHANNEL_8,
+ ADC_CHANNEL_9,
+ ADC_CHANNEL_10,
+ ADC_CHANNEL_11,
+ ADC_CHANNEL_12,
+ ADC_CHANNEL_13,
+ ADC_CHANNEL_14,
+ ADC_CHANNEL_15,
+#if STM32_ADC_MAX_CHANNELS > 16
+ STM32_ADC_CHANNEL_16,
+#endif /* STM32_ADC_MAX_CHANNELS > 16 */
+#if STM32_ADC_MAX_CHANNELS > 17
+ STM32_ADC_CHANNEL_17,
+#endif /* STM32_ADC_MAX_CHANNELS > 17 */
+#if STM32_ADC_MAX_CHANNELS > 18
+ STM32_ADC_CHANNEL_18,
+#endif /* STM32_ADC_MAX_CHANNELS > 18 */
+#if STM32_ADC_MAX_CHANNELS > 19
+ STM32_ADC_CHANNEL_19,
+#endif /* STM32_ADC_MAX_CHANNELS > 19 */
+#if STM32_ADC_MAX_CHANNELS > 20
+ STM32_ADC_CHANNEL_20,
+#endif /* STM32_ADC_MAX_CHANNELS > 20 */
+#if STM32_ADC_MAX_CHANNELS > 21
+ STM32_ADC_CHANNEL_21,
+#endif /* STM32_ADC_MAX_CHANNELS > 21 */
+#if STM32_ADC_MAX_CHANNELS > 22
+ STM32_ADC_CHANNEL_22,
+#endif /* STM32_ADC_MAX_CHANNELS > 22 */
+#if STM32_ADC_MAX_CHANNELS > 23
+ STM32_ADC_CHANNEL_23,
+#endif /* STM32_ADC_MAX_CHANNELS > 23 */
+#if STM32_ADC_MAX_CHANNELS > 24
+ STM32_ADC_CHANNEL_24,
+#endif /* STM32_ADC_MAX_CHANNELS > 24 */
+#if STM32_ADC_MAX_CHANNELS > 25
+ STM32_ADC_CHANNEL_25,
+#endif /* STM32_ADC_MAX_CHANNELS > 25 */
+#if STM32_ADC_MAX_CHANNELS > 26
+ STM32_ADC_CHANNEL_26,
+#endif /* STM32_ADC_MAX_CHANNELS > 26 */
+#if STM32_ADC_MAX_CHANNELS > 27
+ STM32_ADC_CHANNEL_27,
+#endif /* STM32_ADC_MAX_CHANNELS > 27 */
+#if STM32_ADC_MAX_CHANNELS > 28
+ STM32_ADC_CHANNEL_28,
+#endif /* STM32_ADC_MAX_CHANNELS > 28 */
+#if STM32_ADC_MAX_CHANNELS > 29
+ STM32_ADC_CHANNEL_29,
+#endif /* STM32_ADC_MAX_CHANNELS > 29 */
+#if STM32_ADC_MAX_CHANNELS > 30
+ STM32_ADC_CHANNEL_30,
+#endif /* STM32_ADC_MAX_CHANNELS > 30 */
+#if STM32_ADC_MAX_CHANNELS > 31
+ STM32_ADC_CHANNEL_31,
+#endif /* STM32_ADC_MAX_CHANNELS > 31 */
+};
+
+/**
+ * @brief STM32 internal ADC channel capability entry.
+ */
+struct stm32_adc_internal_channel
+{
+ int logical_channel; /**< RT-Thread logical channel number, or negative if unsupported. */
+ uint32_t hal_channel; /**< Primary HAL channel identifier. */
+ rt_uint32_t instance_mask; /**< ADC instances that can use the primary HAL channel. */
+ uint32_t alternate_hal_channel; /**< Alternate HAL channel identifier for instance-specific mappings. */
+ rt_uint32_t alternate_instance_mask; /**< ADC instances that can use the alternate HAL channel. */
+};
+
+/**
+ * @brief STM32 internal ADC channel capability table.
+ */
+static const struct stm32_adc_internal_channel stm32_adc_internal_channels[] = {
+ { STM32_ADC_TEMP_CHANNEL, STM32_ADC_TEMP_HAL_CHANNEL, STM32_ADC_TEMP_INSTANCE_MASK,
+ STM32_ADC_TEMP_ALT_HAL_CHANNEL, STM32_ADC_TEMP_ALT_INSTANCE_MASK },
+ { STM32_ADC_VBAT_CHANNEL, STM32_ADC_VBAT_HAL_CHANNEL, STM32_ADC_VBAT_INSTANCE_MASK,
+ STM32_ADC_VBAT_ALT_HAL_CHANNEL, STM32_ADC_VBAT_ALT_INSTANCE_MASK },
+ { STM32_ADC_VREF_CHANNEL, STM32_ADC_VREF_HAL_CHANNEL, STM32_ADC_VREF_INSTANCE_MASK,
+ STM32_ADC_VREF_ALT_HAL_CHANNEL, STM32_ADC_VREF_ALT_INSTANCE_MASK },
+};
+
+/**
+ * @brief Check whether an ADC channel is a valid HAL channel identifier.
+ * @param hal_channel HAL channel identifier.
+ * @return RT_TRUE if valid, otherwise RT_FALSE.
+ */
+static rt_bool_t stm32_adc_hal_channel_valid(uint32_t hal_channel)
+{
+ return (hal_channel != STM32_ADC_INVALID_CHANNEL) ? RT_TRUE : RT_FALSE;
+}
+
+/**
+ * @brief Check whether an ADC peripheral instance matches an instance mask.
+ * @param instance ADC peripheral instance.
+ * @param mask STM32_ADC_INSTANCE_MASK_x bit mask.
+ * @return RT_TRUE if the instance is included, otherwise RT_FALSE.
+ */
+rt_bool_t stm32_adc_instance_match(ADC_TypeDef *instance, rt_uint32_t mask)
+{
+#ifdef ADC1
+ if ((instance == ADC1) && ((mask & STM32_ADC_INSTANCE_MASK_ADC1) != 0U))
+ {
+ return RT_TRUE;
+ }
+#endif /* ADC1 */
+
+#ifdef ADC2
+ if ((instance == ADC2) && ((mask & STM32_ADC_INSTANCE_MASK_ADC2) != 0U))
+ {
+ return RT_TRUE;
+ }
+#endif /* ADC2 */
+
+#ifdef ADC3
+ if ((instance == ADC3) && ((mask & STM32_ADC_INSTANCE_MASK_ADC3) != 0U))
+ {
+ return RT_TRUE;
+ }
+#endif /* ADC3 */
+
+#ifdef ADC4
+ if ((instance == ADC4) && ((mask & STM32_ADC_INSTANCE_MASK_ADC4) != 0U))
+ {
+ return RT_TRUE;
+ }
+#endif /* ADC4 */
+
+#ifdef ADC5
+ if ((instance == ADC5) && ((mask & STM32_ADC_INSTANCE_MASK_ADC5) != 0U))
+ {
+ return RT_TRUE;
+ }
+#endif /* ADC5 */
+
+ return RT_FALSE;
+}
+
+/**
+ * @brief Check whether one internal HAL channel is supported by the current ADC instance.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param hal_channel HAL ADC channel identifier.
+ * @param instance_mask ADC instance mask allowed to access this internal channel.
+ * @return RT_TRUE if the channel is available on the current ADC instance, otherwise RT_FALSE.
+ */
+static rt_bool_t stm32_adc_internal_channel_supported(struct stm32_adc *adc, uint32_t hal_channel, rt_uint32_t instance_mask)
+{
+ if ((stm32_adc_hal_channel_valid(hal_channel) != RT_TRUE))
+ {
+ return RT_FALSE;
+ }
+
+ return stm32_adc_instance_match(adc->handle.Instance, instance_mask);
+}
+
+/**
+ * @brief Find the internal ADC channel capability entry by logical channel.
+ * @param channel RT-Thread logical ADC channel identifier.
+ * @return Pointer to the internal-channel entry, or RT_NULL if the channel is not internal.
+ */
+static const struct stm32_adc_internal_channel *stm32_adc_find_internal_channel(rt_uint8_t channel)
+{
+ rt_size_t index;
+
+ for (index = 0U; index < RT_ARRAY_SIZE(stm32_adc_internal_channels); index++)
+ {
+ if ((stm32_adc_internal_channels[index].logical_channel >= 0) &&
+ ((rt_uint8_t)stm32_adc_internal_channels[index].logical_channel == channel))
+ {
+ return &stm32_adc_internal_channels[index];
+ }
+ }
+
+ return RT_NULL;
+}
+
+/**
+ * @brief Get an instance-aware HAL channel identifier for an ADC channel.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel RT-Thread logical ADC channel identifier.
+ * @param hal_channel Pointer to the output HAL ADC channel identifier.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_get_channel_for_instance(struct stm32_adc *adc, rt_uint8_t channel, uint32_t *hal_channel)
+{
+ const struct stm32_adc_internal_channel *internal_channel;
+ rt_err_t result;
+
+ internal_channel = stm32_adc_find_internal_channel(channel);
+ if (internal_channel != RT_NULL)
+ {
+ if (stm32_adc_internal_channel_supported(adc, internal_channel->hal_channel, internal_channel->instance_mask) == RT_TRUE)
+ {
+ *hal_channel = internal_channel->hal_channel;
+ return RT_EOK;
+ }
+
+ if (stm32_adc_internal_channel_supported(adc, internal_channel->alternate_hal_channel,
+ internal_channel->alternate_instance_mask) == RT_TRUE)
+ {
+ *hal_channel = internal_channel->alternate_hal_channel;
+ return RT_EOK;
+ }
+
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_get_channel(channel, hal_channel);
+ if ((result == RT_EOK) && (stm32_adc_hal_channel_valid(*hal_channel) != RT_TRUE))
+ {
+ return -RT_EINVAL;
+ }
+
+ return result;
+}
+
+/**
+ * @brief Get the HAL ADC channel identifier.
+ * @param channel RT-Thread ADC channel identifier.
+ * @param hal_channel Pointer to the output HAL channel identifier.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_channel(rt_uint8_t channel, uint32_t *hal_channel)
+{
+ if (((rt_size_t)channel >= RT_ARRAY_SIZE(stm32_adc_channel_table)) ||
+ (stm32_adc_hal_channel_valid(stm32_adc_channel_table[(rt_size_t)channel]) != RT_TRUE))
+ {
+ return -RT_EINVAL;
+ }
+
+ *hal_channel = stm32_adc_channel_table[(rt_size_t)channel];
+ return RT_EOK;
+}
+
+/**
+ * @brief Get the logical channel used to sample STM32 VREF.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical VREFINT channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_vref_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel)
+{
+ uint32_t hal_channel;
+ rt_err_t result;
+
+ if (STM32_ADC_VREF_CHANNEL < 0)
+ {
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_get_channel_for_instance(adc, (rt_uint8_t)STM32_ADC_VREF_CHANNEL, &hal_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ RT_UNUSED(hal_channel);
+ *channel = (rt_uint8_t)STM32_ADC_VREF_CHANNEL;
+ return RT_EOK;
+}
+
+/**
+ * @brief Get the logical channel used to sample STM32 internal temperature sensor.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical temperature-sensor channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_tempsensor_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel)
+{
+ uint32_t hal_channel;
+ rt_err_t result;
+
+ if (STM32_ADC_TEMP_CHANNEL < 0)
+ {
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_get_channel_for_instance(adc, (rt_uint8_t)STM32_ADC_TEMP_CHANNEL, &hal_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ RT_UNUSED(hal_channel);
+ *channel = (rt_uint8_t)STM32_ADC_TEMP_CHANNEL;
+ return RT_EOK;
+}
+
+/**
+ * @brief Get the logical channel used to sample STM32 internal VBAT divider.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical VBAT channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_vbat_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel)
+{
+ uint32_t hal_channel;
+ rt_err_t result;
+
+ if (STM32_ADC_VBAT_CHANNEL < 0)
+ {
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_get_channel_for_instance(adc, (rt_uint8_t)STM32_ADC_VBAT_CHANNEL, &hal_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ RT_UNUSED(hal_channel);
+ *channel = (rt_uint8_t)STM32_ADC_VBAT_CHANNEL;
+ return RT_EOK;
+}
+
+/**
+ * @brief Get the current ADC resolution in bits.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @return Resolution in bits, or 12 when it cannot be determined.
+ */
+rt_uint8_t stm32_adc_get_resolution_bits(const struct stm32_adc *adc)
+{
+#if defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION)
+ switch (adc->handle.Init.Resolution)
+ {
+#ifdef ADC_RESOLUTION_16B
+ case ADC_RESOLUTION_16B:
+ return 16U;
+#endif /* ADC_RESOLUTION_16B */
+#ifdef ADC_RESOLUTION_14B
+ case ADC_RESOLUTION_14B:
+ return 14U;
+#endif /* ADC_RESOLUTION_14B */
+#ifdef ADC_RESOLUTION_12B
+ case ADC_RESOLUTION_12B:
+ return 12U;
+#endif /* ADC_RESOLUTION_12B */
+#ifdef ADC_RESOLUTION_10B
+ case ADC_RESOLUTION_10B:
+ return 10U;
+#endif /* ADC_RESOLUTION_10B */
+#ifdef ADC_RESOLUTION_8B
+ case ADC_RESOLUTION_8B:
+ return 8U;
+#endif /* ADC_RESOLUTION_8B */
+#ifdef ADC_RESOLUTION_6B
+ case ADC_RESOLUTION_6B:
+ return 6U;
+#endif /* ADC_RESOLUTION_6B */
+ default:
+ return 12U;
+ }
+#else
+ RT_UNUSED(adc);
+ return 12U;
+#endif /* defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION) */
+}
+
+#if defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC)
+/**
+ * @brief Convert an ADC resolution in bits to the HAL resolution token.
+ * @param resolution_bits ADC conversion resolution in bits.
+ * @param hal_resolution Pointer to the output HAL resolution token.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_get_hal_resolution(rt_uint8_t resolution_bits, uint32_t *hal_resolution)
+{
+ if (hal_resolution == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ switch (resolution_bits)
+ {
+#ifdef ADC_RESOLUTION_16B
+ case 16U:
+ *hal_resolution = ADC_RESOLUTION_16B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_16B */
+#ifdef ADC_RESOLUTION_14B
+ case 14U:
+ *hal_resolution = ADC_RESOLUTION_14B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_14B */
+#ifdef ADC_RESOLUTION_12B
+ case 12U:
+ *hal_resolution = ADC_RESOLUTION_12B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_12B */
+#ifdef ADC_RESOLUTION_10B
+ case 10U:
+ *hal_resolution = ADC_RESOLUTION_10B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_10B */
+#ifdef ADC_RESOLUTION_8B
+ case 8U:
+ *hal_resolution = ADC_RESOLUTION_8B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_8B */
+#ifdef ADC_RESOLUTION_6B
+ case 6U:
+ *hal_resolution = ADC_RESOLUTION_6B;
+ return RT_EOK;
+#endif /* ADC_RESOLUTION_6B */
+ default:
+ return -RT_EINVAL;
+ }
+}
+#endif /* defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC) */
+
+#if defined(STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA)
+/**
+ * @brief Normalize a raw ADC sample to the 12-bit temperature calibration scale.
+ * @param raw_value Raw ADC sample value.
+ * @param resolution_bits ADC conversion resolution used for @p raw_value.
+ * @param raw_12b Pointer to the output sample normalized to 12-bit scale.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_normalize_to_12b(rt_uint32_t raw_value, rt_uint8_t resolution_bits, rt_uint32_t *raw_12b)
+{
+ if ((raw_12b == RT_NULL) || (resolution_bits == 0U) || (resolution_bits > 16U))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (resolution_bits > 12U)
+ {
+ *raw_12b = raw_value >> (resolution_bits - 12U);
+ }
+ else
+ {
+ *raw_12b = raw_value << (12U - resolution_bits);
+ }
+
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA) */
+
+/**
+ * @brief Calculate STM32 internal temperature sensor value in degrees Celsius.
+ * @param device ADC device handle.
+ * @param raw_value Raw ADC sample value from the temperature sensor channel.
+ * @param vref_mv Current analog reference voltage in millivolts.
+ * @param resolution_bits ADC conversion resolution used for @p raw_value.
+ * @param temperature_c Pointer to the output temperature in degrees Celsius.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_calc_temperature(rt_adc_device_t device, rt_uint32_t raw_value,
+ rt_uint32_t vref_mv, rt_uint8_t resolution_bits,
+ rt_int32_t *temperature_c)
+{
+#if defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC)
+ struct stm32_adc *adc;
+ uint32_t hal_resolution;
+ rt_err_t result;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_get_hal_resolution(resolution_bits, &hal_resolution);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ *temperature_c = (rt_int32_t)STM32_ADC_CALC_TEMPERATURE(adc, vref_mv, raw_value, hal_resolution);
+ return RT_EOK;
+#elif defined(STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA)
+ struct stm32_adc *adc;
+ rt_uint32_t raw_12b;
+ rt_uint32_t raw_calibrated;
+ rt_int32_t cal1;
+ rt_int32_t cal2;
+ rt_int32_t denominator;
+ rt_int64_t numerator;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (vref_mv == 0U) || (temperature_c == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_normalize_to_12b(raw_value, resolution_bits, &raw_12b);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ raw_calibrated = (rt_uint32_t)(((rt_uint64_t)raw_12b * (rt_uint64_t)vref_mv +
+ (TEMPSENSOR_CAL_VREFANALOG / 2U)) / TEMPSENSOR_CAL_VREFANALOG);
+ cal1 = (rt_int32_t)(*TEMPSENSOR_CAL1_ADDR);
+ cal2 = (rt_int32_t)(*TEMPSENSOR_CAL2_ADDR);
+ denominator = cal2 - cal1;
+ if (denominator == 0)
+ {
+ return -RT_EINVAL;
+ }
+
+ numerator = ((rt_int64_t)((rt_int32_t)raw_calibrated - cal1) *
+ (rt_int64_t)(TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP));
+ if (numerator >= 0)
+ {
+ numerator += denominator / 2;
+ }
+ else
+ {
+ numerator -= denominator / 2;
+ }
+
+ *temperature_c = (rt_int32_t)(numerator / denominator) + TEMPSENSOR_CAL1_TEMP;
+ return RT_EOK;
+#else
+ RT_UNUSED(device);
+ RT_UNUSED(raw_value);
+ RT_UNUSED(vref_mv);
+ RT_UNUSED(resolution_bits);
+ RT_UNUSED(temperature_c);
+
+ return -RT_ENOSYS;
+#endif /* defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC) */
+}
+
+#if defined(STM32_ADC_HAS_ENUM_RANK)
+/**
+ * @brief STM32 ADC regular-rank mapping entry.
+ */
+struct stm32_adc_rank_map
+{
+ rt_bool_t valid; /**< Whether this logical rank is supported by HAL. */
+ uint32_t hal_rank; /**< HAL regular-rank enumeration value. */
+};
+
+/**
+ * @brief HAL regular-rank values indexed by logical rank.
+ */
+static const struct stm32_adc_rank_map stm32_adc_rank_table[] = {
+ { RT_FALSE, 0U },
+#ifdef ADC_REGULAR_RANK_1
+ { RT_TRUE, ADC_REGULAR_RANK_1 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_1 */
+#ifdef ADC_REGULAR_RANK_2
+ { RT_TRUE, ADC_REGULAR_RANK_2 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_2 */
+#ifdef ADC_REGULAR_RANK_3
+ { RT_TRUE, ADC_REGULAR_RANK_3 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_3 */
+#ifdef ADC_REGULAR_RANK_4
+ { RT_TRUE, ADC_REGULAR_RANK_4 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_4 */
+#ifdef ADC_REGULAR_RANK_5
+ { RT_TRUE, ADC_REGULAR_RANK_5 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_5 */
+#ifdef ADC_REGULAR_RANK_6
+ { RT_TRUE, ADC_REGULAR_RANK_6 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_6 */
+#ifdef ADC_REGULAR_RANK_7
+ { RT_TRUE, ADC_REGULAR_RANK_7 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_7 */
+#ifdef ADC_REGULAR_RANK_8
+ { RT_TRUE, ADC_REGULAR_RANK_8 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_8 */
+#ifdef ADC_REGULAR_RANK_9
+ { RT_TRUE, ADC_REGULAR_RANK_9 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_9 */
+#ifdef ADC_REGULAR_RANK_10
+ { RT_TRUE, ADC_REGULAR_RANK_10 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_10 */
+#ifdef ADC_REGULAR_RANK_11
+ { RT_TRUE, ADC_REGULAR_RANK_11 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_11 */
+#ifdef ADC_REGULAR_RANK_12
+ { RT_TRUE, ADC_REGULAR_RANK_12 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_12 */
+#ifdef ADC_REGULAR_RANK_13
+ { RT_TRUE, ADC_REGULAR_RANK_13 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_13 */
+#ifdef ADC_REGULAR_RANK_14
+ { RT_TRUE, ADC_REGULAR_RANK_14 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_14 */
+#ifdef ADC_REGULAR_RANK_15
+ { RT_TRUE, ADC_REGULAR_RANK_15 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_15 */
+#ifdef ADC_REGULAR_RANK_16
+ { RT_TRUE, ADC_REGULAR_RANK_16 },
+#else
+ { RT_FALSE, 0U },
+#endif /* ADC_REGULAR_RANK_16 */
+};
+#endif /* defined(STM32_ADC_HAS_ENUM_RANK) */
+
+/**
+ * @brief Convert one STM32 HAL status code to an RT-Thread error code.
+ * @param status STM32 HAL operation status.
+ * @return RT-Thread operation status.
+ */
+static rt_err_t stm32_hal_status_to_rt_err(HAL_StatusTypeDef status)
+{
+ switch (status)
+ {
+ case HAL_OK:
+ return RT_EOK;
+
+ case HAL_BUSY:
+ return -RT_EBUSY;
+
+ case HAL_TIMEOUT:
+ return -RT_ETIMEOUT;
+
+ case HAL_ERROR:
+ default:
+ return -RT_ERROR;
+ }
+}
+
+/**
+ * @brief Get one HAL rank value from a logical rank index.
+ * @param rank Logical rank index starting from 1.
+ * @param hal_rank Pointer to the output HAL rank value.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_get_rank_value(rt_uint32_t rank, uint32_t *hal_rank)
+{
+#if defined(STM32_ADC_HAS_ENUM_RANK)
+ if ((rank >= RT_ARRAY_SIZE(stm32_adc_rank_table)) || (stm32_adc_rank_table[rank].valid != RT_TRUE))
+ {
+ return -RT_EINVAL;
+ }
+
+ *hal_rank = stm32_adc_rank_table[rank].hal_rank;
+#elif defined(STM32_ADC_HAS_CHANNEL_NUMBER_RANK)
+ RT_UNUSED(rank);
+ *hal_rank = ADC_RANK_CHANNEL_NUMBER;
+#else
+ *hal_rank = rank;
+#endif /* defined(STM32_ADC_HAS_ENUM_RANK) */
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Enable ADC analog support required by a specific series.
+ */
+static void stm32_adc_enable_analog_support(void)
+{
+#if defined(STM32_ADC_NEEDS_ANALOG_SUPPLY)
+ __HAL_RCC_PWR_CLK_ENABLE();
+ HAL_PWREx_EnableVddA();
+#endif /* defined(STM32_ADC_NEEDS_ANALOG_SUPPLY) */
+}
+
+#if defined(STM32_ADC_HAS_CALIBRATION)
+/**
+ * @brief Get the input-mode mask from STM32 private configuration.
+ * @param cfg Pointer to the STM32 backend private configuration.
+ * @return RT_ADC_INPUT_MODE_* mask used by calibration.
+ */
+static rt_uint8_t stm32_adc_get_input_modes(const struct stm32_adc_private_cfg *cfg)
+{
+ if (cfg->input_modes == 0U)
+ {
+ return RT_ADC_INPUT_MODE_SINGLE_ENDED;
+ }
+
+ return cfg->input_modes;
+}
+
+/**
+ * @brief Run one calibration pass for a selected ADC input mode.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param calibration_mode HAL calibration mode selector.
+ * @param input_mode HAL single-ended or differential selector.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_run_calibration_pass(struct stm32_adc *adc, uint32_t calibration_mode, uint32_t input_mode)
+{
+ HAL_StatusTypeDef status;
+#if defined(STM32_ADC_HAS_SIMPLE_CALIBRATION)
+ RT_UNUSED(calibration_mode);
+ status = HAL_ADCEx_Calibration_Start(&adc->handle, input_mode);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s calibration failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+ return RT_EOK;
+#elif defined(STM32_ADC_HAS_LINEAR_CALIBRATION)
+ status = HAL_ADCEx_Calibration_Start(&adc->handle, calibration_mode, input_mode);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s calibration failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+ return RT_EOK;
+#else
+ RT_UNUSED(status);
+ RT_UNUSED(calibration_mode);
+ RT_UNUSED(input_mode);
+ return -RT_ENOSYS;
+#endif /* calibration feature buckets */
+}
+
+/**
+ * @brief Run one series-specific ADC calibration from STM32 private configuration.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param private_cfg Pointer to the STM32 backend private configuration.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_run_calibration(struct stm32_adc *adc, const struct stm32_adc_private_cfg *private_cfg)
+{
+ rt_err_t result;
+ rt_uint8_t requested_input_modes;
+#if defined(STM32_ADC_HAS_LINEAR_CALIBRATION) && defined(ADC_CALIB_OFFSET)
+ rt_bool_t single_ended_calibrated;
+#endif /* defined(STM32_ADC_HAS_LINEAR_CALIBRATION) && defined(ADC_CALIB_OFFSET) */
+
+ requested_input_modes = stm32_adc_get_input_modes(private_cfg);
+ LOG_D("%s calibration request: modes=0x%02x", adc->name, requested_input_modes);
+
+#if defined(STM32_ADC_HAS_SIMPLE_CALIBRATION)
+ if ((requested_input_modes & RT_ADC_INPUT_MODE_SINGLE_ENDED) != 0U)
+ {
+ result = stm32_adc_run_calibration_pass(adc, 0U, STM32_ADC_SINGLE_ENDED_VALUE);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ LOG_I("%s single-ended calibration done", adc->name);
+ }
+ if ((requested_input_modes & RT_ADC_INPUT_MODE_DIFFERENTIAL) != 0U)
+ {
+ result = stm32_adc_run_calibration_pass(adc, 0U, STM32_ADC_DIFFERENTIAL_VALUE);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ LOG_I("%s differential calibration done", adc->name);
+ }
+ return RT_EOK;
+#elif defined(STM32_ADC_HAS_LINEAR_CALIBRATION)
+#if defined(ADC_CALIB_OFFSET)
+ single_ended_calibrated = RT_FALSE;
+#endif /* defined(ADC_CALIB_OFFSET) */
+ if ((requested_input_modes & RT_ADC_INPUT_MODE_SINGLE_ENDED) != 0U)
+ {
+ result = stm32_adc_run_calibration_pass(adc, ADC_CALIB_OFFSET_LINEARITY, STM32_ADC_SINGLE_ENDED_VALUE);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+#if defined(ADC_CALIB_OFFSET)
+ single_ended_calibrated = RT_TRUE;
+#endif /* defined(ADC_CALIB_OFFSET) */
+ LOG_I("%s single-ended calibration done", adc->name);
+ }
+ if ((requested_input_modes & RT_ADC_INPUT_MODE_DIFFERENTIAL) != 0U)
+ {
+ result = stm32_adc_run_calibration_pass(adc,
+#if defined(ADC_CALIB_OFFSET)
+ (single_ended_calibrated == RT_TRUE) ? ADC_CALIB_OFFSET : ADC_CALIB_OFFSET_LINEARITY,
+#else
+ ADC_CALIB_OFFSET_LINEARITY,
+#endif /* defined(ADC_CALIB_OFFSET) */
+ STM32_ADC_DIFFERENTIAL_VALUE);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ LOG_I("%s differential calibration done", adc->name);
+ }
+ return RT_EOK;
+#else
+ RT_UNUSED(requested_input_modes);
+ return -RT_ENOSYS;
+#endif /* calibration feature buckets */
+}
+
+#endif /* defined(STM32_ADC_HAS_CALIBRATION) */
+
+/**
+ * @brief Fill the HAL ADC initialization structure from the device object.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_fill_init(struct stm32_adc *adc)
+{
+ ADC_TypeDef *instance;
+
+ LOG_D("%s fill init", adc->name);
+ instance = adc->handle.Instance;
+ rt_memset(&adc->handle, 0, sizeof(adc->handle));
+ adc->handle.Instance = instance;
+#ifdef ADC_DEFAULT_CLOCK_PRESCALER
+ adc->handle.Init.ClockPrescaler = ADC_DEFAULT_CLOCK_PRESCALER;
+#endif /* ADC_DEFAULT_CLOCK_PRESCALER */
+#if defined(STM32_ADC_HAS_INIT_DATA_ALIGN)
+ adc->handle.Init.DataAlign = (adc->config.data_align != 0U) ? adc->config.data_align : ADC_DEFAULT_DATA_ALIGN;
+#endif /* defined(STM32_ADC_HAS_INIT_DATA_ALIGN) */
+ adc->handle.Init.ScanConvMode = STM32_ADC_SCAN_MODE_DISABLE;
+#if defined(STM32_ADC_HAS_INIT_EOC_SELECTION)
+ adc->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+#endif /* defined(STM32_ADC_HAS_INIT_EOC_SELECTION) */
+ adc->handle.Init.ContinuousConvMode = DISABLE;
+#if defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT)
+ adc->handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
+#endif /* defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT) */
+#if defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION)
+ adc->handle.Init.NbrOfConversion = 1;
+#endif /* defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION) */
+ adc->handle.Init.DiscontinuousConvMode = DISABLE;
+#if defined(STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION)
+ adc->handle.Init.NbrOfDiscConversion = 1;
+#endif /* defined(STM32_ADC_HAS_INIT_NBR_OF_DISC_CONVERSION) */
+ adc->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
+#if defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE)
+ adc->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
+#endif /* defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE) */
+#if defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS)
+ adc->handle.Init.DMAContinuousRequests = DISABLE;
+#endif /* defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS) */
+#if defined(STM32_ADC_HAS_HW_OVERSAMPLING)
+ adc->handle.Init.OversamplingMode = DISABLE;
+ adc->handle.Init.Oversampling.Ratio = 0U;
+ adc->handle.Init.Oversampling.RightBitShift = 0U;
+ adc->handle.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
+ adc->handle.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
+#endif /* defined(STM32_ADC_HAS_HW_OVERSAMPLING) */
+
+#if defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION)
+ adc->handle.Init.Resolution = (adc->config.resolution != 0U) ? adc->config.resolution : ADC_DEFAULT_RESOLUTION;
+#else
+ if (adc->config.resolution != 0U)
+ {
+ return -RT_ENOSYS;
+ }
+#endif /* defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION) */
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Force one ADC device back to regular polling conversion mode.
+ * @param adc Pointer to the STM32 ADC device object.
+ *
+ * Sequence reads use HAL_ADC_Start() and HAL_ADC_PollForConversion(), so any
+ * DMA request state left by board initialization must be cleared before
+ * starting a polling conversion.
+ */
+static void stm32_adc_force_poll_mode(struct stm32_adc *adc)
+{
+#if defined(ADC_CR2_DMA)
+ CLEAR_BIT(adc->handle.Instance->CR2, ADC_CR2_DMA);
+#endif /* defined(ADC_CR2_DMA) */
+
+#if defined(ADC_CR2_DDS)
+ CLEAR_BIT(adc->handle.Instance->CR2, ADC_CR2_DDS);
+#endif /* defined(ADC_CR2_DDS) */
+
+#if defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS)
+ adc->handle.Init.DMAContinuousRequests = DISABLE;
+#endif /* defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS) */
+
+#if defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT)
+ adc->handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
+#endif /* defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT) */
+}
+
+/**
+ * @brief Open one STM32 ADC device.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_open(struct rt_adc_device *device)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+ rt_err_t result;
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ LOG_D("%s open start", adc->name);
+ stm32_adc_enable_analog_support();
+ result = stm32_adc_fill_init(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ result = stm32_adc_apply_oversampling(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ status = HAL_ADC_Init(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s init failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+#if defined(STM32_ADC_HAS_CALIBRATION)
+ result = stm32_adc_run_calibration(adc, &adc->config);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+#endif /* defined(STM32_ADC_HAS_CALIBRATION) */
+ LOG_I("%s opened", adc->name);
+ return RT_EOK;
+}
+
+/**
+ * @brief Close one STM32 ADC device.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_close(struct rt_adc_device *device)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ status = HAL_ADC_Stop(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_W("%s stop during close failed", adc->name);
+ }
+ status = HAL_ADC_DeInit(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_W("%s deinit during close failed", adc->name);
+ return -RT_ERROR;
+ }
+ LOG_I("%s closed", adc->name);
+ return RT_EOK;
+}
+
+#if defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS)
+/**
+ * @brief Get the HAL single-ended/differential selector from private configuration.
+ * @param cfg Pointer to the STM32 backend private configuration.
+ * @param single_diff Pointer to the output HAL single-ended or differential selector.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_get_single_diff(const struct stm32_adc_private_cfg *cfg, uint32_t *single_diff)
+{
+ *single_diff = ((cfg->input_modes & RT_ADC_INPUT_MODE_DIFFERENTIAL) != 0U) ?
+ STM32_ADC_DIFFERENTIAL_VALUE : STM32_ADC_SINGLE_ENDED_VALUE;
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS) */
+
+/**
+ * @brief Get one HAL sampling-time value from STM32 private configuration.
+ * @param cfg Pointer to the STM32 backend private configuration.
+ * @param sampling_time Pointer to the output HAL sampling-time value.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_sampling_time(const struct stm32_adc_private_cfg *cfg, uint32_t *sampling_time)
+{
+ if ((cfg == RT_NULL) || (sampling_time == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ *sampling_time = (cfg->sampling_time != 0U) ? cfg->sampling_time : ADC_DEFAULT_SAMPLING_TIME;
+ return RT_EOK;
+}
+
+/**
+ * @brief Configure one ADC regular rank.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel RT-Thread ADC channel identifier.
+ * @param rank Logical regular rank index.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_configure_rank(struct stm32_adc *adc, rt_uint8_t channel, rt_uint32_t rank)
+{
+ ADC_ChannelConfTypeDef config;
+ HAL_StatusTypeDef status;
+ uint32_t hal_channel;
+ uint32_t hal_rank;
+ uint32_t sampling_time;
+ rt_err_t result;
+
+ result = stm32_adc_get_channel_for_instance(adc, channel, &hal_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_get_rank_value(rank, &hal_rank);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_get_sampling_time(&adc->config, &sampling_time);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ rt_memset(&config, 0, sizeof(config));
+ config.Channel = hal_channel;
+ config.Rank = hal_rank;
+ config.SamplingTime = sampling_time;
+#if defined(STM32_ADC_HAS_CONFIG_OFFSET)
+ config.Offset = 0;
+#endif /* defined(STM32_ADC_HAS_CONFIG_OFFSET) */
+#if defined(STM32_ADC_HAS_CONFIG_OFFSET_NUMBER)
+ config.OffsetNumber = ADC_OFFSET_NONE;
+#endif /* defined(STM32_ADC_HAS_CONFIG_OFFSET_NUMBER) */
+#if defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS)
+ result = stm32_adc_get_single_diff(&adc->config, &config.SingleDiff);
+ if ((result != RT_EOK) && (result != -RT_ENOSYS))
+ {
+ return result;
+ }
+#endif /* defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS) */
+
+ status = HAL_ADC_ConfigChannel(&adc->handle, &config);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s configure rank failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Clear backend ADC channel/rank configuration explicitly.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @return Operation status.
+ *
+ * This operation is intentionally not called from normal session configuration.
+ * It is an explicit escape hatch for users that need to clear stale
+ * channel-number rank configuration before rebuilding a conversion session.
+ */
+static rt_err_t stm32_adc_clear_channel_config(struct stm32_adc *adc)
+{
+#if defined(STM32_ADC_HAS_CHANNEL_NUMBER_RANK) && defined(ADC_RANK_NONE)
+ ADC_ChannelConfTypeDef config;
+ HAL_StatusTypeDef status;
+ rt_uint8_t channel;
+ uint32_t hal_channel;
+ uint32_t sampling_time;
+ rt_err_t result;
+
+ result = stm32_adc_get_sampling_time(&adc->config, &sampling_time);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ for (channel = 0U; channel < STM32_ADC_MAX_CHANNELS; channel++)
+ {
+ result = stm32_adc_get_channel_for_instance(adc, channel, &hal_channel);
+ if (result != RT_EOK)
+ {
+ continue;
+ }
+
+ rt_memset(&config, 0, sizeof(config));
+ config.Channel = hal_channel;
+ config.Rank = ADC_RANK_NONE;
+ config.SamplingTime = sampling_time;
+#if defined(STM32_ADC_HAS_CONFIG_OFFSET)
+ config.Offset = 0;
+#endif /* defined(STM32_ADC_HAS_CONFIG_OFFSET) */
+#if defined(STM32_ADC_HAS_CONFIG_OFFSET_NUMBER)
+ config.OffsetNumber = ADC_OFFSET_NONE;
+#endif /* defined(STM32_ADC_HAS_CONFIG_OFFSET_NUMBER) */
+#if defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS)
+ result = stm32_adc_get_single_diff(&adc->config, &config.SingleDiff);
+ if ((result != RT_EOK) && (result != -RT_ENOSYS))
+ {
+ return result;
+ }
+#endif /* defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS) */
+
+ status = HAL_ADC_ConfigChannel(&adc->handle, &config);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s clear channel config failed: channel=%u", adc->name, (unsigned int)channel);
+ return stm32_hal_status_to_rt_err(status);
+ }
+ }
+
+ LOG_D("%s channel config cleared", adc->name);
+ return RT_EOK;
+#else
+ RT_UNUSED(adc);
+ return -RT_ENOSYS;
+#endif /* defined(STM32_ADC_HAS_CHANNEL_NUMBER_RANK) && defined(ADC_RANK_NONE) */
+}
+
+/**
+ * @brief Configure all regular ADC ranks for one session.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_configure_session_ranks(struct stm32_adc *adc, rt_uint32_t channels)
+{
+ rt_uint32_t rank;
+ rt_uint8_t channel;
+ rt_err_t result;
+
+ rank = 1U;
+ while (channels != 0U)
+ {
+ if (rank > STM32_ADC_MAX_SEQUENCE)
+ {
+ return -RT_EINVAL;
+ }
+
+ channel = rt_adc_channel_mask_take_lsb(&channels);
+ result = stm32_adc_configure_rank(adc, channel, rank);
+ if (result != RT_EOK)
+ {
+ LOG_E("%s rank config failed: channel=%u rank=%lu result=%d",
+ adc->name, (unsigned int)channel, (unsigned long)rank, result);
+ return result;
+ }
+ rank++;
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Apply one complete regular ADC configuration to STM32 HAL.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_apply_regular_config(struct stm32_adc *adc, rt_uint32_t channels)
+{
+ HAL_StatusTypeDef status;
+ rt_size_t channel_count;
+ rt_err_t result;
+
+ channel_count = rt_adc_channel_mask_count(channels);
+ if ((channel_count == 0U) || (channel_count > STM32_ADC_MAX_SEQUENCE))
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_fill_init(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_apply_oversampling(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ adc->handle.Init.ScanConvMode = (channel_count > 1U) ? STM32_ADC_SCAN_MODE_ENABLE : STM32_ADC_SCAN_MODE_DISABLE;
+#if defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION)
+ adc->handle.Init.NbrOfConversion = channel_count;
+#endif /* defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION) */
+
+#if defined(STM32_ADC_HAS_INIT_EOC_SELECTION)
+ adc->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+#endif /* defined(STM32_ADC_HAS_INIT_EOC_SELECTION) */
+
+ /*
+ * Multi-rank polling must not let one HAL_ADC_Start() drain the whole
+ * regular sequence, otherwise DR can be overwritten before the CPU reads it.
+ * Discontinuous mode makes each HAL_ADC_Start() convert one rank only.
+ */
+ adc->handle.Init.DiscontinuousConvMode = (channel_count > 1U) ? ENABLE : DISABLE;
+
+ stm32_adc_force_poll_mode(adc);
+
+ status = HAL_ADC_Init(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s regular init failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+ return stm32_adc_configure_session_ranks(adc, channels);
+}
+
+#if STM32_ADC_USING_DMA_STREAM
+/**
+ * @brief Apply one complete regular ADC configuration for circular DMA stream mode.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_apply_stream_regular_config(struct stm32_adc *adc, rt_uint32_t channels)
+{
+ HAL_StatusTypeDef status;
+ rt_size_t channel_count;
+ rt_err_t result;
+
+ channel_count = rt_adc_channel_mask_count(channels);
+ if ((channel_count == 0U) || (channel_count > STM32_ADC_MAX_SEQUENCE))
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_fill_init(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_apply_oversampling(adc);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+#if defined(STM32_ADC_USING_TRIGGER)
+ struct stm32_adc_trigger_fields trigger_fields;
+ if (adc->prepared_trigger_valid == RT_TRUE)
+ {
+ trigger_fields = adc->prepared_trigger;
+ }
+ else
+ {
+ result = stm32_adc_trigger_fields_get(adc, RT_NULL, &trigger_fields);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ }
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+
+ adc->handle.Init.ScanConvMode = (channel_count > 1U) ? STM32_ADC_SCAN_MODE_ENABLE : STM32_ADC_SCAN_MODE_DISABLE;
+#if defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION)
+ adc->handle.Init.NbrOfConversion = channel_count;
+#endif /* defined(STM32_ADC_HAS_INIT_NBR_OF_CONVERSION) */
+#if defined(STM32_ADC_HAS_INIT_EOC_SELECTION) && defined(ADC_EOC_SEQ_CONV)
+ adc->handle.Init.EOCSelection = ADC_EOC_SEQ_CONV;
+#elif defined(STM32_ADC_HAS_INIT_EOC_SELECTION)
+ adc->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+#endif /* defined(STM32_ADC_HAS_INIT_EOC_SELECTION) && defined(ADC_EOC_SEQ_CONV) */
+#if defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT)
+ adc->handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
+#endif /* defined(STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT) */
+#if defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS)
+ adc->handle.Init.DMAContinuousRequests = ENABLE;
+#endif /* defined(STM32_ADC_HAS_INIT_DMA_CONT_REQUESTS) */
+#if defined(STM32_ADC_USING_TRIGGER)
+ adc->handle.Init.ContinuousConvMode = (trigger_fields.selector == ADC_SOFTWARE_START) ? ENABLE : DISABLE;
+ adc->handle.Init.ExternalTrigConv = trigger_fields.selector;
+#if defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE)
+ adc->handle.Init.ExternalTrigConvEdge = trigger_fields.edge;
+#endif /* defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE) */
+#else
+ adc->handle.Init.ContinuousConvMode = ENABLE;
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+
+ status = HAL_ADC_Init(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_E("%s stream regular init failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+
+ return stm32_adc_configure_session_ranks(adc, channels);
+}
+#endif /* STM32_ADC_USING_DMA_STREAM */
+
+/**
+ * @brief Configure one ADC conversion session on one STM32 ADC device.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_session_config(struct rt_adc_device *device, rt_uint32_t channels)
+{
+ struct stm32_adc *adc;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ return stm32_adc_apply_regular_config(adc, channels);
+}
+
+/**
+ * @brief Start one STM32 ADC finite sequence session.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the ADC sequence request object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_sequence_start(struct rt_adc_device *device, rt_uint32_t channels,
+ const struct rt_adc_sequence_cfg *cfg)
+{
+ RT_UNUSED(device);
+ RT_UNUSED(channels);
+ RT_UNUSED(cfg);
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Read one sample from one STM32 ADC sequence session.
+ * @param device Pointer to the ADC device object.
+ * @param value Pointer to the output sample value.
+ * @param timeout_ms Read timeout in milliseconds.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_sequence_read(struct rt_adc_device *device, rt_uint32_t *value, rt_int32_t timeout_ms)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+ uint32_t timeout;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ status = HAL_ADC_Start(&adc->handle);
+ if (status != HAL_OK)
+ {
+ goto fail;
+ }
+
+ timeout = (timeout_ms < 0) ? HAL_MAX_DELAY : (uint32_t)timeout_ms;
+ status = HAL_ADC_PollForConversion(&adc->handle, timeout);
+ if (status != HAL_OK)
+ {
+ goto fail;
+ }
+
+ *value = (rt_uint32_t)HAL_ADC_GetValue(&adc->handle);
+ LOG_D("%s sample read: value=%lu", adc->name, (unsigned long)*value);
+
+ return RT_EOK;
+
+fail:
+ LOG_E("%s sequence read failed: status=%d state=0x%08lx error=0x%08lx",
+ adc->name, (int)status, (unsigned long)adc->handle.State, (unsigned long)adc->handle.ErrorCode);
+
+ return stm32_hal_status_to_rt_err(status);
+}
+/**
+ * @brief Stop one STM32 ADC sequence session.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_sequence_stop(struct rt_adc_device *device)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+ rt_err_t result;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ LOG_D("%s sequence stop", adc->name);
+ result = RT_EOK;
+
+ status = HAL_ADC_Stop(&adc->handle);
+ if (status != HAL_OK)
+ {
+ LOG_W("%s sequence stop failed", adc->name);
+ return stm32_hal_status_to_rt_err(status);
+ }
+
+ return result;
+}
+
+#if STM32_ADC_USING_DMA_STREAM
+#if defined(STM32_ADC_NEEDS_DMA_CACHE_MAINTENANCE)
+/** @brief STM32 Cortex-M7 D-Cache line size used by DMA buffers. */
+#define STM32_ADC_DMA_CACHE_LINE_SIZE 32U
+
+/**
+ * @brief Release any cache-aligned ADC stream DMA buffer owned by the driver.
+ * @param adc Pointer to the STM32 ADC device object.
+ */
+static void stm32_adc_stream_release_cache_buffer(struct stm32_adc *adc)
+{
+ if ((adc != RT_NULL) && (adc->cache_dma_buffer != RT_NULL))
+ {
+ LOG_D("%s stream cache buffer release: buffer=%p", adc->name, adc->cache_dma_buffer);
+ rt_free_align(adc->cache_dma_buffer);
+ adc->cache_dma_buffer = RT_NULL;
+ }
+}
+
+/**
+ * @brief Select a D-Cache-safe DMA buffer for one ADC stream session.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the stream configuration object.
+ * @param dma_buffer Pointer to the selected DMA buffer output.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_prepare_cache_buffer(struct stm32_adc *adc, const struct rt_adc_stream_cfg *cfg,
+ rt_uint32_t **dma_buffer)
+{
+ rt_size_t bytes;
+ rt_size_t cache_bytes;
+
+ bytes = cfg->dma_buffer_length * sizeof(rt_uint32_t);
+ cache_bytes = RT_ALIGN(bytes, STM32_ADC_DMA_CACHE_LINE_SIZE);
+ stm32_adc_stream_release_cache_buffer(adc);
+
+ if (RT_IS_ALIGN((rt_ubase_t)cfg->dma_buffer, STM32_ADC_DMA_CACHE_LINE_SIZE) &&
+ RT_IS_ALIGN(bytes, STM32_ADC_DMA_CACHE_LINE_SIZE))
+ {
+ *dma_buffer = cfg->dma_buffer;
+ LOG_D("%s stream cache buffer direct: buffer=%p bytes=%u", adc->name, *dma_buffer, (unsigned int)bytes);
+ }
+ else
+ {
+ adc->cache_dma_buffer = (rt_uint32_t *)rt_malloc_align(cache_bytes, STM32_ADC_DMA_CACHE_LINE_SIZE);
+ if (adc->cache_dma_buffer == RT_NULL)
+ {
+ LOG_E("%s stream cache buffer alloc failed: bytes=%u aligned=%u",
+ adc->name, (unsigned int)bytes, (unsigned int)cache_bytes);
+ return -RT_ENOMEM;
+ }
+
+ *dma_buffer = adc->cache_dma_buffer;
+ LOG_W("%s stream cache buffer fallback: caller=%p dma=%p bytes=%u",
+ adc->name, cfg->dma_buffer, *dma_buffer, (unsigned int)bytes);
+ }
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, *dma_buffer, cache_bytes);
+ adc->device.stream_ctrl.dma_buffer = *dma_buffer;
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Invalidate a completed ADC stream DMA RX sample range.
+ * @param device Pointer to the ADC device object.
+ * @param sample_buffer Pointer to the sample buffer to synchronize.
+ * @param sample_count Number of samples to synchronize.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_sync(struct rt_adc_device *device, const rt_uint32_t *sample_buffer, rt_size_t sample_count)
+{
+ rt_ubase_t start;
+ rt_ubase_t end;
+ rt_ubase_t aligned_start;
+ rt_ubase_t aligned_end;
+
+ if ((device == RT_NULL) || (sample_buffer == RT_NULL) || (sample_count == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ start = (rt_ubase_t)sample_buffer;
+ end = start + sample_count * sizeof(rt_uint32_t);
+ aligned_start = RT_ALIGN_DOWN(start, STM32_ADC_DMA_CACHE_LINE_SIZE);
+ aligned_end = RT_ALIGN(end, STM32_ADC_DMA_CACHE_LINE_SIZE);
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, (void *)aligned_start, aligned_end - aligned_start);
+
+ return RT_EOK;
+}
+#else
+/**
+ * @brief Release any cache-aligned ADC stream DMA buffer owned by the driver.
+ * @param adc Pointer to the STM32 ADC device object.
+ */
+static void stm32_adc_stream_release_cache_buffer(struct stm32_adc *adc)
+{
+ RT_UNUSED(adc);
+}
+
+/**
+ * @brief Select the caller-owned DMA buffer for one ADC stream session.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the stream configuration object.
+ * @param dma_buffer Pointer to the selected DMA buffer output.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_prepare_cache_buffer(struct stm32_adc *adc, const struct rt_adc_stream_cfg *cfg,
+ rt_uint32_t **dma_buffer)
+{
+ RT_UNUSED(adc);
+
+ *dma_buffer = cfg->dma_buffer;
+ return RT_EOK;
+}
+
+/**
+ * @brief Synchronize a backend DMA sample range before CPU access.
+ * @param device Pointer to the ADC device object.
+ * @param sample_buffer Pointer to the DMA sample buffer.
+ * @param sample_count Number of samples to synchronize.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_sync(struct rt_adc_device *device, const rt_uint32_t *sample_buffer, rt_size_t sample_count)
+{
+ RT_UNUSED(device);
+ RT_UNUSED(sample_buffer);
+ RT_UNUSED(sample_count);
+
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_NEEDS_DMA_CACHE_MAINTENANCE) */
+
+/**
+ * @brief Configure STM32 DMA transfer event interrupts for one stream session.
+ * @param dma_handle Pointer to the DMA handle linked to the ADC stream.
+ * @param mode Effective ADC stream DMA event mode.
+ */
+static void stm32_adc_stream_configure_dma_events(DMA_HandleTypeDef *dma_handle, enum rt_adc_stream_dma_event_mode mode)
+{
+ if (dma_handle == RT_NULL)
+ {
+ return;
+ }
+
+ if (mode == RT_ADC_STREAM_DMA_EVENT_NONE)
+ {
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_TC);
+ }
+ else if (mode == RT_ADC_STREAM_DMA_EVENT_FULL_ONLY)
+ {
+ __HAL_DMA_DISABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_TC);
+ }
+ else
+ {
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_HT);
+ __HAL_DMA_ENABLE_IT(dma_handle, DMA_IT_TC);
+ }
+}
+
+/**
+ * @brief Start one STM32 ADC stream session using circular DMA.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the stream configuration object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_start(struct rt_adc_device *device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+ rt_uint32_t *dma_buffer;
+ rt_err_t result;
+
+ adc = RT_NULL;
+ dma_buffer = RT_NULL;
+ result = RT_EOK;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if ((adc == RT_NULL) || (adc->dma_rx == RT_NULL))
+ {
+ result = -RT_ENOSYS;
+ goto exit;
+ }
+
+ result = stm32_adc_apply_stream_regular_config(adc, channels);
+ if (result != RT_EOK)
+ {
+ goto exit;
+ }
+
+ result = stm32_adc_stream_prepare_cache_buffer(adc, cfg, &dma_buffer);
+ if (result != RT_EOK)
+ {
+ goto exit;
+ }
+
+ result = stm32_dma_setup(&adc->dma_handle, &adc->handle, &adc->handle.DMA_Handle, adc->dma_rx);
+ if (result != RT_EOK)
+ {
+ goto exit;
+ }
+ status = HAL_ADC_Start_DMA(&adc->handle, dma_buffer, (uint32_t)cfg->dma_buffer_length);
+ if (status != HAL_OK)
+ {
+ result = stm32_hal_status_to_rt_err(status);
+ goto exit;
+ }
+
+ stm32_adc_stream_configure_dma_events(&adc->dma_handle, adc->device.stream_ctrl.dma_event_mode);
+exit:
+ if (result != RT_EOK)
+ {
+ LOG_E("%s stream startfailed: result=%d", adc->name, result);
+ }
+
+ return result;
+}
+
+/**
+ * @brief Stop one STM32 ADC stream session and release DMA resources.
+ * @param device Pointer to the ADC device object.
+ * @param hardware_stopped Pointer to the hardware-stop state output.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_stream_stop(struct rt_adc_device *device, rt_bool_t *hardware_stopped)
+{
+ struct stm32_adc *adc;
+ HAL_StatusTypeDef status;
+ rt_bool_t hal_stopped;
+ rt_bool_t dma_attached;
+ rt_bool_t dma_released;
+ rt_err_t result;
+
+ *hardware_stopped = RT_FALSE;
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = RT_EOK;
+ hal_stopped = RT_FALSE;
+ dma_released = RT_FALSE;
+ dma_attached = (adc->handle.DMA_Handle == &adc->dma_handle) ? RT_TRUE : RT_FALSE;
+
+ if (dma_attached != RT_TRUE)
+ {
+ adc->handle.DMA_Handle = RT_NULL;
+ adc->dma_handle.Parent = RT_NULL;
+ stm32_adc_stream_release_cache_buffer(adc);
+ *hardware_stopped = RT_TRUE;
+ return RT_EOK;
+ }
+
+ status = HAL_ADC_Stop_DMA(&adc->handle);
+ if (status == HAL_OK)
+ {
+ hal_stopped = RT_TRUE;
+ }
+ else
+ {
+ result = stm32_hal_status_to_rt_err(status);
+ LOG_W("%s stream DMA stop returned %d, continue cleanup", adc->name, result);
+ }
+
+ if (adc->dma_rx != RT_NULL)
+ {
+ rt_err_t dma_result;
+
+ dma_result = stm32_dma_deinit(&adc->dma_handle, adc->dma_rx, (hal_stopped == RT_TRUE) ? RT_FALSE : RT_TRUE);
+ if (dma_result == RT_EOK)
+ {
+ dma_released = RT_TRUE;
+ }
+ else
+ {
+ LOG_E("%s stream DMA cleanup failed after stop: result=%d", adc->name, dma_result);
+ if (result == RT_EOK)
+ {
+ result = dma_result;
+ }
+ }
+ }
+ else if (hal_stopped == RT_TRUE)
+ {
+ dma_released = RT_TRUE;
+ }
+
+ if ((hal_stopped == RT_TRUE) || (dma_released == RT_TRUE))
+ {
+ adc->handle.DMA_Handle = RT_NULL;
+ adc->dma_handle.Parent = RT_NULL;
+ stm32_adc_stream_release_cache_buffer(adc);
+ *hardware_stopped = RT_TRUE;
+ return result;
+ }
+
+ return (result != RT_EOK) ? result : -RT_ERROR;
+}
+
+/**
+ * @brief Check whether a HAL ADC handle belongs to an active stream DMA session.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param hadc Pointer to the HAL ADC handle.
+ * @return RT_TRUE when the handle is attached to the stream DMA backend.
+ */
+static rt_bool_t stm32_adc_stream_dma_is_active(const struct stm32_adc *adc, const ADC_HandleTypeDef *hadc)
+{
+ if (hadc->DMA_Handle != &adc->dma_handle)
+ {
+ return RT_FALSE;
+ }
+
+ return (adc->device.stream_ctrl.active == RT_TRUE) ? RT_TRUE : RT_FALSE;
+}
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+/**
+ * @brief Dispatch one ADC stream DMA completion event to the ADC framework.
+ * @param hadc Pointer to the HAL ADC handle.
+ * @param event DMA stream event to report.
+ */
+static void stm32_adc_stream_dma_callback(ADC_HandleTypeDef *hadc, enum rt_adc_stream_event event)
+{
+ struct stm32_adc *adc;
+ struct rt_adc_stream_ctrl *ctrl;
+ const rt_uint32_t *sample_buffer;
+ rt_size_t half;
+ rt_size_t sample_count;
+ rt_err_t result;
+
+ RT_ASSERT(hadc != RT_NULL);
+ adc = (struct stm32_adc *)hadc;
+ if (stm32_adc_stream_dma_is_active(adc, hadc) != RT_TRUE)
+ {
+ return;
+ }
+
+ ctrl = &adc->device.stream_ctrl;
+ sample_buffer = RT_NULL;
+ sample_count = 0U;
+
+ if (ctrl->policy != RT_ADC_STREAM_POLICY_FIFO)
+ {
+ return;
+ }
+
+ if (ctrl->dma_event_mode == RT_ADC_STREAM_DMA_EVENT_FULL_ONLY)
+ {
+ if (event != RT_ADC_STREAM_EVENT_DMA_DONE)
+ {
+ return;
+ }
+ sample_buffer = ctrl->dma_buffer;
+ sample_count = ctrl->dma_buffer_length;
+ }
+ else if (ctrl->dma_event_mode == RT_ADC_STREAM_DMA_EVENT_HALF_FULL)
+ {
+ half = ctrl->dma_buffer_length / 2U;
+ if (event == RT_ADC_STREAM_EVENT_DMA_DONE)
+ {
+ sample_buffer = &ctrl->dma_buffer[half];
+ sample_count = ctrl->dma_buffer_length - half;
+ }
+ else
+ {
+ sample_buffer = ctrl->dma_buffer;
+ sample_count = half;
+ }
+ }
+
+ if (sample_count == 0U)
+ {
+ return;
+ }
+
+ result = stm32_adc_stream_sync(&adc->device, sample_buffer, sample_count);
+ if (result != RT_EOK)
+ {
+ rt_atomic_store(&ctrl->last_error, (rt_atomic_t)result);
+ event = RT_ADC_STREAM_EVENT_ERROR;
+ sample_buffer = RT_NULL;
+ sample_count = 0U;
+ }
+
+ (void)rt_hw_adc_stream_isr(&adc->device, event, sample_buffer, sample_count);
+}
+
+/**
+ * @brief HAL ADC DMA half-transfer callback.
+ * @param hadc Pointer to the HAL ADC handle.
+ */
+void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
+{
+ stm32_adc_stream_dma_callback(hadc, RT_ADC_STREAM_EVENT_DMA_HALF);
+}
+
+/**
+ * @brief HAL ADC DMA transfer-complete callback.
+ * @param hadc Pointer to the HAL ADC handle.
+ */
+void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
+{
+ stm32_adc_stream_dma_callback(hadc, RT_ADC_STREAM_EVENT_DMA_DONE);
+}
+
+#else
+/**
+ * @brief HAL ADC DMA half-transfer callback.
+ * @param hadc Pointer to the HAL ADC handle.
+ */
+void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
+{
+ RT_UNUSED(hadc);
+}
+
+/**
+ * @brief HAL ADC DMA transfer-complete callback.
+ * @param hadc Pointer to the HAL ADC handle.
+ */
+void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
+{
+ RT_UNUSED(hadc);
+}
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+/**
+ * @brief HAL ADC error callback.
+ * @param hadc Pointer to the HAL ADC handle.
+ */
+void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
+{
+ struct stm32_adc *adc;
+ struct rt_adc_stream_ctrl *ctrl;
+
+ RT_ASSERT(hadc != RT_NULL);
+ adc = (struct stm32_adc *)hadc;
+ if (stm32_adc_stream_dma_is_active(adc, hadc) != RT_TRUE)
+ {
+ return;
+ }
+
+ ctrl = &adc->device.stream_ctrl;
+ rt_atomic_store(&ctrl->last_error, (rt_atomic_t)-RT_ERROR);
+ LOG_E("%s stream HAL ADC error: error_code=0x%08lx", adc->name, (unsigned long)hadc->ErrorCode);
+ (void)rt_hw_adc_stream_isr(&adc->device, RT_ADC_STREAM_EVENT_ERROR, RT_NULL, 0U);
+}
+
+#if defined(BSP_USING_ADC1) && defined(BSP_ADC1_USING_DMA)
+/**
+ * @brief ADC1 DMA interrupt handler.
+ */
+void ADC1_DMA_IRQHandler(void)
+{
+ rt_interrupt_enter();
+ HAL_DMA_IRQHandler(&stm32_adc_obj[ADC1_INDEX].dma_handle);
+ rt_interrupt_leave();
+}
+#endif /* defined(BSP_USING_ADC1) && defined(BSP_ADC1_USING_DMA) */
+
+#if defined(BSP_USING_ADC2) && defined(BSP_ADC2_USING_DMA)
+/**
+ * @brief ADC2 DMA interrupt handler.
+ */
+void ADC2_DMA_IRQHandler(void)
+{
+ rt_interrupt_enter();
+ HAL_DMA_IRQHandler(&stm32_adc_obj[ADC2_INDEX].dma_handle);
+ rt_interrupt_leave();
+}
+#endif /* defined(BSP_USING_ADC2) && defined(BSP_ADC2_USING_DMA) */
+
+#if defined(BSP_USING_ADC3) && defined(BSP_ADC3_USING_DMA)
+/**
+ * @brief ADC3 DMA interrupt handler.
+ */
+void ADC3_DMA_IRQHandler(void)
+{
+ rt_interrupt_enter();
+ HAL_DMA_IRQHandler(&stm32_adc_obj[ADC3_INDEX].dma_handle);
+ rt_interrupt_leave();
+}
+#endif /* defined(BSP_USING_ADC3) && defined(BSP_ADC3_USING_DMA) */
+
+#if defined(BSP_USING_ADC4) && defined(BSP_ADC4_USING_DMA)
+/**
+ * @brief ADC4 DMA interrupt handler.
+ */
+void ADC4_DMA_IRQHandler(void)
+{
+ rt_interrupt_enter();
+ HAL_DMA_IRQHandler(&stm32_adc_obj[ADC4_INDEX].dma_handle);
+ rt_interrupt_leave();
+}
+#endif /* defined(BSP_USING_ADC4) && defined(BSP_ADC4_USING_DMA) */
+#endif /* STM32_ADC_USING_DMA_STREAM */
+
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+/**
+ * @brief Calculate the ADC reference voltage from a raw VREF sample.
+ * @param device Pointer to the ADC device object.
+ * @param vref_mv Pointer to the input raw VREF code and output VDDA in mV.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_calc_vref_mv(struct rt_adc_device *device, rt_uint32_t *vref_mv)
+{
+ struct stm32_adc *adc;
+ rt_uint32_t raw_value;
+
+ if (*vref_mv == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ raw_value = *vref_mv;
+ *vref_mv = (rt_uint32_t)STM32_ADC_CALC_VREF_MV(adc, raw_value);
+ if (*vref_mv == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ LOG_D("%s VREF calculated: raw=%lu vref=%lu mV", adc->name, (unsigned long)raw_value, (unsigned long)*vref_mv);
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+
+/**
+ * @brief Handle control commands on one STM32 ADC device.
+ * @param device Pointer to the ADC device object.
+ * @param cmd Control command.
+ * @param args Pointer to the control argument buffer.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_control(struct rt_adc_device *device, int cmd, void *args)
+{
+ struct stm32_adc *adc;
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ LOG_D("%s control cmd=%d", adc->name, cmd);
+ switch (cmd)
+ {
+ case RT_ADC_CMD_GET_RESOLUTION:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ *((rt_uint8_t *)args) = stm32_adc_get_resolution_bits(adc);
+ return RT_EOK;
+
+ case RT_ADC_CMD_GET_VREF_CHANNEL:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ return stm32_adc_get_vref_logical_channel(adc, (rt_uint8_t *)args);
+
+ case RT_ADC_CMD_CALC_VREF:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+ return stm32_adc_calc_vref_mv(device, (rt_uint32_t *)args);
+#else
+ if (device->default_vref_mv == 0U)
+ {
+ return -RT_ENOSYS;
+ }
+ *((rt_uint32_t *)args) = device->default_vref_mv;
+ return RT_EOK;
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+
+ case RT_ADC_CMD_CALIBRATE:
+#if defined(STM32_ADC_HAS_CALIBRATION)
+ return stm32_adc_run_calibration(adc, &adc->config);
+#else
+ return -RT_ENOSYS;
+#endif /* defined(STM32_ADC_HAS_CALIBRATION) */
+
+ case RT_ADC_CMD_SET_CONFIG:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ adc->config = *((const struct stm32_adc_private_cfg *)args);
+ return RT_EOK;
+
+ case RT_ADC_CMD_GET_CONFIG:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ *((struct stm32_adc_private_cfg *)args) = adc->config;
+ return RT_EOK;
+
+ case RT_ADC_CMD_CLEAR_CHANNEL_CONFIG:
+ if (args != RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ return stm32_adc_clear_channel_config(adc);
+
+ default:
+ RT_UNUSED(args);
+ return -RT_ENOSYS;
+ }
+}
+
+/**
+ * @brief STM32 ADC core operation table.
+ */
+static const struct rt_adc_core_ops stm32_adc_core_ops = {
+ .open = stm32_adc_open,
+ .close = stm32_adc_close,
+ .session_config = stm32_adc_session_config,
+#if defined(STM32_ADC_USING_TRIGGER)
+ .trigger_prepare = stm32_adc_trigger_prepare,
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+ .control = stm32_adc_control,
+};
+
+/**
+ * @brief STM32 ADC sequence-session operation table.
+ */
+static const struct rt_adc_sequence_ops stm32_adc_sequence_ops = {
+ .start = stm32_adc_sequence_start,
+ .read = stm32_adc_sequence_read,
+ .stop = stm32_adc_sequence_stop,
+};
+
+#if STM32_ADC_USING_DMA_STREAM
+/**
+ * @brief STM32 ADC stream-session operation table.
+ */
+static const struct rt_adc_stream_ops stm32_adc_stream_ops = {
+ .start = stm32_adc_stream_start,
+ .sync = stm32_adc_stream_sync,
+ .stop = stm32_adc_stream_stop,
+};
+#endif /* STM32_ADC_USING_DMA_STREAM */
+
+/**
+ * @brief STM32 ADC operation table.
+ */
+static const struct rt_adc_ops stm32_adc_ops = {
+ .core = &stm32_adc_core_ops,
+ .sequence = &stm32_adc_sequence_ops,
+#if STM32_ADC_USING_DMA_STREAM
+ .stream = &stm32_adc_stream_ops,
+#endif /* STM32_ADC_USING_DMA_STREAM */
+};
+
+/**
+ * @brief Initialize and register STM32 ADC devices.
+ * @return Operation status.
+ */
+int stm32_adc_init(void)
+{
+ rt_size_t index;
+ int result;
+
+ result = RT_EOK;
+ for (index = 0; index < RT_ARRAY_SIZE(stm32_adc_obj); index++)
+ {
+ rt_atomic_store(&stm32_adc_obj[index].device.state, RT_ADC_STATE_IDLE);
+ stm32_adc_obj[index].device.default_vref_mv = 0;
+ if (rt_hw_adc_register(&stm32_adc_obj[index].device, stm32_adc_obj[index].name,
+ &stm32_adc_ops, &stm32_adc_obj[index]) != RT_EOK)
+ {
+ result = -RT_ERROR;
+ continue;
+ }
+ }
+
+ return result;
+}
+INIT_BOARD_EXPORT(stm32_adc_init);
+#endif /* defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4) */
+
+#endif /* defined(RT_USING_ADC_V2) */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.h
new file mode 100644
index 0000000000..a26f7a3aa3
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add stm32 adc v2 driver declarations
+ */
+
+/**
+ * @file drv_adc_v2.h
+ * @brief STM32 ADC V2 driver declarations.
+ */
+
+#ifndef __DRV_ADC_V2_H__
+#define __DRV_ADC_V2_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+#include <board.h>
+#include <rtdevice.h>
+#include <drivers/adc_v2.h>
+
+/**
+ * @brief STM32 ADC backend private device configuration.
+ *
+ * @note The fields map directly to STM32 HAL ADC initialization values. Use
+ * ADC_RESOLUTION_xxx, ADC_OVERSAMPLING_RATIO_xxx, and
+ * ADC_RIGHTBITSHIFT_xxx macros from the active STM32 HAL headers when
+ * the corresponding feature exists. The configuration should be updated
+ * before opening the ADC device.
+ */
+struct stm32_adc_private_cfg
+{
+ rt_uint32_t sampling_time; /**< HAL ADC sampling-time value; 0 uses ADC_DEFAULT_SAMPLING_TIME. */
+ rt_uint32_t resolution; /**< HAL ADC resolution value; 0 uses ADC_DEFAULT_RESOLUTION. */
+ rt_uint32_t data_align; /**< HAL ADC data-alignment value; 0 uses ADC_DEFAULT_DATA_ALIGN. */
+ rt_uint8_t input_modes; /**< Bit mask of enum rt_adc_input_mode values; 0 uses single-ended input. */
+ rt_uint8_t reserved[3]; /**< Reserved for alignment and future STM32 backend options. */
+ rt_uint32_t oversampling_ratio; /**< HAL ADC oversampling ratio; 0 disables hardware oversampling. */
+ rt_uint32_t oversampling_right_shift; /**< HAL ADC oversampling right shift; 0 uses no right shift. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Initialize and register STM32 ADC devices.
+ * @return Operation status.
+ */
+int stm32_adc_init(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __DRV_ADC_V2_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_msh.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_msh.c
new file mode 100644
index 0000000000..fc86157418
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_msh.c
@@ -0,0 +1,810 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-24 wdfk-prog split stm32 adc v2 msh special commands
+ */
+
+/**
+ * @file drv_adc_v2_msh.c
+ * @brief STM32 ADC V2 FinSH/MSH special-channel commands.
+ */
+#include <rtconfig.h>
+
+#include <stdlib.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include "drv_adc_v2_private.h"
+
+#if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4)
+
+#define DRV_DEBUG
+#define LOG_TAG "drv.adc.msh"
+#include <drv_log.h>
+
+#if defined(RT_USING_FINSH) && defined(RT_ADC_V2_USING_MSH)
+
+/** @brief Default timeout in milliseconds for STM32 ADC MSH special reads. */
+#define STM32_ADC_MSH_DEFAULT_READ_TIMEOUT_MS 1000
+
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+#define STM32_ADC_MSH_HAS_VREF_READ 1
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+
+#if defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC) || defined(STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA)
+#define STM32_ADC_MSH_HAS_TEMPSENSOR_READ 1
+#endif /* defined(STM32_ADC_HAS_LL_TEMPERATURE_CALC) || defined(STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA) */
+
+#define STM32_ADC_MSH_HAS_VBAT_READ 1
+
+#if defined(STM32_ADC_MSH_HAS_VREF_READ) || defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) || \
+ defined(STM32_ADC_MSH_HAS_VBAT_READ)
+#define STM32_ADC_MSH_HAS_SPECIAL_READ 1
+#endif /* defined(STM32_ADC_MSH_HAS_VREF_READ) || defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) || defined(STM32_ADC_MSH_HAS_VBAT_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_SPECIAL_READ)
+/**
+ * @brief Sample data read from one STM32 internal ADC channel.
+ */
+struct stm32_adc_special_sample
+{
+ rt_uint32_t raw_value; /**< Raw ADC sample of the requested channel. */
+ rt_uint32_t vref_mv; /**< VDDA calculated from VREFINT, in millivolts. */
+ rt_uint8_t resolution_bits; /**< ADC conversion resolution in bits. */
+};
+#endif /* defined(STM32_ADC_MSH_HAS_SPECIAL_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_SPECIAL_READ)
+/**
+ * @brief Get VDDA in millivolts for STM32 ADC special-channel conversion.
+ * @param device Pointer to the ADC device object.
+ * @param samples Pointer to the ADC sample buffer containing VREFINT raw data.
+ * @param has_vref_sample Whether @p samples contains a valid VREFINT sample.
+ * @param vref_index Index of the VREFINT sample in @p samples.
+ * @param vref_mv Pointer to the output analog reference voltage in millivolts.
+ * @return Operation status.
+ *
+ * This helper prefers the sampled VREFINT path when a VREFINT sample is
+ * available. If dynamic VREF calculation is unavailable or VREFINT is not part
+ * of the current session, it falls back to the framework default_vref_mv.
+ */
+static rt_err_t stm32_adc_msh_get_vref_mv(rt_adc_device_t device, const rt_uint32_t *samples, rt_bool_t has_vref_sample,
+ rt_size_t vref_index, rt_uint32_t *vref_mv)
+{
+ if (has_vref_sample == RT_TRUE)
+ {
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+ rt_err_t result;
+ *vref_mv = samples[vref_index];
+ result = stm32_adc_calc_vref_mv(device, vref_mv);
+ if (result == RT_EOK)
+ {
+ return RT_EOK;
+ }
+
+ if (result != -RT_ENOSYS)
+ {
+ return result;
+ }
+#else
+ RT_UNUSED(samples);
+ RT_UNUSED(vref_index);
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+ }
+
+ if (device->default_vref_mv != 0U)
+ {
+ *vref_mv = device->default_vref_mv;
+ return RT_EOK;
+ }
+
+ return (has_vref_sample == RT_TRUE) ? -RT_ENOSYS : -RT_EINVAL;
+}
+
+/**
+ * @brief Read one preconfigured STM32 internal ADC channel sample.
+ * @param device Pointer to the ADC device object.
+ * @param channel Logical ADC channel identifier.
+ * @param need_vref Whether the caller needs VDDA for value conversion.
+ * @param timeout_ms Per-sample timeout in milliseconds; negative means wait forever.
+ * @param sample Pointer to the output special-channel sample.
+ * @return Operation status.
+ *
+ * This helper reads using the currently configured framework session. The
+ * caller must first configure an active framework session containing the
+ * requested special channel. If @p need_vref is RT_TRUE, VDDA is calculated
+ * from VREFINT when VREFINT is present in the session; otherwise the configured
+ * default_vref_mv is used as the fallback reference voltage.
+ */
+static rt_err_t stm32_adc_read_special_sample(rt_adc_device_t device, rt_uint8_t channel, rt_bool_t need_vref,
+ rt_int32_t timeout_ms, struct stm32_adc_special_sample *sample)
+{
+ struct stm32_adc *adc;
+ struct rt_adc_sequence_cfg sequence_cfg;
+ rt_uint32_t samples[STM32_ADC_MAX_CHANNELS];
+ rt_uint8_t vref_channel;
+ rt_bool_t has_vref_sample;
+ rt_size_t sample_count;
+ rt_size_t sample_index;
+ rt_size_t vref_index;
+ rt_size_t read_count;
+ rt_err_t result;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+
+ if ((device->session_ctrl.configured != RT_TRUE) || (device->session_ctrl.channel_count == 0U) ||
+ ((device->session_ctrl.channels & RT_ADC_CHANNEL_MASK(channel)) == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ sample_count = device->session_ctrl.channel_count;
+ if (sample_count > RT_ARRAY_SIZE(samples))
+ {
+ return -RT_EINVAL;
+ }
+
+ result = rt_adc_session_channel_index(device->session_ctrl.channels, RT_ADC_CHANNEL_MASK(channel), &sample_index);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ vref_index = 0U;
+ has_vref_sample = RT_FALSE;
+
+ if (need_vref == RT_TRUE)
+ {
+ result = stm32_adc_get_vref_logical_channel(adc, &vref_channel);
+ if (result == RT_EOK)
+ {
+ if ((device->session_ctrl.channels & RT_ADC_CHANNEL_MASK(vref_channel)) != 0U)
+ {
+ result = rt_adc_session_channel_index(device->session_ctrl.channels,
+ RT_ADC_CHANNEL_MASK(vref_channel), &vref_index);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ has_vref_sample = RT_TRUE;
+ }
+ else if (device->default_vref_mv == 0U)
+ {
+ return -RT_EINVAL;
+ }
+ }
+ else if (device->default_vref_mv == 0U)
+ {
+ return result;
+ }
+ }
+
+ rt_memset(&sequence_cfg, 0, sizeof(sequence_cfg));
+ rt_memset(samples, 0, sizeof(samples));
+ sequence_cfg.buffer = samples;
+ sequence_cfg.buffer_length = sample_count;
+ sequence_cfg.timeout_ms = timeout_ms;
+
+ result = rt_adc_read_sequence(device, device->session_ctrl.channels, &sequence_cfg, &read_count);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ if (read_count <= sample_index)
+ {
+ return -RT_ERROR;
+ }
+
+ sample->raw_value = samples[sample_index];
+ sample->vref_mv = 0U;
+ sample->resolution_bits = stm32_adc_get_resolution_bits(adc);
+
+ if (need_vref == RT_TRUE)
+ {
+ if (sample->resolution_bits == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_msh_get_vref_mv(device, samples, has_vref_sample, vref_index, &sample->vref_mv);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ }
+
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_MSH_HAS_SPECIAL_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ)
+/**
+ * @brief Check whether STM32 ADC MSH can provide VDDA for temperature conversion.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param device Pointer to the ADC device object.
+ * @return RT_TRUE if temperature conversion can obtain VDDA, otherwise RT_FALSE.
+ *
+ * Temperature conversion requires VDDA in millivolts. Dynamic VDDA calculation
+ * requires a supported VREFINT logical channel and LL VREF calculation support;
+ * otherwise the framework default_vref_mv must be configured.
+ */
+static rt_bool_t stm32_adc_msh_has_temperature_vref_source(struct stm32_adc *adc, rt_adc_device_t device)
+{
+ rt_uint8_t vref_channel;
+
+ if ((adc == RT_NULL) || (device == RT_NULL))
+ {
+ return RT_FALSE;
+ }
+
+ if (device->default_vref_mv != 0U)
+ {
+ return RT_TRUE;
+ }
+
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+ if (stm32_adc_get_vref_logical_channel(adc, &vref_channel) == RT_EOK)
+ {
+ return RT_TRUE;
+ }
+#else
+ RT_UNUSED(vref_channel);
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+
+ return RT_FALSE;
+}
+#endif /* defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_VREF_READ)
+/**
+ * @brief Read VREFINT and calculate VDDA in millivolts for STM32 ADC MSH.
+ * @param device Pointer to the ADC device object.
+ * @param timeout_ms Per-sample timeout in milliseconds; negative means wait forever.
+ * @param vref_mv Pointer to the output analog reference voltage in millivolts.
+ * @return Operation status.
+ *
+ * VREF read requires LL VREF calculation support. Without that support, the
+ * command is reported as unsupported instead of returning default_vref_mv.
+ */
+static rt_err_t stm32_adc_msh_read_vref(rt_adc_device_t device, rt_int32_t timeout_ms, rt_uint32_t *vref_mv)
+{
+ struct stm32_adc *adc;
+ struct stm32_adc_special_sample sample;
+ rt_uint8_t vref_channel;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (vref_mv == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_get_vref_logical_channel(adc, &vref_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_read_special_sample(device, vref_channel, RT_FALSE, timeout_ms, &sample);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ return stm32_adc_msh_get_vref_mv(device, &sample.raw_value, RT_TRUE, 0U, vref_mv);
+}
+#endif /* defined(STM32_ADC_MSH_HAS_VREF_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ)
+/**
+ * @brief Read the STM32 internal temperature sensor for ADC MSH.
+ * @param device Pointer to the ADC device object.
+ * @param timeout_ms Per-sample timeout in milliseconds; negative means wait forever.
+ * @param temperature_c Pointer to the output temperature in degrees Celsius.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_msh_read_temperature(rt_adc_device_t device, rt_int32_t timeout_ms, rt_int32_t *temperature_c)
+{
+ struct stm32_adc *adc;
+ struct stm32_adc_special_sample sample;
+ rt_uint8_t tempsensor_channel;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (temperature_c == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_get_tempsensor_logical_channel(adc, &tempsensor_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_read_special_sample(device, tempsensor_channel, RT_TRUE, timeout_ms, &sample);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ return stm32_adc_calc_temperature(device, sample.raw_value, sample.vref_mv, sample.resolution_bits, temperature_c);
+}
+#endif /* defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_VBAT_READ)
+/**
+ * @brief Read raw VBAT ADC sample for STM32 ADC MSH.
+ * @param device Pointer to the ADC device object.
+ * @param timeout_ms Per-sample timeout in milliseconds; negative means wait forever.
+ * @param raw_value Pointer to the output raw VBAT ADC sample.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_msh_read_vbat(rt_adc_device_t device, rt_int32_t timeout_ms, rt_uint32_t *raw_value)
+{
+ struct stm32_adc *adc;
+ struct stm32_adc_special_sample sample;
+ rt_uint8_t vbat_channel;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (raw_value == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_get_vbat_logical_channel(adc, &vbat_channel);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = stm32_adc_read_special_sample(device, vbat_channel, RT_FALSE, timeout_ms, &sample);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ *raw_value = sample.raw_value;
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_MSH_HAS_VBAT_READ) */
+
+/**
+ * @brief Get one STM32 ADC special MSH item property.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the item name.
+ * @param channel Pointer to the output logical channel.
+ * @param need_vref Optional pointer to the output VREF requirement flag.
+ * @param unit Optional pointer to the output display unit string.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_msh_get_item(rt_adc_device_t device, const char *name, rt_uint8_t *channel,
+ rt_bool_t *need_vref, const char **unit)
+{
+ struct stm32_adc *adc;
+
+ if ((device == RT_NULL) || (name == RT_NULL) || (channel == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+#if defined(STM32_ADC_MSH_HAS_VREF_READ)
+ if (rt_strcmp(name, "vref") == 0)
+ {
+ if (need_vref != RT_NULL)
+ {
+ *need_vref = RT_FALSE;
+ }
+ if (unit != RT_NULL)
+ {
+ *unit = "mV";
+ }
+ return stm32_adc_get_vref_logical_channel(adc, channel);
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_VREF_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ)
+ if (rt_strcmp(name, "temp") == 0)
+ {
+ if (stm32_adc_get_tempsensor_logical_channel(adc, channel) != RT_EOK)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (stm32_adc_msh_has_temperature_vref_source(adc, device) != RT_TRUE)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (need_vref != RT_NULL)
+ {
+ *need_vref = RT_TRUE;
+ }
+ if (unit != RT_NULL)
+ {
+ *unit = "C";
+ }
+ return RT_EOK;
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_VBAT_READ)
+ if (rt_strcmp(name, "vbat") == 0)
+ {
+ if (stm32_adc_get_vbat_logical_channel(adc, channel) != RT_EOK)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (need_vref != RT_NULL)
+ {
+ *need_vref = RT_FALSE;
+ }
+ if (unit != RT_NULL)
+ {
+ *unit = "raw";
+ }
+ return RT_EOK;
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_VBAT_READ) */
+
+ return -RT_ENOSYS;
+}
+
+/**
+ * @brief Print one supported STM32 ADC special MSH item if available.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the item name.
+ * @return RT_TRUE if the item was printed, otherwise RT_FALSE.
+ */
+static rt_bool_t stm32_adc_msh_print_item(rt_adc_device_t device, const char *name)
+{
+ struct stm32_adc *adc;
+ const char *unit;
+ rt_bool_t need_vref;
+ rt_bool_t has_vref_channel;
+ rt_uint8_t channel;
+ rt_uint8_t vref_channel;
+ rt_err_t result;
+
+ if (stm32_adc_msh_get_item(device, name, &channel, &need_vref, &unit) != RT_EOK)
+ {
+ return RT_FALSE;
+ }
+
+ has_vref_channel = RT_FALSE;
+ vref_channel = 0U;
+
+ if (need_vref == RT_TRUE)
+ {
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return RT_FALSE;
+ }
+
+ result = stm32_adc_get_vref_logical_channel(adc, &vref_channel);
+ if (result == RT_EOK)
+ {
+ has_vref_channel = RT_TRUE;
+ }
+ else if (device->default_vref_mv == 0U)
+ {
+ rt_kprintf(" %s: unsupported, missing vref/default_vref\n", name);
+ return RT_FALSE;
+ }
+ }
+
+ rt_kprintf(" %s: channel=%u unit=%s", name, (unsigned int)channel, unit);
+
+ if (need_vref == RT_TRUE)
+ {
+ if (has_vref_channel == RT_TRUE)
+ {
+ rt_kprintf(" needs=vref channel=%u", (unsigned int)vref_channel);
+ }
+ else
+ {
+ rt_kprintf(" needs=default_vref");
+ }
+ }
+
+ rt_kprintf("\n");
+
+ return RT_TRUE;
+}
+/**
+ * @brief Print supported STM32 ADC special MSH items for the selected device.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_msh_special_list(rt_adc_device_t device)
+{
+ rt_bool_t has_temp;
+ rt_size_t count;
+
+ count = 0U;
+ count += (stm32_adc_msh_print_item(device, "vref") == RT_TRUE) ? 1U : 0U;
+ has_temp = stm32_adc_msh_print_item(device, "temp");
+
+ count += (has_temp == RT_TRUE) ? 1U : 0U;
+ count += (stm32_adc_msh_print_item(device, "vbat") == RT_TRUE) ? 1U : 0U;
+
+ if (count == 0U)
+ {
+ rt_kprintf(" no STM32 ADC special channels supported by current device\n");
+ }
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Print STM32 ADC special MSH command usage.
+ */
+static void stm32_adc_msh_special_usage(void)
+{
+ rt_kprintf("STM32 ADC special commands:\n");
+ rt_kprintf(" adc special list\n");
+ rt_kprintf(" adc special read <item-from-list> [timeout_ms]\n");
+ rt_kprintf(" timeout_ms defaults to 1000; negative means wait forever\n");
+ rt_kprintf(" run adc special list first, then use the printed adc config command\n");
+ rt_kprintf(" temp accuracy depends on datasheet sampling time; adc special list shows item notes\n");
+}
+
+/**
+ * @brief Print ADC config command for one STM32 ADC special MSH item.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the item name.
+ */
+static void stm32_adc_msh_print_config_hint(rt_adc_device_t device, const char *name)
+{
+ struct stm32_adc *adc;
+ rt_bool_t need_vref;
+ rt_uint8_t channel;
+ rt_uint8_t vref_channel;
+
+ if ((device == RT_NULL) || (name == RT_NULL))
+ {
+ return;
+ }
+
+ if (stm32_adc_msh_get_item(device, name, &channel, &need_vref, RT_NULL) != RT_EOK)
+ {
+ return;
+ }
+
+ if (need_vref != RT_TRUE)
+ {
+ rt_kprintf("configure with: adc config %u\n", (unsigned int)channel);
+ return;
+ }
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if ((adc != RT_NULL) && (stm32_adc_get_vref_logical_channel(adc, &vref_channel) == RT_EOK))
+ {
+ rt_kprintf("configure with: adc config %u %u\n", (unsigned int)channel, (unsigned int)vref_channel);
+ }
+ else
+ {
+ rt_kprintf("configure with: adc config %u\n", (unsigned int)channel);
+ }
+}
+
+/**
+ * @brief Parse one optional STM32 ADC special-read timeout argument.
+ * @param arg Pointer to the timeout argument string.
+ * @param timeout_ms Pointer to the output timeout in milliseconds.
+ * @return Operation status.
+ *
+ * A negative timeout keeps the ADC framework convention of waiting forever.
+ */
+static rt_err_t stm32_adc_msh_parse_timeout(const char *arg, rt_int32_t *timeout_ms)
+{
+ char *endptr;
+ long value;
+
+ if ((arg == RT_NULL) || (timeout_ms == RT_NULL) || (*arg == '\0'))
+ {
+ return -RT_EINVAL;
+ }
+
+ endptr = RT_NULL;
+ value = strtol(arg, &endptr, 0);
+ if ((endptr == arg) || (endptr == RT_NULL) || (*endptr != '\0'))
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((value > 2147483647L) || (value < (-2147483647L - 1L)))
+ {
+ return -RT_EINVAL;
+ }
+
+ *timeout_ms = (rt_int32_t)value;
+ return RT_EOK;
+}
+
+/**
+ * @brief Print and normalize one STM32 ADC special MSH command result.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the requested item name.
+ * @param action Pointer to the action name.
+ * @param result Operation status to normalize.
+ * @return Operation status for the framework-level command dispatcher.
+ */
+static rt_err_t stm32_adc_msh_finish_special_result(rt_adc_device_t device, const char *name,
+ const char *action, rt_err_t result)
+{
+ if (result == RT_EOK)
+ {
+ return RT_EOK;
+ }
+
+ rt_kprintf("%s %s failed: %d\n", name, action, result);
+
+ if (result == -RT_EINVAL)
+ {
+ rt_kprintf("run adc special list first or use the following command before reading\n");
+ stm32_adc_msh_print_config_hint(device, name);
+ }
+
+ return (result == -RT_ENOSYS) ? -RT_ERROR : result;
+}
+
+/**
+ * @brief Handle one STM32 ADC special MSH read command.
+ * @param device Pointer to the ADC device object.
+ * @param argc Argument count excluding the top-level adc command.
+ * @param argv Argument vector excluding the top-level adc command.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_msh_special_read(rt_adc_device_t device, int argc, char **argv)
+{
+ const char *name;
+ rt_uint8_t channel;
+ rt_int32_t timeout_ms;
+ rt_err_t result;
+
+ if ((argc != 3) && (argc != 4))
+ {
+ stm32_adc_msh_special_usage();
+ return -RT_EINVAL;
+ }
+
+ name = argv[2];
+ timeout_ms = STM32_ADC_MSH_DEFAULT_READ_TIMEOUT_MS;
+ if ((argc == 4) && (stm32_adc_msh_parse_timeout(argv[3], &timeout_ms) != RT_EOK))
+ {
+ rt_kprintf("invalid timeout_ms: %s\n", argv[3]);
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_msh_get_item(device, name, &channel, RT_NULL, RT_NULL);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("%s is not supported by current STM32 ADC device\n", name);
+ return -RT_EINVAL;
+ }
+
+#if defined(STM32_ADC_MSH_HAS_VREF_READ)
+ if (rt_strcmp(name, "vref") == 0)
+ {
+ rt_uint32_t value_mv;
+ result = stm32_adc_msh_read_vref(device, timeout_ms, &value_mv);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("vref: %lu mV\n", (unsigned long)value_mv);
+ }
+ return stm32_adc_msh_finish_special_result(device, name, "read", result);
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_VREF_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ)
+ if (rt_strcmp(name, "temp") == 0)
+ {
+ rt_int32_t temperature_c;
+ result = stm32_adc_msh_read_temperature(device, timeout_ms, &temperature_c);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("temp: %ld C\n", (long)temperature_c);
+ }
+ return stm32_adc_msh_finish_special_result(device, name, "read", result);
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_TEMPSENSOR_READ) */
+
+#if defined(STM32_ADC_MSH_HAS_VBAT_READ)
+ if (rt_strcmp(name, "vbat") == 0)
+ {
+ rt_uint32_t raw_value;
+ result = stm32_adc_msh_read_vbat(device, timeout_ms, &raw_value);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("vbat: %lu raw\n", (unsigned long)raw_value);
+ }
+ return stm32_adc_msh_finish_special_result(device, name, "read", result);
+ }
+#endif /* defined(STM32_ADC_MSH_HAS_VBAT_READ) */
+
+ RT_UNUSED(channel);
+ return -RT_ENOSYS;
+}
+
+/**
+ * @brief Print STM32 ADC backend-specific FinSH command usage.
+ */
+void rt_adc_msh_special_help(void)
+{
+ stm32_adc_msh_special_usage();
+}
+
+/**
+ * @brief Handle STM32 ADC backend-specific FinSH commands.
+ * @param device Pointer to the selected ADC device object.
+ * @param argc Argument count excluding the top-level adc command.
+ * @param argv Argument vector excluding the top-level adc command.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_msh_special(rt_adc_device_t device, int argc, char **argv)
+{
+ if ((device == RT_NULL) || (argv == RT_NULL) || (argc <= 0))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (rt_strcmp(argv[0], "special") != 0)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if ((argc == 2) && (rt_strcmp(argv[1], "list") == 0))
+ {
+ return stm32_adc_msh_special_list(device);
+ }
+
+ if ((argc >= 3) && (rt_strcmp(argv[1], "read") == 0))
+ {
+ return stm32_adc_msh_special_read(device, argc, argv);
+ }
+
+ stm32_adc_msh_special_usage();
+ return -RT_EINVAL;
+}
+
+#endif /* defined(RT_USING_FINSH) && defined(RT_ADC_V2_USING_MSH) */
+
+#endif /* defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4) */
+
+#endif /* defined(RT_USING_ADC_V2) */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_private.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_private.h
new file mode 100644
index 0000000000..99d2ee9ff8
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_private.h
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+/**
+ * @file drv_adc_v2_private.h
+ * @brief Private declarations for the STM32 ADC V2 backend.
+ */
+
+#ifndef __DRV_ADC_V2_PRIVATE_H__
+#define __DRV_ADC_V2_PRIVATE_H__
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include "drv_adc_v2.h"
+#include <stddef.h>
+
+#if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4)
+
+/* STM32 HAL ADC support is detected here when the HAL exposes a stable
+ * feature macro. Keep series-specific defaults and internal-channel routing
+ * overrides in config/<series>/adc_config_v2.h; keep HAL structure/API
+ * compatibility here so new series normally inherit support from their HAL
+ * headers.
+ */
+
+/* STM32F0-like sequencers use ADC_RANK_CHANNEL_NUMBER instead of a numeric
+ * regular-rank slot. Other HALs that expose ADC_REGULAR_RANK_x constants can
+ * use those constants directly; otherwise plain rank numbers are used.
+ */
+#if defined(ADC_RANK_CHANNEL_NUMBER)
+#define STM32_ADC_HAS_CHANNEL_NUMBER_RANK 1
+#elif defined(ADC_REGULAR_RANK_1)
+#define STM32_ADC_HAS_ENUM_RANK 1
+#endif /* defined(ADC_RANK_CHANNEL_NUMBER) */
+
+#if defined(ADC_CONVERSIONDATA_DR) && defined(ADC_CONVERSIONDATA_DMA_CIRCULAR)
+#define STM32_ADC_HAS_INIT_CONVERSION_DATA_MANAGEMENT 1
+#endif /* defined(ADC_CONVERSIONDATA_DR) && defined(ADC_CONVERSIONDATA_DMA_CIRCULAR) */
+
+#if defined(ADC_SCAN_ENABLE)
+#define STM32_ADC_SCAN_MODE_ENABLE ADC_SCAN_ENABLE
+#elif defined(ADC_SCAN_DIRECTION_FORWARD)
+#define STM32_ADC_SCAN_MODE_ENABLE ADC_SCAN_DIRECTION_FORWARD
+#else
+#define STM32_ADC_SCAN_MODE_ENABLE ENABLE
+#endif /* defined(ADC_SCAN_ENABLE) */
+
+#if defined(ADC_SCAN_DISABLE)
+#define STM32_ADC_SCAN_MODE_DISABLE ADC_SCAN_DISABLE
+#elif defined(ADC_SCAN_DIRECTION_FORWARD)
+#define STM32_ADC_SCAN_MODE_DISABLE ADC_SCAN_DIRECTION_FORWARD
+#else
+#define STM32_ADC_SCAN_MODE_DISABLE DISABLE
+#endif /* defined(ADC_SCAN_DISABLE) */
+
+/* Channel configuration fields are tied to HAL channel-mode and offset macros.
+ * A config file may still override these before including this driver header if
+ * a vendor HAL variant exposes a different field layout.
+ */
+#if !defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS)
+#if defined(ADC_SINGLE_ENDED) && defined(ADC_DIFFERENTIAL_ENDED)
+#define STM32_ADC_HAS_SINGLE_DIFF_FIELDS 1
+#define STM32_ADC_SINGLE_ENDED_VALUE ADC_SINGLE_ENDED
+#define STM32_ADC_DIFFERENTIAL_VALUE ADC_DIFFERENTIAL_ENDED
+#elif defined(LL_ADC_SINGLE_ENDED) && defined(LL_ADC_DIFFERENTIAL_ENDED)
+#define STM32_ADC_HAS_SINGLE_DIFF_FIELDS 1
+#define STM32_ADC_SINGLE_ENDED_VALUE LL_ADC_SINGLE_ENDED
+#define STM32_ADC_DIFFERENTIAL_VALUE LL_ADC_DIFFERENTIAL_ENDED
+#endif /* defined(ADC_SINGLE_ENDED) && defined(ADC_DIFFERENTIAL_ENDED) */
+#endif /* !defined(STM32_ADC_HAS_SINGLE_DIFF_FIELDS) */
+
+#if defined(ADC_OFFSET_NONE)
+#ifndef STM32_ADC_HAS_CONFIG_OFFSET
+#define STM32_ADC_HAS_CONFIG_OFFSET 1
+#endif /* STM32_ADC_HAS_CONFIG_OFFSET */
+#ifndef STM32_ADC_HAS_CONFIG_OFFSET_NUMBER
+#define STM32_ADC_HAS_CONFIG_OFFSET_NUMBER 1
+#endif /* STM32_ADC_HAS_CONFIG_OFFSET_NUMBER */
+#endif /* defined(ADC_OFFSET_NONE) */
+
+#if defined(ADC_RESOLUTION_12B)
+#define STM32_ADC_HAS_CONFIGURABLE_RESOLUTION 1
+#endif /* defined(ADC_RESOLUTION_12B) */
+
+#if defined(ADC_CALIB_OFFSET_LINEARITY)
+#define STM32_ADC_HAS_LINEAR_CALIBRATION 1
+#endif /* defined(ADC_CALIB_OFFSET_LINEARITY) */
+
+#if defined(STM32_ADC_HAS_SIMPLE_CALIBRATION) || defined(STM32_ADC_HAS_LINEAR_CALIBRATION)
+#define STM32_ADC_HAS_CALIBRATION 1
+#endif /* defined(STM32_ADC_HAS_SIMPLE_CALIBRATION) || defined(STM32_ADC_HAS_LINEAR_CALIBRATION) */
+
+#if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32H7RS)
+/** @brief Enable D-Cache-safe ADC DMA stream handling for Cortex-M7 STM32 series. */
+#define STM32_ADC_NEEDS_DMA_CACHE_MAINTENANCE 1
+#endif /* defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32H7RS) */
+
+#if defined(BSP_ADC_USING_TRIGGER) && defined(RT_ADC_USING_TRIGGER)
+/** @brief Whether the STM32 ADC trigger backend support is compiled in. */
+#define STM32_ADC_USING_TRIGGER 1
+#endif /* defined(BSP_ADC_USING_TRIGGER) && defined(RT_ADC_USING_TRIGGER) */
+
+#if defined(STM32_ADC_USING_TRIGGER) && defined(BSP_ADC_USING_TIMER_TRIGGER) && defined(RT_ADC_TRIGGER_USING_TIMER) && defined(BSP_USING_TIM)
+/** @brief Whether the STM32 ADC timer trigger selector backend is compiled in. */
+#define STM32_ADC_USING_TIMER_TRIGGER 1
+#endif /* defined(STM32_ADC_USING_TRIGGER) && defined(BSP_ADC_USING_TIMER_TRIGGER) && defined(RT_ADC_TRIGGER_USING_TIMER) && defined(BSP_USING_TIM) */
+
+#if defined(STM32_ADC_USING_TRIGGER) && defined(BSP_ADC_USING_ANALOG_COMPARE_TRIGGER)
+#if defined(RT_ADC_TRIGGER_USING_COMPARE)
+/** @brief Whether the STM32 ADC analog-comparator trigger selector backend is compiled in. */
+#define STM32_ADC_USING_ANALOG_COMPARE_TRIGGER 1
+#endif /* defined(RT_ADC_TRIGGER_USING_COMPARE) */
+#endif /* defined(STM32_ADC_USING_TRIGGER) && defined(BSP_ADC_USING_ANALOG_COMPARE_TRIGGER) */
+
+#if defined(__LL_ADC_CALC_VREFANALOG_VOLTAGE) && defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION)
+#define STM32_ADC_HAS_LL_VREF_CALC 1
+#endif /* defined(__LL_ADC_CALC_VREFANALOG_VOLTAGE) && defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION) */
+
+#if defined(STM32_ADC_HAS_LL_VREF_CALC)
+#if defined(STM32_ADC_VREF_NEEDS_INSTANCE)
+/* Calculate VDDA in millivolts with an instance-aware LL helper. */
+#define STM32_ADC_CALC_VREF_MV(_adc, _raw) \
+ __LL_ADC_CALC_VREFANALOG_VOLTAGE((_adc)->handle.Instance, (_raw), (_adc)->handle.Init.Resolution)
+#else
+/* Calculate VDDA in millivolts with the generic LL helper. */
+#define STM32_ADC_CALC_VREF_MV(_adc, _raw) \
+ __LL_ADC_CALC_VREFANALOG_VOLTAGE((_raw), (_adc)->handle.Init.Resolution)
+#endif /* defined(STM32_ADC_VREF_NEEDS_INSTANCE) */
+#endif /* defined(STM32_ADC_HAS_LL_VREF_CALC) */
+
+#if defined(__LL_ADC_CALC_TEMPERATURE) && defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION)
+#define STM32_ADC_HAS_LL_TEMPERATURE_CALC 1
+
+#if defined(STM32_ADC_TEMPERATURE_NEEDS_INSTANCE)
+/* Calculate temperature in degrees Celsius with an instance-aware LL helper. */
+#define STM32_ADC_CALC_TEMPERATURE(_adc, _vref_mv, _raw, _resolution) \
+ __LL_ADC_CALC_TEMPERATURE((_adc)->handle.Instance, (_vref_mv), (_raw), (_resolution))
+#else
+/* Calculate temperature in degrees Celsius with the generic LL helper. */
+#define STM32_ADC_CALC_TEMPERATURE(_adc, _vref_mv, _raw, _resolution) \
+ __LL_ADC_CALC_TEMPERATURE((_vref_mv), (_raw), (_resolution))
+#endif /* defined(STM32_ADC_TEMPERATURE_NEEDS_INSTANCE) */
+
+#endif /* defined(__LL_ADC_CALC_TEMPERATURE) && defined(STM32_ADC_HAS_CONFIGURABLE_RESOLUTION) */
+
+#if defined(TEMPSENSOR_CAL1_ADDR) && defined(TEMPSENSOR_CAL2_ADDR) && defined(TEMPSENSOR_CAL1_TEMP) && \
+ defined(TEMPSENSOR_CAL2_TEMP) && defined(TEMPSENSOR_CAL_VREFANALOG)
+#define STM32_ADC_HAS_TEMPSENSOR_CALIBRATION_DATA 1
+#endif /* defined(TEMPSENSOR_CAL1_ADDR) && defined(TEMPSENSOR_CAL2_ADDR) && defined(TEMPSENSOR_CAL1_TEMP) && defined(TEMPSENSOR_CAL2_TEMP) && defined(TEMPSENSOR_CAL_VREFANALOG) */
+
+#if defined(ADC_OVERSAMPLING_RATIO_2) && defined(ADC_RIGHTBITSHIFT_1)
+#if defined(ADC_TRIGGEREDMODE_SINGLE_TRIGGER) && defined(ADC_REGOVERSAMPLING_CONTINUED_MODE)
+#define STM32_ADC_HAS_HW_OVERSAMPLING 1
+#endif /* defined(ADC_TRIGGEREDMODE_SINGLE_TRIGGER) && defined(ADC_REGOVERSAMPLING_CONTINUED_MODE) */
+#endif /* defined(ADC_OVERSAMPLING_RATIO_2) && defined(ADC_RIGHTBITSHIFT_1) */
+
+/** @brief Marker for an unavailable STM32 HAL ADC channel. */
+#ifndef STM32_ADC_INVALID_CHANNEL
+#define STM32_ADC_INVALID_CHANNEL 0xFFFFFFFFUL
+#endif /* STM32_ADC_INVALID_CHANNEL */
+
+/** @brief Invalid RT-Thread logical ADC channel marker. */
+#ifndef STM32_ADC_INVALID_LOGICAL_CHANNEL
+#define STM32_ADC_INVALID_LOGICAL_CHANNEL (-1)
+#endif /* STM32_ADC_INVALID_LOGICAL_CHANNEL */
+
+/** @brief STM32 ADC instance mask bit for ADC1. */
+#ifndef STM32_ADC_INSTANCE_MASK_ADC1
+#define STM32_ADC_INSTANCE_MASK_ADC1 (1UL << 0)
+#endif /* STM32_ADC_INSTANCE_MASK_ADC1 */
+
+/** @brief STM32 ADC instance mask bit for ADC2. */
+#ifndef STM32_ADC_INSTANCE_MASK_ADC2
+#define STM32_ADC_INSTANCE_MASK_ADC2 (1UL << 1)
+#endif /* STM32_ADC_INSTANCE_MASK_ADC2 */
+
+/** @brief STM32 ADC instance mask bit for ADC3. */
+#ifndef STM32_ADC_INSTANCE_MASK_ADC3
+#define STM32_ADC_INSTANCE_MASK_ADC3 (1UL << 2)
+#endif /* STM32_ADC_INSTANCE_MASK_ADC3 */
+
+/** @brief STM32 ADC instance mask bit for ADC4. */
+#ifndef STM32_ADC_INSTANCE_MASK_ADC4
+#define STM32_ADC_INSTANCE_MASK_ADC4 (1UL << 3)
+#endif /* STM32_ADC_INSTANCE_MASK_ADC4 */
+
+/** @brief STM32 ADC instance mask bit for ADC5. */
+#ifndef STM32_ADC_INSTANCE_MASK_ADC5
+#define STM32_ADC_INSTANCE_MASK_ADC5 (1UL << 4)
+#endif /* STM32_ADC_INSTANCE_MASK_ADC5 */
+
+/** @brief Mask value that allows every known STM32 ADC instance. */
+#ifndef STM32_ADC_INSTANCE_MASK_ALL
+#define STM32_ADC_INSTANCE_MASK_ALL 0xffffffffUL
+#endif /* STM32_ADC_INSTANCE_MASK_ALL */
+
+/** @brief Convert a STM32 HAL ADC channel literal into a RT-Thread logical channel number. */
+#ifndef STM32_ADC_HAL_CHANNEL_TO_LOGICAL
+#if defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_HAL_CHANNEL_TO_LOGICAL(_channel) __HAL_ADC_CHANNEL_TO_DECIMAL_NB(_channel)
+#elif defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_HAL_CHANNEL_TO_LOGICAL(_channel) __LL_ADC_CHANNEL_TO_DECIMAL_NB(_channel)
+#else
+#define STM32_ADC_HAL_CHANNEL_TO_LOGICAL(_channel) STM32_ADC_INVALID_LOGICAL_CHANNEL
+#endif /* defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) */
+#endif /* STM32_ADC_HAL_CHANNEL_TO_LOGICAL */
+
+/** @brief Maximum HAL ADC channel-table entries exposed by the active STM32 HAL. */
+#ifndef STM32_ADC_MAX_CHANNELS
+#if defined(ADC_CHANNEL_31)
+#define STM32_ADC_MAX_CHANNELS 32
+#elif defined(ADC_CHANNEL_30)
+#define STM32_ADC_MAX_CHANNELS 31
+#elif defined(ADC_CHANNEL_29)
+#define STM32_ADC_MAX_CHANNELS 30
+#elif defined(ADC_CHANNEL_28)
+#define STM32_ADC_MAX_CHANNELS 29
+#elif defined(ADC_CHANNEL_27)
+#define STM32_ADC_MAX_CHANNELS 28
+#elif defined(ADC_CHANNEL_26)
+#define STM32_ADC_MAX_CHANNELS 27
+#elif defined(ADC_CHANNEL_25)
+#define STM32_ADC_MAX_CHANNELS 26
+#elif defined(ADC_CHANNEL_24)
+#define STM32_ADC_MAX_CHANNELS 25
+#elif defined(ADC_CHANNEL_23)
+#define STM32_ADC_MAX_CHANNELS 24
+#elif defined(ADC_CHANNEL_22)
+#define STM32_ADC_MAX_CHANNELS 23
+#elif defined(ADC_CHANNEL_21)
+#define STM32_ADC_MAX_CHANNELS 22
+#elif defined(ADC_CHANNEL_20)
+#define STM32_ADC_MAX_CHANNELS 21
+#elif defined(ADC_CHANNEL_19)
+#define STM32_ADC_MAX_CHANNELS 20
+#elif defined(ADC_CHANNEL_18)
+#define STM32_ADC_MAX_CHANNELS 19
+#elif defined(ADC_CHANNEL_17)
+#define STM32_ADC_MAX_CHANNELS 18
+#elif defined(ADC_CHANNEL_16)
+#define STM32_ADC_MAX_CHANNELS 17
+#else
+#define STM32_ADC_MAX_CHANNELS 16
+#endif /* defined(ADC_CHANNEL_31) */
+#endif /* STM32_ADC_MAX_CHANNELS */
+
+/* Optional ADC channel encodings supplied by the active STM32 HAL. */
+#ifndef STM32_ADC_CHANNEL_16
+#ifdef ADC_CHANNEL_16
+#define STM32_ADC_CHANNEL_16 ADC_CHANNEL_16
+#else
+#define STM32_ADC_CHANNEL_16 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_16 */
+#endif /* STM32_ADC_CHANNEL_16 */
+
+#ifndef STM32_ADC_CHANNEL_17
+#ifdef ADC_CHANNEL_17
+#define STM32_ADC_CHANNEL_17 ADC_CHANNEL_17
+#else
+#define STM32_ADC_CHANNEL_17 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_17 */
+#endif /* STM32_ADC_CHANNEL_17 */
+
+#ifndef STM32_ADC_CHANNEL_18
+#ifdef ADC_CHANNEL_18
+#define STM32_ADC_CHANNEL_18 ADC_CHANNEL_18
+#else
+#define STM32_ADC_CHANNEL_18 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_18 */
+#endif /* STM32_ADC_CHANNEL_18 */
+
+#ifndef STM32_ADC_CHANNEL_19
+#ifdef ADC_CHANNEL_19
+#define STM32_ADC_CHANNEL_19 ADC_CHANNEL_19
+#else
+#define STM32_ADC_CHANNEL_19 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_19 */
+#endif /* STM32_ADC_CHANNEL_19 */
+
+#ifndef STM32_ADC_CHANNEL_20
+#ifdef ADC_CHANNEL_20
+#define STM32_ADC_CHANNEL_20 ADC_CHANNEL_20
+#else
+#define STM32_ADC_CHANNEL_20 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_20 */
+#endif /* STM32_ADC_CHANNEL_20 */
+
+#ifndef STM32_ADC_CHANNEL_21
+#ifdef ADC_CHANNEL_21
+#define STM32_ADC_CHANNEL_21 ADC_CHANNEL_21
+#else
+#define STM32_ADC_CHANNEL_21 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_21 */
+#endif /* STM32_ADC_CHANNEL_21 */
+
+#ifndef STM32_ADC_CHANNEL_22
+#ifdef ADC_CHANNEL_22
+#define STM32_ADC_CHANNEL_22 ADC_CHANNEL_22
+#else
+#define STM32_ADC_CHANNEL_22 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_22 */
+#endif /* STM32_ADC_CHANNEL_22 */
+
+#ifndef STM32_ADC_CHANNEL_23
+#ifdef ADC_CHANNEL_23
+#define STM32_ADC_CHANNEL_23 ADC_CHANNEL_23
+#else
+#define STM32_ADC_CHANNEL_23 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_23 */
+#endif /* STM32_ADC_CHANNEL_23 */
+
+#ifndef STM32_ADC_CHANNEL_24
+#ifdef ADC_CHANNEL_24
+#define STM32_ADC_CHANNEL_24 ADC_CHANNEL_24
+#else
+#define STM32_ADC_CHANNEL_24 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_24 */
+#endif /* STM32_ADC_CHANNEL_24 */
+
+#ifndef STM32_ADC_CHANNEL_25
+#ifdef ADC_CHANNEL_25
+#define STM32_ADC_CHANNEL_25 ADC_CHANNEL_25
+#else
+#define STM32_ADC_CHANNEL_25 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_25 */
+#endif /* STM32_ADC_CHANNEL_25 */
+
+#ifndef STM32_ADC_CHANNEL_26
+#ifdef ADC_CHANNEL_26
+#define STM32_ADC_CHANNEL_26 ADC_CHANNEL_26
+#else
+#define STM32_ADC_CHANNEL_26 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_26 */
+#endif /* STM32_ADC_CHANNEL_26 */
+
+#ifndef STM32_ADC_CHANNEL_27
+#ifdef ADC_CHANNEL_27
+#define STM32_ADC_CHANNEL_27 ADC_CHANNEL_27
+#else
+#define STM32_ADC_CHANNEL_27 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_27 */
+#endif /* STM32_ADC_CHANNEL_27 */
+
+#ifndef STM32_ADC_CHANNEL_28
+#ifdef ADC_CHANNEL_28
+#define STM32_ADC_CHANNEL_28 ADC_CHANNEL_28
+#else
+#define STM32_ADC_CHANNEL_28 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_28 */
+#endif /* STM32_ADC_CHANNEL_28 */
+
+#ifndef STM32_ADC_CHANNEL_29
+#ifdef ADC_CHANNEL_29
+#define STM32_ADC_CHANNEL_29 ADC_CHANNEL_29
+#else
+#define STM32_ADC_CHANNEL_29 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_29 */
+#endif /* STM32_ADC_CHANNEL_29 */
+
+#ifndef STM32_ADC_CHANNEL_30
+#ifdef ADC_CHANNEL_30
+#define STM32_ADC_CHANNEL_30 ADC_CHANNEL_30
+#else
+#define STM32_ADC_CHANNEL_30 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_30 */
+#endif /* STM32_ADC_CHANNEL_30 */
+
+#ifndef STM32_ADC_CHANNEL_31
+#ifdef ADC_CHANNEL_31
+#define STM32_ADC_CHANNEL_31 ADC_CHANNEL_31
+#else
+#define STM32_ADC_CHANNEL_31 STM32_ADC_INVALID_CHANNEL
+#endif /* ADC_CHANNEL_31 */
+#endif /* STM32_ADC_CHANNEL_31 */
+
+/**
+ * @brief Default ADC instance mask for common STM32 internal ADC sources.
+ *
+ * Series configuration files should override this macro only when internal
+ * sources are not routed to ADC1 by default.
+ */
+#ifndef STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#define STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC1
+#endif /* STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK */
+
+/* Resolve temperature sensor HAL channel and supported ADC instances. */
+#ifndef STM32_ADC_TEMP_HAL_CHANNEL
+#if defined(ADC_CHANNEL_TEMPSENSOR_ADC1)
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR_ADC1
+#ifndef STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_TEMP_INSTANCE_MASK
+#define STM32_ADC_TEMP_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC1
+#endif /* STM32_ADC_TEMP_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_TEMPSENSOR_ADC3)
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR_ADC3
+#ifndef STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_TEMP_INSTANCE_MASK
+#define STM32_ADC_TEMP_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC3
+#endif /* STM32_ADC_TEMP_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_TEMPSENSOR)
+#define STM32_ADC_TEMP_HAL_CHANNEL ADC_CHANNEL_TEMPSENSOR
+#ifndef STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_TEMP_INSTANCE_MASK
+#define STM32_ADC_TEMP_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#endif /* STM32_ADC_TEMP_INSTANCE_MASK */
+#else
+#define STM32_ADC_TEMP_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#ifndef STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL_AVAILABLE 0
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_TEMP_INSTANCE_MASK
+#define STM32_ADC_TEMP_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_TEMP_INSTANCE_MASK */
+#endif /* defined(ADC_CHANNEL_TEMPSENSOR_ADC1) */
+#endif /* STM32_ADC_TEMP_HAL_CHANNEL */
+
+/** @brief Whether the primary temperature-sensor HAL channel can be used. */
+#ifndef STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+
+#ifndef STM32_ADC_TEMP_INSTANCE_MASK
+#if STM32_ADC_TEMP_CHANNEL_AVAILABLE
+/** @brief ADC instances that can sample the temperature sensor. */
+#define STM32_ADC_TEMP_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#else
+/** @brief ADC instances that can sample the temperature sensor. */
+#define STM32_ADC_TEMP_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_TEMP_INSTANCE_MASK */
+
+#ifndef STM32_ADC_TEMP_CHANNEL
+#if !STM32_ADC_TEMP_CHANNEL_AVAILABLE
+#define STM32_ADC_TEMP_CHANNEL STM32_ADC_INVALID_LOGICAL_CHANNEL
+#elif defined(STM32_ADC_TEMP_LOGICAL_OVERRIDE)
+#define STM32_ADC_TEMP_CHANNEL STM32_ADC_TEMP_LOGICAL_OVERRIDE
+#elif defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) || defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_TEMP_CHANNEL STM32_ADC_HAL_CHANNEL_TO_LOGICAL(STM32_ADC_TEMP_HAL_CHANNEL)
+#else
+#error "STM32 ADC V2: define STM32_ADC_TEMP_LOGICAL_OVERRIDE for this legacy HAL series."
+#endif /* !STM32_ADC_TEMP_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_TEMP_CHANNEL */
+
+/* Resolve VBAT HAL channel and supported ADC instances. */
+#ifndef STM32_ADC_VBAT_HAL_CHANNEL
+#if defined(ADC_CHANNEL_VBAT_ADC1)
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT_ADC1
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#define STM32_ADC_VBAT_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC1
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VBAT_ADC2)
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT_ADC2
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#define STM32_ADC_VBAT_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC2
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VBAT_ADC3)
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT_ADC3
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#define STM32_ADC_VBAT_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC3
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VBAT)
+#define STM32_ADC_VBAT_HAL_CHANNEL ADC_CHANNEL_VBAT
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#define STM32_ADC_VBAT_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+#else
+#define STM32_ADC_VBAT_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 0
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#define STM32_ADC_VBAT_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+#endif /* defined(ADC_CHANNEL_VBAT_ADC1) */
+#endif /* STM32_ADC_VBAT_HAL_CHANNEL */
+
+/** @brief Whether the primary VBAT HAL channel can be used. */
+#ifndef STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+
+#ifndef STM32_ADC_VBAT_INSTANCE_MASK
+#if STM32_ADC_VBAT_CHANNEL_AVAILABLE
+/** @brief ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#else
+/** @brief ADC instances that can sample VBAT. */
+#define STM32_ADC_VBAT_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_VBAT_INSTANCE_MASK */
+
+#ifndef STM32_ADC_VBAT_CHANNEL
+#if !STM32_ADC_VBAT_CHANNEL_AVAILABLE
+#define STM32_ADC_VBAT_CHANNEL STM32_ADC_INVALID_LOGICAL_CHANNEL
+#elif defined(STM32_ADC_VBAT_LOGICAL_OVERRIDE)
+#define STM32_ADC_VBAT_CHANNEL STM32_ADC_VBAT_LOGICAL_OVERRIDE
+#elif defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) || defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_VBAT_CHANNEL STM32_ADC_HAL_CHANNEL_TO_LOGICAL(STM32_ADC_VBAT_HAL_CHANNEL)
+#else
+#error "STM32 ADC V2: define STM32_ADC_VBAT_LOGICAL_OVERRIDE for this legacy HAL series."
+#endif /* !STM32_ADC_VBAT_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_VBAT_CHANNEL */
+
+/* Resolve VREFINT HAL channel and supported ADC instances. */
+#ifndef STM32_ADC_VREF_HAL_CHANNEL
+#if defined(ADC_CHANNEL_VREFINT_ADC1)
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT_ADC1
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#define STM32_ADC_VREF_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC1
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VREFINT_ADC2)
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT_ADC2
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#define STM32_ADC_VREF_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC2
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VREFINT_ADC3)
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT_ADC3
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#define STM32_ADC_VREF_INSTANCE_MASK STM32_ADC_INSTANCE_MASK_ADC3
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+#elif defined(ADC_CHANNEL_VREFINT)
+#define STM32_ADC_VREF_HAL_CHANNEL ADC_CHANNEL_VREFINT
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#define STM32_ADC_VREF_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+#else
+#define STM32_ADC_VREF_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 0
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#define STM32_ADC_VREF_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+#endif /* defined(ADC_CHANNEL_VREFINT_ADC1) */
+#endif /* STM32_ADC_VREF_HAL_CHANNEL */
+
+/** @brief Whether the primary VREFINT HAL channel can be used. */
+#ifndef STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL_AVAILABLE 1
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+
+#ifndef STM32_ADC_VREF_INSTANCE_MASK
+#if STM32_ADC_VREF_CHANNEL_AVAILABLE
+/** @brief ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK STM32_ADC_INTERNAL_DEFAULT_INSTANCE_MASK
+#else
+/** @brief ADC instances that can sample VREFINT. */
+#define STM32_ADC_VREF_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_VREF_INSTANCE_MASK */
+
+#ifndef STM32_ADC_VREF_CHANNEL
+#if !STM32_ADC_VREF_CHANNEL_AVAILABLE
+#define STM32_ADC_VREF_CHANNEL STM32_ADC_INVALID_LOGICAL_CHANNEL
+#elif defined(STM32_ADC_VREF_LOGICAL_OVERRIDE)
+#define STM32_ADC_VREF_CHANNEL STM32_ADC_VREF_LOGICAL_OVERRIDE
+#elif defined(__HAL_ADC_CHANNEL_TO_DECIMAL_NB) || defined(__LL_ADC_CHANNEL_TO_DECIMAL_NB)
+#define STM32_ADC_VREF_CHANNEL STM32_ADC_HAL_CHANNEL_TO_LOGICAL(STM32_ADC_VREF_HAL_CHANNEL)
+#else
+#error "STM32 ADC V2: define STM32_ADC_VREF_LOGICAL_OVERRIDE for this legacy HAL series."
+#endif /* !STM32_ADC_VREF_CHANNEL_AVAILABLE */
+#endif /* STM32_ADC_VREF_CHANNEL */
+
+#ifndef STM32_ADC_TEMP_ALT_HAL_CHANNEL
+#define STM32_ADC_TEMP_ALT_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#endif /* STM32_ADC_TEMP_ALT_HAL_CHANNEL */
+
+#ifndef STM32_ADC_TEMP_ALT_INSTANCE_MASK
+#define STM32_ADC_TEMP_ALT_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_TEMP_ALT_INSTANCE_MASK */
+
+#ifndef STM32_ADC_VBAT_ALT_HAL_CHANNEL
+#define STM32_ADC_VBAT_ALT_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#endif /* STM32_ADC_VBAT_ALT_HAL_CHANNEL */
+
+#ifndef STM32_ADC_VBAT_ALT_INSTANCE_MASK
+#define STM32_ADC_VBAT_ALT_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VBAT_ALT_INSTANCE_MASK */
+
+#ifndef STM32_ADC_VREF_ALT_HAL_CHANNEL
+#define STM32_ADC_VREF_ALT_HAL_CHANNEL STM32_ADC_INVALID_CHANNEL
+#endif /* STM32_ADC_VREF_ALT_HAL_CHANNEL */
+
+#ifndef STM32_ADC_VREF_ALT_INSTANCE_MASK
+#define STM32_ADC_VREF_ALT_INSTANCE_MASK 0UL
+#endif /* STM32_ADC_VREF_ALT_INSTANCE_MASK */
+
+#ifndef STM32_ADC_USING_STREAM
+#define STM32_ADC_USING_STREAM 0
+#endif /* STM32_ADC_USING_STREAM */
+
+#ifndef STM32_ADC_USING_DMA_STREAM
+#define STM32_ADC_USING_DMA_STREAM STM32_ADC_USING_STREAM
+#endif /* STM32_ADC_USING_DMA_STREAM */
+
+
+#if defined(STM32_ADC_USING_TRIGGER)
+/**
+ * @brief Prepared STM32 ADC external trigger fields.
+ */
+struct stm32_adc_trigger_fields
+{
+ rt_uint32_t selector; /**< HAL ADC external trigger selector. */
+ rt_uint32_t edge; /**< HAL ADC external trigger edge selector. */
+};
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+
+/**
+ * @brief STM32 ADC device object.
+ *
+ * @note The HAL ADC handle must remain the first member. STM32 HAL
+ * callbacks receive an ADC_HandleTypeDef pointer, and this driver
+ * casts it back to struct stm32_adc while handling callbacks.
+ */
+struct stm32_adc
+{
+ ADC_HandleTypeDef handle; /**< HAL ADC handle; keep first for HAL callback owner cast. */
+ const char *name; /**< Device name. */
+ struct stm32_adc_private_cfg config; /**< Default STM32 backend private configuration. */
+ struct rt_adc_device device; /**< RT-Thread ADC device object. */
+#if STM32_ADC_USING_DMA_STREAM
+ const struct stm32_dma_config *dma_rx; /**< ADC stream DMA RX configuration. */
+ DMA_HandleTypeDef dma_handle; /**< HAL DMA handle used by stream mode. */
+#if defined(STM32_ADC_NEEDS_DMA_CACHE_MAINTENANCE)
+ rt_uint32_t *cache_dma_buffer; /**< Cache-aligned stream DMA buffer when caller buffer is not safe. */
+#endif /* defined(STM32_ADC_NEEDS_DMA_CACHE_MAINTENANCE) */
+#endif /* STM32_ADC_USING_DMA_STREAM */
+#if defined(STM32_ADC_USING_TRIGGER)
+ struct stm32_adc_trigger_fields prepared_trigger; /**< Cached trigger selector fields for the next stream config. */
+ rt_bool_t prepared_trigger_valid; /**< Whether prepared_trigger contains a valid cached selector. */
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+};
+
+/*
+ * HAL callbacks receive ADC_HandleTypeDef *. The driver casts it back to
+ * struct stm32_adc, so the HAL handle must remain the first member.
+ */
+RT_STATIC_ASSERT(stm32_adc_handle_must_be_first, offsetof(struct stm32_adc, handle) == 0U);
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Check whether an ADC peripheral instance matches an instance mask.
+ * @param instance ADC peripheral instance.
+ * @param mask STM32_ADC_INSTANCE_MASK_x bit mask.
+ * @return RT_TRUE if the instance is included, otherwise RT_FALSE.
+ */
+rt_bool_t stm32_adc_instance_match(ADC_TypeDef *instance, rt_uint32_t mask);
+
+/**
+ * @brief Get the HAL ADC channel identifier.
+ * @param channel RT-Thread ADC channel identifier.
+ * @param hal_channel Pointer to the output HAL ADC channel identifier.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_channel(rt_uint8_t channel, uint32_t *hal_channel);
+
+/**
+ * @brief Get the logical channel used to sample STM32 internal VREFINT.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical VREFINT channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_vref_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel);
+
+/**
+ * @brief Get the logical channel used to sample STM32 internal temperature sensor.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical temperature-sensor channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_tempsensor_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel);
+
+/**
+ * @brief Get the logical channel used to sample STM32 internal VBAT divider.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Pointer to the output logical VBAT channel.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_vbat_logical_channel(struct stm32_adc *adc, rt_uint8_t *channel);
+
+/**
+ * @brief Get one HAL sampling-time value from STM32 private configuration.
+ * @param cfg Pointer to the STM32 backend private configuration.
+ * @param sampling_time Pointer to the output HAL sampling-time value.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_get_sampling_time(const struct stm32_adc_private_cfg *cfg, uint32_t *sampling_time);
+
+/**
+ * @brief Get the current ADC resolution in bits.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @return Resolution in bits, or 12 when it cannot be determined.
+ */
+rt_uint8_t stm32_adc_get_resolution_bits(const struct stm32_adc *adc);
+
+/**
+ * @brief Calculate STM32 internal temperature sensor value in degrees Celsius.
+ * @param device ADC device handle.
+ * @param raw_value Raw ADC sample value from the temperature sensor channel.
+ * @param vref_mv Current analog reference voltage in millivolts.
+ * @param resolution_bits ADC conversion resolution used for @p raw_value.
+ * @param temperature_c Pointer to the output temperature in degrees Celsius.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_calc_temperature(rt_adc_device_t device, rt_uint32_t raw_value,
+ rt_uint32_t vref_mv, rt_uint8_t resolution_bits,
+ rt_int32_t *temperature_c);
+
+/**
+ * @brief Calculate VDDA from a raw VREFINT sample.
+ * @param device Pointer to the ADC device object.
+ * @param vref_mv Pointer to the raw VREFINT sample on input and VDDA millivolts on output.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_calc_vref_mv(struct rt_adc_device *device, rt_uint32_t *vref_mv);
+
+
+#if defined(STM32_ADC_USING_TRIGGER)
+/**
+ * @brief Resolve STM32 ADC trigger selector fields.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration, or RT_NULL for software start.
+ * @param fields Pointer to the output STM32 trigger fields.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_trigger_fields_get(struct stm32_adc *adc, const struct rt_adc_trigger_cfg *cfg,
+ struct stm32_adc_trigger_fields *fields);
+
+/**
+ * @brief Preconfigure STM32 ADC trigger selector state for the next stream configuration.
+ * @param device Pointer to the ADC framework device object.
+ * @param cfg Pointer to the ADC trigger configuration, or RT_NULL for software start.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_trigger_prepare(struct rt_adc_device *device, const struct rt_adc_trigger_cfg *cfg);
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4) */
+
+#endif /* defined(RT_USING_ADC_V2) */
+
+#endif /* __DRV_ADC_V2_PRIVATE_H__ */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_trigger.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_trigger.c
new file mode 100644
index 0000000000..59a4d4c8c9
--- /dev/null
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_adc_v2_trigger.c
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-24 wdfk-prog add STM32 ADC V2 timer trigger backend
+ */
+
+/**
+ * @file drv_adc_v2_trigger.c
+ * @brief STM32 ADC V2 trigger selector backend.
+ */
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include "drv_config.h"
+#include "drv_adc_v2_private.h"
+
+#if defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4)
+
+#define DRV_DEBUG
+#define LOG_TAG "drv.adc"
+#include <drv_log.h>
+
+#if defined(STM32_ADC_USING_TRIGGER)
+/** @brief Invalid trigger selector array slot. */
+#define STM32_ADC_TRIGGER_SELECTOR_NONE { 0U, RT_FALSE }
+
+/** @brief Valid trigger selector array slot initializer. */
+#define STM32_ADC_TRIGGER_SELECTOR(_selector) { (_selector), RT_TRUE }
+
+/** @brief Maximum compare channel index encoded by the STM32 ADC trigger tables. */
+#define STM32_ADC_TIMER_COMPARE_CHANNEL_MAX 4U
+
+/**
+ * @brief STM32 ADC trigger selector slot.
+ */
+struct stm32_adc_trigger_selector
+{
+ rt_uint32_t selector; /**< HAL ADC external trigger selector. */
+ rt_bool_t valid; /**< Whether selector is valid for this slot. */
+};
+
+/**
+ * @brief Encode one ADC trigger edge as STM32 HAL external trigger edge.
+ * @param edge ADC framework trigger edge.
+ * @param hal_edge Pointer to the HAL edge selector output.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_trigger_edge_encode(enum rt_adc_trigger_edge edge, rt_uint32_t *hal_edge)
+{
+ if (hal_edge == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+#if defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE)
+ switch (edge)
+ {
+ case RT_ADC_TRIGGER_EDGE_NONE:
+#if defined(ADC_EXTERNALTRIGCONVEDGE_NONE)
+ *hal_edge = ADC_EXTERNALTRIGCONVEDGE_NONE;
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_NONE) */
+
+ case RT_ADC_TRIGGER_EDGE_RISING:
+#if defined(ADC_EXTERNALTRIGCONVEDGE_RISING)
+ *hal_edge = ADC_EXTERNALTRIGCONVEDGE_RISING;
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_RISING) */
+
+ case RT_ADC_TRIGGER_EDGE_FALLING:
+#if defined(ADC_EXTERNALTRIGCONVEDGE_FALLING)
+ *hal_edge = ADC_EXTERNALTRIGCONVEDGE_FALLING;
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_FALLING) */
+
+ case RT_ADC_TRIGGER_EDGE_BOTH:
+#if defined(ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING)
+ *hal_edge = ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING;
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING) */
+
+ default:
+ return -RT_EINVAL;
+ }
+#else
+ if ((edge != RT_ADC_TRIGGER_EDGE_NONE) && (edge != RT_ADC_TRIGGER_EDGE_RISING))
+ {
+ return -RT_ENOSYS;
+ }
+
+ *hal_edge = 0U;
+ return RT_EOK;
+#endif /* defined(STM32_ADC_HAS_INIT_EXT_TRIG_EDGE) */
+}
+
+#if defined(STM32_ADC_USING_TIMER_TRIGGER)
+/**
+ * @brief STM32 timer to ADC trigger selector mapping entry.
+ */
+struct stm32_adc_timer_trigger_map
+{
+ TIM_TypeDef *instance; /**< TIM hardware instance. */
+ rt_uint32_t adc_instance_mask; /**< ADC instances allowed to use this trigger. */
+ struct stm32_adc_trigger_selector update; /**< TIM update/TRGO trigger selector. */
+
+ /** TIM compare trigger selectors indexed by 1-based channel number. */
+ struct stm32_adc_trigger_selector compare[STM32_ADC_TIMER_COMPARE_CHANNEL_MAX + 1U];
+};
+
+/**
+ * @brief ADC timer trigger selector table.
+ *
+ * @note Compare selectors are intentionally encoded with array indexes so
+ * channel 1 maps to compare[1], channel 2 maps to compare[2], etc.
+ */
+static const struct stm32_adc_timer_trigger_map stm32_adc_timer_trigger_table[] = {
+#if defined(TIM1)
+ {
+ TIM1,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T1_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T1_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T1_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T1_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T1_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T1_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T1_CC1),
+#elif defined(ADC_EXTERNALTRIG_T1_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T1_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T1_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T1_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T1_CC2),
+#elif defined(ADC_EXTERNALTRIG_T1_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T1_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T1_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T1_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T1_CC3),
+#elif defined(ADC_EXTERNALTRIG_T1_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T1_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T1_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T1_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T1_CC4),
+#elif defined(ADC_EXTERNALTRIG_T1_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T1_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T1_CC4) */
+ },
+ },
+#endif /* defined(TIM1) */
+#if defined(TIM2)
+ {
+ TIM2,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T2_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T2_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T2_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T2_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T2_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T2_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T2_CC1),
+#elif defined(ADC_EXTERNALTRIG_T2_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T2_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T2_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T2_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T2_CC2),
+#elif defined(ADC_EXTERNALTRIG_T2_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T2_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T2_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T2_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T2_CC3),
+#elif defined(ADC_EXTERNALTRIG_T2_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T2_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T2_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T2_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T2_CC4),
+#elif defined(ADC_EXTERNALTRIG_T2_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T2_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T2_CC4) */
+ },
+ },
+#endif /* defined(TIM2) */
+#if defined(TIM3)
+ {
+ TIM3,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T3_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T3_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T3_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T3_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T3_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T3_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T3_CC1),
+#elif defined(ADC_EXTERNALTRIG_T3_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T3_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T3_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T3_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T3_CC2),
+#elif defined(ADC_EXTERNALTRIG_T3_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T3_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T3_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T3_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T3_CC3),
+#elif defined(ADC_EXTERNALTRIG_T3_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T3_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T3_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T3_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T3_CC4),
+#elif defined(ADC_EXTERNALTRIG_T3_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T3_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T3_CC4) */
+ },
+ },
+#endif /* defined(TIM3) */
+#if defined(TIM4)
+ {
+ TIM4,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T4_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T4_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T4_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T4_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T4_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T4_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T4_CC1),
+#elif defined(ADC_EXTERNALTRIG_T4_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T4_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T4_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T4_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T4_CC2),
+#elif defined(ADC_EXTERNALTRIG_T4_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T4_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T4_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T4_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T4_CC3),
+#elif defined(ADC_EXTERNALTRIG_T4_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T4_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T4_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T4_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T4_CC4),
+#elif defined(ADC_EXTERNALTRIG_T4_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T4_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T4_CC4) */
+ },
+ },
+#endif /* defined(TIM4) */
+#if defined(TIM5)
+ {
+ TIM5,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T5_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T5_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T5_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T5_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T5_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T5_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T5_CC1),
+#elif defined(ADC_EXTERNALTRIG_T5_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T5_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T5_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T5_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T5_CC2),
+#elif defined(ADC_EXTERNALTRIG_T5_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T5_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T5_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T5_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T5_CC3),
+#elif defined(ADC_EXTERNALTRIG_T5_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T5_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T5_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T5_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T5_CC4),
+#elif defined(ADC_EXTERNALTRIG_T5_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T5_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T5_CC4) */
+ },
+ },
+#endif /* defined(TIM5) */
+#if defined(TIM6)
+ {
+ TIM6,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T6_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T6_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T6_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T6_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T6_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T6_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T6_CC1),
+#elif defined(ADC_EXTERNALTRIG_T6_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T6_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T6_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T6_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T6_CC2),
+#elif defined(ADC_EXTERNALTRIG_T6_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T6_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T6_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T6_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T6_CC3),
+#elif defined(ADC_EXTERNALTRIG_T6_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T6_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T6_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T6_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T6_CC4),
+#elif defined(ADC_EXTERNALTRIG_T6_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T6_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T6_CC4) */
+ },
+ },
+#endif /* defined(TIM6) */
+#if defined(TIM7)
+ {
+ TIM7,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T7_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T7_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T7_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T7_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T7_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T7_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T7_CC1),
+#elif defined(ADC_EXTERNALTRIG_T7_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T7_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T7_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T7_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T7_CC2),
+#elif defined(ADC_EXTERNALTRIG_T7_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T7_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T7_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T7_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T7_CC3),
+#elif defined(ADC_EXTERNALTRIG_T7_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T7_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T7_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T7_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T7_CC4),
+#elif defined(ADC_EXTERNALTRIG_T7_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T7_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T7_CC4) */
+ },
+ },
+#endif /* defined(TIM7) */
+#if defined(TIM8)
+ {
+ TIM8,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T8_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T8_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T8_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T8_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T8_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T8_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T8_CC1),
+#elif defined(ADC_EXTERNALTRIG_T8_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T8_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T8_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T8_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T8_CC2),
+#elif defined(ADC_EXTERNALTRIG_T8_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T8_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T8_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T8_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T8_CC3),
+#elif defined(ADC_EXTERNALTRIG_T8_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T8_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T8_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T8_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T8_CC4),
+#elif defined(ADC_EXTERNALTRIG_T8_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T8_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T8_CC4) */
+ },
+ },
+#endif /* defined(TIM8) */
+#if defined(TIM9)
+ {
+ TIM9,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T9_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T9_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T9_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T9_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T9_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T9_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T9_CC1),
+#elif defined(ADC_EXTERNALTRIG_T9_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T9_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T9_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T9_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T9_CC2),
+#elif defined(ADC_EXTERNALTRIG_T9_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T9_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T9_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T9_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T9_CC3),
+#elif defined(ADC_EXTERNALTRIG_T9_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T9_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T9_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T9_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T9_CC4),
+#elif defined(ADC_EXTERNALTRIG_T9_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T9_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T9_CC4) */
+ },
+ },
+#endif /* defined(TIM9) */
+#if defined(TIM10)
+ {
+ TIM10,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T10_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T10_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T10_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T10_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T10_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T10_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T10_CC1),
+#elif defined(ADC_EXTERNALTRIG_T10_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T10_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T10_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T10_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T10_CC2),
+#elif defined(ADC_EXTERNALTRIG_T10_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T10_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T10_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T10_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T10_CC3),
+#elif defined(ADC_EXTERNALTRIG_T10_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T10_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T10_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T10_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T10_CC4),
+#elif defined(ADC_EXTERNALTRIG_T10_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T10_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T10_CC4) */
+ },
+ },
+#endif /* defined(TIM10) */
+#if defined(TIM11)
+ {
+ TIM11,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T11_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T11_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T11_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T11_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T11_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T11_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T11_CC1),
+#elif defined(ADC_EXTERNALTRIG_T11_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T11_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T11_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T11_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T11_CC2),
+#elif defined(ADC_EXTERNALTRIG_T11_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T11_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T11_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T11_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T11_CC3),
+#elif defined(ADC_EXTERNALTRIG_T11_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T11_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T11_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T11_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T11_CC4),
+#elif defined(ADC_EXTERNALTRIG_T11_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T11_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T11_CC4) */
+ },
+ },
+#endif /* defined(TIM11) */
+#if defined(TIM12)
+ {
+ TIM12,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T12_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T12_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T12_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T12_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T12_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T12_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T12_CC1),
+#elif defined(ADC_EXTERNALTRIG_T12_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T12_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T12_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T12_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T12_CC2),
+#elif defined(ADC_EXTERNALTRIG_T12_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T12_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T12_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T12_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T12_CC3),
+#elif defined(ADC_EXTERNALTRIG_T12_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T12_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T12_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T12_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T12_CC4),
+#elif defined(ADC_EXTERNALTRIG_T12_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T12_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T12_CC4) */
+ },
+ },
+#endif /* defined(TIM12) */
+#if defined(TIM13)
+ {
+ TIM13,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T13_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T13_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T13_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T13_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T13_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T13_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T13_CC1),
+#elif defined(ADC_EXTERNALTRIG_T13_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T13_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T13_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T13_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T13_CC2),
+#elif defined(ADC_EXTERNALTRIG_T13_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T13_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T13_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T13_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T13_CC3),
+#elif defined(ADC_EXTERNALTRIG_T13_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T13_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T13_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T13_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T13_CC4),
+#elif defined(ADC_EXTERNALTRIG_T13_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T13_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T13_CC4) */
+ },
+ },
+#endif /* defined(TIM13) */
+#if defined(TIM14)
+ {
+ TIM14,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T14_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T14_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T14_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T14_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T14_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T14_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T14_CC1),
+#elif defined(ADC_EXTERNALTRIG_T14_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T14_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T14_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T14_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T14_CC2),
+#elif defined(ADC_EXTERNALTRIG_T14_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T14_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T14_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T14_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T14_CC3),
+#elif defined(ADC_EXTERNALTRIG_T14_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T14_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T14_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T14_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T14_CC4),
+#elif defined(ADC_EXTERNALTRIG_T14_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T14_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T14_CC4) */
+ },
+ },
+#endif /* defined(TIM14) */
+#if defined(TIM15)
+ {
+ TIM15,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T15_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T15_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T15_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T15_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T15_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T15_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T15_CC1),
+#elif defined(ADC_EXTERNALTRIG_T15_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T15_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T15_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T15_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T15_CC2),
+#elif defined(ADC_EXTERNALTRIG_T15_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T15_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T15_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T15_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T15_CC3),
+#elif defined(ADC_EXTERNALTRIG_T15_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T15_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T15_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T15_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T15_CC4),
+#elif defined(ADC_EXTERNALTRIG_T15_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T15_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T15_CC4) */
+ },
+ },
+#endif /* defined(TIM15) */
+#if defined(TIM16)
+ {
+ TIM16,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T16_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T16_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T16_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T16_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T16_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T16_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T16_CC1),
+#elif defined(ADC_EXTERNALTRIG_T16_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T16_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T16_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T16_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T16_CC2),
+#elif defined(ADC_EXTERNALTRIG_T16_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T16_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T16_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T16_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T16_CC3),
+#elif defined(ADC_EXTERNALTRIG_T16_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T16_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T16_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T16_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T16_CC4),
+#elif defined(ADC_EXTERNALTRIG_T16_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T16_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T16_CC4) */
+ },
+ },
+#endif /* defined(TIM16) */
+#if defined(TIM17)
+ {
+ TIM17,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T17_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T17_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T17_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T17_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T17_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T17_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T17_CC1),
+#elif defined(ADC_EXTERNALTRIG_T17_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T17_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T17_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T17_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T17_CC2),
+#elif defined(ADC_EXTERNALTRIG_T17_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T17_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T17_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T17_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T17_CC3),
+#elif defined(ADC_EXTERNALTRIG_T17_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T17_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T17_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T17_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T17_CC4),
+#elif defined(ADC_EXTERNALTRIG_T17_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T17_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T17_CC4) */
+ },
+ },
+#endif /* defined(TIM17) */
+#if defined(TIM18)
+{
+ TIM18,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T18_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T18_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T18_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T18_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T18_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T18_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T18_CC1),
+#elif defined(ADC_EXTERNALTRIG_T18_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T18_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T18_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T18_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T18_CC2),
+#elif defined(ADC_EXTERNALTRIG_T18_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T18_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T18_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T18_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T18_CC3),
+#elif defined(ADC_EXTERNALTRIG_T18_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T18_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T18_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T18_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T18_CC4),
+#elif defined(ADC_EXTERNALTRIG_T18_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T18_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T18_CC4) */
+ },
+},
+#endif /* defined(TIM18) */
+#if defined(TIM19)
+{
+ TIM19,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T19_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T19_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T19_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T19_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T19_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T19_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T19_CC1),
+#elif defined(ADC_EXTERNALTRIG_T19_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T19_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T19_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T19_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T19_CC2),
+#elif defined(ADC_EXTERNALTRIG_T19_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T19_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T19_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T19_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T19_CC3),
+#elif defined(ADC_EXTERNALTRIG_T19_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T19_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T19_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T19_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T19_CC4),
+#elif defined(ADC_EXTERNALTRIG_T19_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T19_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T19_CC4) */
+ },
+},
+#endif /* defined(TIM19) */
+#if defined(TIM20)
+ {
+ TIM20,
+ STM32_ADC_INSTANCE_MASK_ALL,
+#if defined(ADC_EXTERNALTRIGCONV_T20_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T20_TRGO),
+#elif defined(ADC_EXTERNALTRIG_T20_TRGO)
+ STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T20_TRGO),
+#else
+ STM32_ADC_TRIGGER_SELECTOR_NONE,
+#endif /* defined(ADC_EXTERNALTRIGCONV_T20_TRGO) */
+ {
+#if defined(ADC_EXTERNALTRIGCONV_T20_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T20_CC1),
+#elif defined(ADC_EXTERNALTRIG_T20_CC1)
+ [1] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T20_CC1),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T20_CC1) */
+#if defined(ADC_EXTERNALTRIGCONV_T20_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T20_CC2),
+#elif defined(ADC_EXTERNALTRIG_T20_CC2)
+ [2] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T20_CC2),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T20_CC2) */
+#if defined(ADC_EXTERNALTRIGCONV_T20_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T20_CC3),
+#elif defined(ADC_EXTERNALTRIG_T20_CC3)
+ [3] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T20_CC3),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T20_CC3) */
+#if defined(ADC_EXTERNALTRIGCONV_T20_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_T20_CC4),
+#elif defined(ADC_EXTERNALTRIG_T20_CC4)
+ [4] = STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_T20_CC4),
+#endif /* defined(ADC_EXTERNALTRIGCONV_T20_CC4) */
+ },
+ },
+#endif /* defined(TIM20) */
+};
+
+/**
+ * @brief Resolve an ADC external trigger selector from a TIM event.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param instance TIM hardware instance.
+ * @param channel Timer compare channel, or 0 for update/TRGO.
+ * @param selector Pointer to the output HAL ADC trigger selector.
+ * @return RT_TRUE if the timer event is supported by this HAL build and ADC instance.
+ */
+static rt_bool_t stm32_adc_timer_trigger_selector_get(struct stm32_adc *adc, TIM_TypeDef *instance,
+ rt_uint16_t channel, rt_uint32_t *selector)
+{
+ rt_size_t index;
+
+ for (index = 0; index < RT_ARRAY_SIZE(stm32_adc_timer_trigger_table); index++)
+ {
+ const struct stm32_adc_timer_trigger_map *map = &stm32_adc_timer_trigger_table[index];
+ const struct stm32_adc_trigger_selector *slot;
+
+ if (map->instance != instance)
+ {
+ continue;
+ }
+
+ if (stm32_adc_instance_match(adc->handle.Instance, map->adc_instance_mask) != RT_TRUE)
+ {
+ return RT_FALSE;
+ }
+
+ if (channel == 0U)
+ {
+ slot = &map->update;
+ }
+ else
+ {
+ if (channel > STM32_ADC_TIMER_COMPARE_CHANNEL_MAX)
+ {
+ return RT_FALSE;
+ }
+ slot = &map->compare[channel];
+ }
+
+ if (slot->valid != RT_TRUE)
+ {
+ return RT_FALSE;
+ }
+
+ *selector = slot->selector;
+ return RT_TRUE;
+ }
+
+ return RT_FALSE;
+}
+
+/**
+ * @brief Encode one STM32 ADC timer trigger configuration.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration object.
+ * @param selector Pointer to the output HAL ADC trigger selector.
+ * @param edge Pointer to the output HAL ADC trigger edge selector.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_encode_timer_trigger(struct stm32_adc *adc, const struct rt_adc_trigger_cfg *cfg,
+ rt_uint32_t *selector, rt_uint32_t *edge)
+{
+ TIM_HandleTypeDef *tim;
+ rt_uint16_t channel;
+ rt_err_t result;
+
+ if (cfg->event.timer.timer == RT_NULL)
+ {
+ LOG_E("%s timer trigger source is null", adc->name);
+ return -RT_EINVAL;
+ }
+
+ tim = (TIM_HandleTypeDef *)cfg->event.timer.timer->user_data;
+ if (tim == RT_NULL)
+ {
+ LOG_E("%s timer trigger source has no TIM handle", adc->name);
+ return -RT_EINVAL;
+ }
+
+ switch (cfg->type)
+ {
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+ channel = 0U;
+ break;
+
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+ channel = cfg->event.timer.channel;
+ if (channel == 0U)
+ {
+ LOG_E("%s timer compare trigger channel is invalid", adc->name);
+ return -RT_EINVAL;
+ }
+ break;
+
+ default:
+ return -RT_EINVAL;
+ }
+
+ if (stm32_adc_timer_trigger_selector_get(adc, tim->Instance, channel, selector) != RT_TRUE)
+ {
+ LOG_E("%s timer trigger source unsupported", adc->name);
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_trigger_edge_encode(RT_ADC_TRIGGER_EDGE_RISING, edge);
+ return result;
+}
+#endif /* defined(STM32_ADC_USING_TIMER_TRIGGER) */
+
+#if defined(STM32_ADC_USING_ANALOG_COMPARE_TRIGGER)
+/**
+ * @brief STM32 comparator to ADC trigger selector table entry.
+ */
+struct stm32_adc_compare_trigger_slot
+{
+ rt_uint32_t adc_instance_mask; /**< ADC instances allowed to use this comparator trigger. */
+ struct stm32_adc_trigger_selector trigger; /**< COMPx_OUT trigger selector. */
+};
+
+/**
+ * @brief ADC analog comparator trigger selector table indexed by comparator channel.
+ */
+static const struct stm32_adc_compare_trigger_slot stm32_adc_compare_trigger_table[] = {
+ [0] = { 0U, STM32_ADC_TRIGGER_SELECTOR_NONE },
+#if defined(ADC_EXTERNALTRIGCONV_COMP1_OUT)
+ [1] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP1_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP1_OUT)
+ [1] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP1_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP1)
+ [1] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP1) },
+#elif defined(ADC_EXTERNALTRIG_COMP1)
+ [1] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP1) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP1_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP2_OUT)
+ [2] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP2_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP2_OUT)
+ [2] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP2_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP2)
+ [2] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP2) },
+#elif defined(ADC_EXTERNALTRIG_COMP2)
+ [2] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP2) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP2_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP3_OUT)
+ [3] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP3_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP3_OUT)
+ [3] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP3_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP3)
+ [3] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP3) },
+#elif defined(ADC_EXTERNALTRIG_COMP3)
+ [3] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP3) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP3_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP4_OUT)
+ [4] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP4_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP4_OUT)
+ [4] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP4_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP4)
+ [4] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP4) },
+#elif defined(ADC_EXTERNALTRIG_COMP4)
+ [4] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP4) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP4_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP5_OUT)
+ [5] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP5_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP5_OUT)
+ [5] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP5_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP5)
+ [5] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP5) },
+#elif defined(ADC_EXTERNALTRIG_COMP5)
+ [5] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP5) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP5_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP6_OUT)
+ [6] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP6_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP6_OUT)
+ [6] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP6_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP6)
+ [6] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP6) },
+#elif defined(ADC_EXTERNALTRIG_COMP6)
+ [6] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP6) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP6_OUT) */
+#if defined(ADC_EXTERNALTRIGCONV_COMP7_OUT)
+ [7] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP7_OUT) },
+#elif defined(ADC_EXTERNALTRIG_COMP7_OUT)
+ [7] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP7_OUT) },
+#elif defined(ADC_EXTERNALTRIGCONV_COMP7)
+ [7] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIGCONV_COMP7) },
+#elif defined(ADC_EXTERNALTRIG_COMP7)
+ [7] = { STM32_ADC_INSTANCE_MASK_ALL, STM32_ADC_TRIGGER_SELECTOR(ADC_EXTERNALTRIG_COMP7) },
+#endif /* defined(ADC_EXTERNALTRIGCONV_COMP7_OUT) */
+};
+
+/**
+ * @brief Resolve an ADC external trigger selector from a comparator channel.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param channel Comparator channel.
+ * @param selector Pointer to the output HAL ADC trigger selector.
+ * @return RT_TRUE if the comparator channel is supported by this HAL build and ADC instance.
+ */
+static rt_bool_t stm32_adc_compare_trigger_selector_get(struct stm32_adc *adc, rt_uint16_t channel, rt_uint32_t *selector)
+{
+ const struct stm32_adc_compare_trigger_slot *slot;
+
+ if (channel >= RT_ARRAY_SIZE(stm32_adc_compare_trigger_table))
+ {
+ return RT_FALSE;
+ }
+
+ slot = &stm32_adc_compare_trigger_table[channel];
+ if (slot->trigger.valid != RT_TRUE)
+ {
+ return RT_FALSE;
+ }
+
+ if (stm32_adc_instance_match(adc->handle.Instance, slot->adc_instance_mask) != RT_TRUE)
+ {
+ return RT_FALSE;
+ }
+
+ *selector = slot->trigger.selector;
+ return RT_TRUE;
+}
+
+/**
+ * @brief Encode one STM32 ADC analog comparator trigger configuration.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration object.
+ * @param selector Pointer to the output HAL ADC trigger selector.
+ * @param edge Pointer to the output HAL ADC trigger edge selector.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_encode_compare_trigger(struct stm32_adc *adc, const struct rt_adc_trigger_cfg *cfg,
+ rt_uint32_t *selector, rt_uint32_t *edge)
+{
+ rt_err_t result;
+
+ if ((cfg->event.compare.channel == 0U) ||
+ (cfg->event.compare.edge == RT_ADC_TRIGGER_EDGE_NONE))
+ {
+ LOG_E("%s analog compare trigger config invalid", adc->name);
+ return -RT_EINVAL;
+ }
+
+ if (stm32_adc_compare_trigger_selector_get(adc, cfg->event.compare.channel, selector) != RT_TRUE)
+ {
+ LOG_E("%s analog compare trigger source unsupported", adc->name);
+ return -RT_ENOSYS;
+ }
+
+ result = stm32_adc_trigger_edge_encode(cfg->event.compare.edge, edge);
+ return result;
+}
+#endif /* defined(STM32_ADC_USING_ANALOG_COMPARE_TRIGGER) */
+
+/**
+ * @brief Encode one STM32 ADC trigger configuration into HAL selector fields.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration object, or RT_NULL for software/default trigger.
+ * @param selector Pointer to the output HAL ADC trigger selector.
+ * @param edge Pointer to the output HAL ADC trigger edge selector.
+ * @return Operation status.
+ */
+static rt_err_t stm32_adc_encode_trigger(struct stm32_adc *adc, const struct rt_adc_trigger_cfg *cfg,
+ rt_uint32_t *selector, rt_uint32_t *edge)
+{
+ rt_err_t result;
+
+ if (cfg == RT_NULL)
+ {
+ *selector = ADC_SOFTWARE_START;
+ return stm32_adc_trigger_edge_encode(RT_ADC_TRIGGER_EDGE_NONE, edge);
+ }
+
+ switch (cfg->type)
+ {
+#if defined(STM32_ADC_USING_TIMER_TRIGGER)
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+ result = stm32_adc_encode_timer_trigger(adc, cfg, selector, edge);
+ break;
+#endif /* defined(STM32_ADC_USING_TIMER_TRIGGER) */
+
+#if defined(STM32_ADC_USING_ANALOG_COMPARE_TRIGGER)
+ case RT_ADC_TRIGGER_ANALOG_COMPARE:
+ result = stm32_adc_encode_compare_trigger(adc, cfg, selector, edge);
+ break;
+#endif /* defined(STM32_ADC_USING_ANALOG_COMPARE_TRIGGER) */
+
+
+ default:
+ LOG_E("%s trigger type unsupported: %d", adc->name, (int)cfg->type);
+ result = -RT_ENOSYS;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * @brief Resolve STM32 ADC trigger selector fields.
+ * @param adc Pointer to the STM32 ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration, or RT_NULL for software start.
+ * @param fields Pointer to the output STM32 trigger fields.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_trigger_fields_get(struct stm32_adc *adc, const struct rt_adc_trigger_cfg *cfg,
+ struct stm32_adc_trigger_fields *fields)
+{
+ return stm32_adc_encode_trigger(adc, cfg, &fields->selector, &fields->edge);
+}
+
+/**
+ * @brief Preconfigure STM32 ADC trigger selector state for the next stream configuration.
+ * @param device Pointer to the ADC framework device object.
+ * @param cfg Pointer to the ADC trigger configuration, or RT_NULL for software start.
+ * @return Operation status.
+ */
+rt_err_t stm32_adc_trigger_prepare(struct rt_adc_device *device, const struct rt_adc_trigger_cfg *cfg)
+{
+ struct stm32_adc *adc;
+ struct stm32_adc_trigger_fields fields;
+ rt_err_t result;
+
+ adc = (struct stm32_adc *)device->parent.user_data;
+ if (adc == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = stm32_adc_trigger_fields_get(adc, cfg, &fields);
+ if (result != RT_EOK)
+ {
+ adc->prepared_trigger_valid = RT_FALSE;
+ return result;
+ }
+
+ adc->prepared_trigger = fields;
+ adc->prepared_trigger_valid = RT_TRUE;
+ return RT_EOK;
+}
+#endif /* defined(STM32_ADC_USING_TRIGGER) */
+
+#endif /* defined(BSP_USING_ADC1) || defined(BSP_USING_ADC2) || defined(BSP_USING_ADC3) || defined(BSP_USING_ADC4) */
+
+#endif /* defined(RT_USING_ADC_V2) */
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_config.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_config.h
index 8d68e3096c..415fde5434 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_config.h
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_config.h
@@ -6,7 +6,7 @@
* Change Logs:
* Date Author Notes
* 2018-10-30 SummerGift first version
- * 2020-10-14 PeakRacing Porting for stm32wbxx
+ * 2020-10-14 PeakRacing Porting for stm32wbxx
*/
#ifndef __DRV_CONFIG_H__
@@ -18,7 +18,7 @@
#ifdef __cplusplus
extern "C" {
-#endif
+#endif /* __cplusplus */
#if defined(SOC_SERIES_STM32F0)
#include "f0/dma_config.h"
@@ -27,82 +27,92 @@ extern "C" {
#include "f0/tim_config.h"
#include "f0/pwm_config.h"
#include "f0/adc_config.h"
+#include "f0/adc_config_v2.h"
#elif defined(SOC_SERIES_STM32F1)
#include "f1/dma_config.h"
#include "f1/uart_config.h"
#include "f1/spi_config.h"
#include "f1/adc_config.h"
+#include "f1/adc_config_v2.h"
#include "f1/tim_config.h"
#include "f1/sdio_config.h"
#include "f1/pwm_config.h"
#include "f1/usbd_config.h"
#include "f1/i2c_hard_config.h"
#include "f1/pulse_encoder_config.h"
-#elif defined(SOC_SERIES_STM32F2)
+#elif defined(SOC_SERIES_STM32F2)
#include "f2/dma_config.h"
#include "f2/uart_config.h"
#include "f2/spi_config.h"
#include "f2/adc_config.h"
+#include "f2/adc_config_v2.h"
#include "f2/tim_config.h"
#include "f2/sdio_config.h"
#include "f2/pwm_config.h"
-#elif defined(SOC_SERIES_STM32F3)
+#elif defined(SOC_SERIES_STM32F3)
#include "f3/uart_config.h"
#include "f3/tim_config.h"
#include "f3/pwm_config.h"
#include "f3/dma_config.h"
-#elif defined(SOC_SERIES_STM32F4)
+#include "f3/adc_config_v2.h"
+#elif defined(SOC_SERIES_STM32F4)
#include "f4/dma_config.h"
#include "f4/uart_config.h"
#include "f4/spi_config.h"
#include "f4/qspi_config.h"
#include "f4/usbd_config.h"
#include "f4/adc_config.h"
+#include "f4/adc_config_v2.h"
#include "f4/dac_config.h"
#include "f4/tim_config.h"
#include "f4/sdio_config.h"
#include "f4/pwm_config.h"
#include "f4/i2c_hard_config.h"
#include "f4/pulse_encoder_config.h"
-#elif defined(SOC_SERIES_STM32F7)
+#elif defined(SOC_SERIES_STM32F7)
#include "f7/dma_config.h"
#include "f7/uart_config.h"
#include "f7/spi_config.h"
#include "f7/qspi_config.h"
#include "f7/adc_config.h"
+#include "f7/adc_config_v2.h"
#include "f7/tim_config.h"
#include "f7/sdio_config.h"
#include "f7/pwm_config.h"
-#elif defined(SOC_SERIES_STM32L0)
+#elif defined(SOC_SERIES_STM32L0)
#include "l0/dma_config.h"
#include "l0/uart_config.h"
-#elif defined(SOC_SERIES_STM32L4)
+#include "l0/adc_config_v2.h"
+#elif defined(SOC_SERIES_STM32L4)
#include "l4/dma_config.h"
#include "l4/uart_config.h"
#include "l4/spi_config.h"
#include "l4/qspi_config.h"
#include "l4/adc_config.h"
+#include "l4/adc_config_v2.h"
#include "l4/dac_config.h"
#include "l4/tim_config.h"
#include "l4/sdio_config.h"
#include "l4/pwm_config.h"
#include "l4/usbd_config.h"
-#elif defined(SOC_SERIES_STM32L5)
+#elif defined(SOC_SERIES_STM32L5)
#include "l5/dma_config.h"
#include "l5/uart_config.h"
#include "l5/spi_config.h"
#include "l5/qspi_config.h"
#include "l5/adc_config.h"
+#include "l5/adc_config_v2.h"
#include "l5/dac_config.h"
#include "l5/tim_config.h"
#include "l5/sdio_config.h"
#include "l5/pwm_config.h"
#include "l5/usbd_config.h"
-#elif defined(SOC_SERIES_STM32G0)
+#elif defined(SOC_SERIES_STM32G0)
#include "g0/dma_config.h"
#include "g0/uart_config.h"
#include "g0/spi_config.h"
#include "g0/adc_config.h"
+#include "g0/adc_config_v2.h"
#include "g0/tim_config.h"
#include "g0/pwm_config.h"
#include "g0/usbd_config.h"
@@ -113,16 +123,18 @@ extern "C" {
#include "g4/qspi_config.h"
#include "g4/usbd_config.h"
#include "g4/adc_config.h"
+#include "g4/adc_config_v2.h"
#include "g4/tim_config.h"
#include "g4/sdio_config.h"
#include "g4/pwm_config.h"
#include "g4/pulse_encoder_config.h"
-#elif defined(SOC_SERIES_STM32H7)
+#elif defined(SOC_SERIES_STM32H7)
#include "h7/dma_config.h"
#include "h7/uart_config.h"
#include "h7/spi_config.h"
#include "h7/qspi_config.h"
#include "h7/adc_config.h"
+#include "h7/adc_config_v2.h"
#include "h7/dac_config.h"
#include "h7/tim_config.h"
#include "h7/lptim_config.h"
@@ -130,23 +142,23 @@ extern "C" {
#include "h7/pwm_config.h"
#include "h7/usbd_config.h"
#include "h7/i2c_hard_config.h"
-
-#elif defined(SOC_SERIES_STM32H7RS)
+#elif defined(SOC_SERIES_STM32H7RS)
#include "h7/dma_config.h"
#include "h7/uart_config.h"
#include "h7/spi_config.h"
#include "h7/adc_config.h"
+#include "h7rs/adc_config_v2.h"
#include "h7/dac_config.h"
#include "h7/tim_config.h"
#include "h7/pwm_config.h"
#include "h7/usbd_config.h"
-
#elif defined(SOC_SERIES_STM32U5)
#include "u5/dma_config.h"
#include "u5/uart_config.h"
#include "u5/spi_config.h"
#include "u5/qspi_config.h"
#include "u5/adc_config.h"
+#include "u5/adc_config_v2.h"
#include "u5/dac_config.h"
#include "u5/tim_config.h"
#include "u5/sdio_config.h"
@@ -156,22 +168,26 @@ extern "C" {
#include "h5/uart_config.h"
#include "h5/pwm_config.h"
#include "h5/adc_config.h"
-#elif defined(SOC_SERIES_STM32MP1)
+#include "h5/adc_config_v2.h"
+#elif defined(SOC_SERIES_STM32MP1)
#include "mp1/dma_config.h"
#include "mp1/uart_config.h"
#include "mp1/qspi_config.h"
#include "mp1/spi_config.h"
#include "mp1/adc_config.h"
+#include "mp1/adc_config_v2.h"
#include "mp1/dac_config.h"
#include "mp1/tim_config.h"
#include "mp1/pwm_config.h"
-#elif defined(SOC_SERIES_STM32WL)
+#elif defined(SOC_SERIES_STM32WL)
#include "wl/dma_config.h"
#include "wl/uart_config.h"
#include "wl/spi_config.h"
#include "wl/tim_config.h"
-#elif defined(SOC_SERIES_STM32WB)
+#include "wl/adc_config_v2.h"
+#elif defined(SOC_SERIES_STM32WB)
#include "wb/adc_config.h"
+#include "wb/adc_config_v2.h"
#include "wb/dma_config.h"
#include "wb/pwm_config.h"
#include "wb/qspi_config.h"
@@ -179,10 +195,10 @@ extern "C" {
#include "wb/tim_config.h"
#include "wb/uart_config.h"
#include "wb/usbd_config.h"
-#endif
+#endif /* defined(SOC_SERIES_STM32F0) */
#ifdef __cplusplus
}
-#endif
+#endif /* __cplusplus */
-#endif
+#endif /* __DRV_CONFIG_H__ */ \ No newline at end of file
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h
index c4feec05a8..83e1535e68 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h
@@ -265,6 +265,9 @@ struct stm32_dma_config
#define STM32_DMA_RX_WORD_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _channel, _request, _priority, _preempt_priority, _sub_priority) \
STM32_DMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_channel), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_PERIPH_TO_MEMORY, DMA_PINC_DISABLE, DMA_MINC_ENABLE, DMA_PDATAALIGN_WORD, DMA_MDATAALIGN_WORD, DMA_NORMAL)
+#define STM32_DMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _channel, _request, _priority, _preempt_priority, _sub_priority) \
+ STM32_DMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_channel), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_PERIPH_TO_MEMORY, DMA_PINC_DISABLE, DMA_MINC_ENABLE, DMA_PDATAALIGN_WORD, DMA_MDATAALIGN_WORD, DMA_CIRCULAR)
+
#define STM32_DMA_TX_WORD_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _channel, _request, _priority, _preempt_priority, _sub_priority) \
STM32_DMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_channel), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_MEMORY_TO_PERIPH, DMA_PINC_DISABLE, DMA_MINC_ENABLE, DMA_PDATAALIGN_WORD, DMA_MDATAALIGN_WORD, DMA_NORMAL)
@@ -305,6 +308,9 @@ struct stm32_dma_config
#define STM32_GPDMA_RX_WORD_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _request, _priority, _preempt_priority, _sub_priority) \
STM32_GPDMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_PERIPH_TO_MEMORY, DMA_SINC_FIXED, DMA_DINC_INCREMENTED, DMA_SRC_DATAWIDTH_WORD, DMA_DEST_DATAWIDTH_WORD, DMA_NORMAL)
+#define STM32_GPDMA_RX_WORD_CIRCULAR_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _request, _priority, _preempt_priority, _sub_priority) \
+ STM32_GPDMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_PERIPH_TO_MEMORY, DMA_SINC_FIXED, DMA_DINC_INCREMENTED, DMA_SRC_DATAWIDTH_WORD, DMA_DEST_DATAWIDTH_WORD, DMA_CIRCULAR)
+
#define STM32_GPDMA_TX_WORD_CONFIG_INIT_EX(_instance, _dma_rcc, _dma_irq, _request, _priority, _preempt_priority, _sub_priority) \
STM32_GPDMA_CONFIG_INIT_EX((_instance), (_dma_rcc), (_dma_irq), (_request), (_priority), (_preempt_priority), (_sub_priority), DMA_MEMORY_TO_PERIPH, DMA_SINC_INCREMENTED, DMA_DINC_FIXED, DMA_SRC_DATAWIDTH_WORD, DMA_DEST_DATAWIDTH_WORD, DMA_NORMAL)
diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c
index b236a7ffdd..a443bc1494 100644
--- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c
+++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_tim.c
@@ -116,6 +116,44 @@ void stm32_tim_pclkx_doubler_get(rt_uint32_t *pclk1_doubler, rt_uint32_t *pclk2_
#endif /* defined(SOC_SERIES_STM32MP1) */
}
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+/**
+ * @brief Get the effective input clock frequency of one STM32 timer.
+ * @param tim Pointer to the STM32 HAL timer handle.
+ * @param timer_clk Pointer to the output timer clock frequency in hertz.
+ * @return Operation status.
+ */
+static rt_err_t stm32_tim_clock_get(TIM_HandleTypeDef *tim, rt_uint32_t *timer_clk)
+{
+ rt_uint32_t pclk1_doubler;
+ rt_uint32_t pclk2_doubler;
+
+ stm32_tim_pclkx_doubler_get(&pclk1_doubler, &pclk2_doubler);
+
+#if defined(APBPERIPH_BASE)
+ *timer_clk = HAL_RCC_GetPCLK1Freq() * pclk1_doubler;
+#elif defined(APB1PERIPH_BASE) || defined(APB2PERIPH_BASE)
+ if ((rt_uint32_t)tim->Instance >= APB2PERIPH_BASE)
+ {
+ *timer_clk = HAL_RCC_GetPCLK2Freq() * pclk2_doubler;
+ }
+ else
+ {
+ *timer_clk = HAL_RCC_GetPCLK1Freq() * pclk1_doubler;
+ }
+#else
+#error "This driver has not supported this series yet!"
+#endif /* defined(APBPERIPH_BASE) */
+
+ if (*timer_clk == 0U)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+
void stm32_tim_enable_clock(TIM_HandleTypeDef* htim_base)
{
RT_ASSERT(htim_base != RT_NULL);
@@ -304,6 +342,10 @@ struct stm32_clock_timer
TIM_HandleTypeDef tim_handle;
IRQn_Type tim_irqn;
char *name;
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+ enum rt_clock_timer_trigger_event trigger_event; /**< Cached trigger output event. */
+ rt_uint16_t trigger_channel; /**< Cached compare channel, or 0 for update event. */
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
};
static struct stm32_clock_timer stm32_clock_timer_obj[] =
@@ -485,6 +527,448 @@ static void timer_stop(rt_clock_timer_t *timer)
__HAL_TIM_SET_COUNTER(tim, 0);
}
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+/**
+ * @brief Calculate STM32 timer divider values for hardware trigger output.
+ * @param timer Pointer to the RT-Thread clock timer device.
+ * @param freq_hz Target trigger frequency in hertz.
+ * @param prescaler Pointer to the output PSC register value.
+ * @param period Pointer to the output ARR register value.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_calc(rt_clock_timer_t *timer, rt_uint32_t freq_hz, rt_uint32_t *prescaler, rt_uint32_t *period)
+{
+ TIM_HandleTypeDef *tim;
+ rt_uint32_t timer_clk;
+ rt_uint32_t max_period;
+ rt_uint64_t cycles;
+ rt_uint64_t prescaler_div;
+ rt_uint64_t period_count;
+ rt_err_t result;
+
+ tim = (TIM_HandleTypeDef *)timer->parent.user_data;
+ result = stm32_tim_clock_get(tim, &timer_clk);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ if (freq_hz > timer_clk)
+ {
+ return -RT_EINVAL;
+ }
+
+ cycles = ((rt_uint64_t)timer_clk + (freq_hz / 2U)) / freq_hz;
+ if (cycles == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ max_period = ((timer->info != RT_NULL) && (timer->info->maxcnt != 0U)) ? timer->info->maxcnt : 0xffffU;
+ prescaler_div = (cycles + max_period - 1U) / max_period;
+ if ((prescaler_div == 0U) || (prescaler_div > 0x10000ULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ period_count = cycles / prescaler_div;
+ if (period_count == 0U)
+ {
+ period_count = 1U;
+ }
+ if (period_count > max_period)
+ {
+ period_count = max_period;
+ }
+
+ *prescaler = (rt_uint32_t)(prescaler_div - 1U);
+ *period = (rt_uint32_t)(period_count - 1U);
+
+ return RT_EOK;
+}
+
+
+/** @brief Maximum compare channel index encoded by the STM32 TIM trigger backend. */
+#define STM32_TIM_TRIGGER_COMPARE_CHANNEL_MAX 4U
+
+/**
+ * @brief STM32 HAL timer compare channel slot.
+ */
+struct stm32_tim_compare_channel
+{
+ rt_uint32_t channel; /**< HAL TIM channel selector. */
+ rt_uint32_t flag; /**< HAL TIM compare flag. */
+ rt_bool_t valid; /**< Whether channel and flag are valid. */
+};
+
+/**
+ * @brief HAL TIM compare channel table indexed by 1-based timer channel number.
+ */
+static const struct stm32_tim_compare_channel stm32_tim_compare_channel_table[STM32_TIM_TRIGGER_COMPARE_CHANNEL_MAX + 1U] = {
+#if defined(TIM_CHANNEL_1) && defined(TIM_FLAG_CC1)
+ [1] = { TIM_CHANNEL_1, TIM_FLAG_CC1, RT_TRUE },
+#endif /* defined(TIM_CHANNEL_1) && defined(TIM_FLAG_CC1) */
+#if defined(TIM_CHANNEL_2) && defined(TIM_FLAG_CC2)
+ [2] = { TIM_CHANNEL_2, TIM_FLAG_CC2, RT_TRUE },
+#endif /* defined(TIM_CHANNEL_2) && defined(TIM_FLAG_CC2) */
+#if defined(TIM_CHANNEL_3) && defined(TIM_FLAG_CC3)
+ [3] = { TIM_CHANNEL_3, TIM_FLAG_CC3, RT_TRUE },
+#endif /* defined(TIM_CHANNEL_3) && defined(TIM_FLAG_CC3) */
+#if defined(TIM_CHANNEL_4) && defined(TIM_FLAG_CC4)
+ [4] = { TIM_CHANNEL_4, TIM_FLAG_CC4, RT_TRUE },
+#endif /* defined(TIM_CHANNEL_4) && defined(TIM_FLAG_CC4) */
+};
+
+/**
+ * @brief Get a HAL compare channel slot from a 1-based timer channel number.
+ * @param channel 1-based timer compare channel number.
+ * @return Pointer to a valid channel slot, or RT_NULL when unsupported.
+ */
+static const struct stm32_tim_compare_channel *timer_trigger_compare_channel_get(rt_uint16_t channel)
+{
+ const struct stm32_tim_compare_channel *slot;
+
+ if (channel >= RT_ARRAY_SIZE(stm32_tim_compare_channel_table))
+ {
+ return RT_NULL;
+ }
+
+ slot = &stm32_tim_compare_channel_table[channel];
+ return (slot->valid == RT_TRUE) ? slot : RT_NULL;
+}
+
+/**
+ * @brief Fill the common STM32 timer base configuration for trigger output.
+ * @param tim Pointer to the STM32 HAL timer handle.
+ * @param prescaler PSC register value.
+ * @param period ARR register value.
+ */
+static void timer_trigger_base_fill(TIM_HandleTypeDef *tim, rt_uint32_t prescaler, rt_uint32_t period)
+{
+ tim->Init.Prescaler = prescaler;
+ tim->Init.Period = period;
+ tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ tim->Init.CounterMode = TIM_COUNTERMODE_UP;
+ tim->Init.RepetitionCounter = 0;
+#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB)
+ tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) */
+}
+
+/**
+ * @brief Configure one STM32 timer update event as a hardware trigger source.
+ * @param timer_device Pointer to the STM32 clock timer object.
+ * @param prescaler PSC register value.
+ * @param period ARR register value.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_update_config(struct stm32_clock_timer *timer_device, rt_uint32_t prescaler, rt_uint32_t period)
+{
+#if defined(TIM_TRGO_UPDATE)
+ TIM_HandleTypeDef *tim;
+ TIM_MasterConfigTypeDef master = {0};
+
+ tim = &timer_device->tim_handle;
+ HAL_TIM_Base_Stop(tim);
+ timer_trigger_base_fill(tim, prescaler, period);
+
+ if (HAL_TIM_Base_Init(tim) != HAL_OK)
+ {
+ LOG_E("TIM trigger base init failed");
+ return -RT_ERROR;
+ }
+
+ master.MasterOutputTrigger = TIM_TRGO_UPDATE;
+#if defined(TIM_MASTERSLAVEMODE_DISABLE)
+ master.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+#endif /* defined(TIM_MASTERSLAVEMODE_DISABLE) */
+ if (HAL_TIMEx_MasterConfigSynchronization(tim, &master) != HAL_OK)
+ {
+ LOG_E("TIM trigger master config failed");
+ return -RT_ERROR;
+ }
+
+ timer_device->trigger_event = CLOCK_TIMER_TRIGGER_EVENT_UPDATE;
+ timer_device->trigger_channel = 0U;
+ tim->Instance->CR1 &= (~TIM_OPMODE_SINGLE);
+ __HAL_TIM_SET_COUNTER(tim, 0);
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+
+ return RT_EOK;
+#else
+ RT_UNUSED(timer_device);
+ RT_UNUSED(prescaler);
+ RT_UNUSED(period);
+ return -RT_ENOSYS;
+#endif /* defined(TIM_TRGO_UPDATE) */
+}
+
+
+/**
+ * @brief Configure one STM32 timer compare event as a hardware trigger source.
+ * @param timer_device Pointer to the STM32 clock timer object.
+ * @param cfg Pointer to the hardware trigger configuration.
+ * @param prescaler PSC register value.
+ * @param period ARR register value.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_compare_config(struct stm32_clock_timer *timer_device,
+ const struct rt_clock_timer_trigger_cfg *cfg,
+ rt_uint32_t prescaler, rt_uint32_t period)
+{
+#if defined(TIM_OCMODE_TIMING)
+ const struct stm32_tim_compare_channel *slot;
+ TIM_HandleTypeDef *tim;
+ TIM_OC_InitTypeDef oc = {0};
+ rt_uint32_t pulse;
+
+ slot = timer_trigger_compare_channel_get(cfg->channel);
+ if (slot == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ tim = &timer_device->tim_handle;
+ HAL_TIM_OC_Stop(tim, slot->channel);
+ HAL_TIM_Base_Stop(tim);
+ timer_trigger_base_fill(tim, prescaler, period);
+
+ if (HAL_TIM_Base_Init(tim) != HAL_OK)
+ {
+ LOG_E("TIM trigger compare base init failed");
+ return -RT_ERROR;
+ }
+ if (HAL_TIM_OC_Init(tim) != HAL_OK)
+ {
+ LOG_E("TIM trigger compare init failed");
+ return -RT_ERROR;
+ }
+
+ pulse = (period + 1U) / 2U;
+ if (pulse > period)
+ {
+ pulse = period;
+ }
+
+ oc.OCMode = TIM_OCMODE_PWM2;
+ oc.Pulse = pulse;
+#if defined(TIM_OCPOLARITY_HIGH)
+ oc.OCPolarity = TIM_OCPOLARITY_HIGH;
+#endif /* defined(TIM_OCPOLARITY_HIGH) */
+#if defined(TIM_OCNPOLARITY_HIGH)
+ oc.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+#endif /* defined(TIM_OCNPOLARITY_HIGH) */
+#if defined(TIM_OCFAST_DISABLE)
+ oc.OCFastMode = TIM_OCFAST_DISABLE;
+#endif /* defined(TIM_OCFAST_DISABLE) */
+#if defined(TIM_OCIDLESTATE_RESET)
+ oc.OCIdleState = TIM_OCIDLESTATE_RESET;
+#endif /* defined(TIM_OCIDLESTATE_RESET) */
+#if defined(TIM_OCNIDLESTATE_RESET)
+ oc.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+#endif /* defined(TIM_OCNIDLESTATE_RESET) */
+
+ if (HAL_TIM_OC_ConfigChannel(tim, &oc, slot->channel) != HAL_OK)
+ {
+ LOG_E("TIM trigger compare channel config failed");
+ return -RT_ERROR;
+ }
+
+ timer_device->trigger_event = CLOCK_TIMER_TRIGGER_EVENT_COMPARE;
+ timer_device->trigger_channel = cfg->channel;
+ tim->Instance->CR1 &= (~TIM_OPMODE_SINGLE);
+ __HAL_TIM_SET_COUNTER(tim, 0);
+ __HAL_TIM_CLEAR_FLAG(tim, slot->flag);
+
+ return RT_EOK;
+#else
+ RT_UNUSED(timer_device);
+ RT_UNUSED(cfg);
+ RT_UNUSED(prescaler);
+ RT_UNUSED(period);
+ return -RT_ENOSYS;
+#endif /* defined(TIM_OCMODE_TIMING) */
+}
+
+/**
+ * @brief Configure one STM32 timer as a hardware trigger source.
+ * @param timer Pointer to the RT-Thread clock timer device.
+ * @param cfg Pointer to the hardware trigger configuration.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_config(rt_clock_timer_t *timer, const struct rt_clock_timer_trigger_cfg *cfg)
+{
+ struct stm32_clock_timer *timer_device;
+ rt_uint32_t prescaler;
+ rt_uint32_t period;
+ rt_err_t result;
+
+ if (cfg->freq_hz == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((cfg->event != CLOCK_TIMER_TRIGGER_EVENT_UPDATE) &&
+ (cfg->event != CLOCK_TIMER_TRIGGER_EVENT_COMPARE))
+ {
+ return -RT_EINVAL;
+ }
+
+ timer_device = (struct stm32_clock_timer *)timer;
+ if (timer_device->time_device.parent.user_data == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = timer_trigger_calc(timer, cfg->freq_hz, &prescaler, &period);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ stm32_tim_enable_clock(&timer_device->tim_handle);
+
+ switch (cfg->event)
+ {
+ case CLOCK_TIMER_TRIGGER_EVENT_UPDATE:
+ return timer_trigger_update_config(timer_device, prescaler, period);
+
+ case CLOCK_TIMER_TRIGGER_EVENT_COMPARE:
+ return timer_trigger_compare_config(timer_device, cfg, prescaler, period);
+
+ default:
+ return -RT_EINVAL;
+ }
+}
+
+/**
+ * @brief Start hardware trigger output on one STM32 timer.
+ * @param timer Pointer to the RT-Thread clock timer device.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_start(rt_clock_timer_t *timer)
+{
+ struct stm32_clock_timer *timer_device;
+ const struct stm32_tim_compare_channel *slot;
+ TIM_HandleTypeDef *tim;
+
+ timer_device = (struct stm32_clock_timer *)timer;
+ if (timer_device->time_device.parent.user_data == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ tim = &timer_device->tim_handle;
+ tim->Instance->CR1 &= (~TIM_OPMODE_SINGLE);
+ __HAL_TIM_SET_COUNTER(tim, 0);
+
+ if (timer_device->trigger_event == CLOCK_TIMER_TRIGGER_EVENT_COMPARE)
+ {
+ slot = timer_trigger_compare_channel_get(timer_device->trigger_channel);
+ if (slot == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ __HAL_TIM_CLEAR_FLAG(tim, slot->flag);
+ return (HAL_TIM_OC_Start(tim, slot->channel) == HAL_OK) ? RT_EOK : -RT_ERROR;
+ }
+
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+ return (HAL_TIM_Base_Start(tim) == HAL_OK) ? RT_EOK : -RT_ERROR;
+}
+
+/**
+ * @brief Stop hardware trigger output on one STM32 timer.
+ * @param timer Pointer to the RT-Thread clock timer device.
+ * @return Operation status.
+ */
+static rt_err_t timer_trigger_stop(rt_clock_timer_t *timer)
+{
+ struct stm32_clock_timer *timer_device;
+ const struct stm32_tim_compare_channel *slot;
+ TIM_HandleTypeDef *tim;
+ rt_err_t result;
+
+ timer_device = (struct stm32_clock_timer *)timer;
+ if (timer_device->time_device.parent.user_data == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ tim = &timer_device->tim_handle;
+
+ if (timer_device->trigger_event == CLOCK_TIMER_TRIGGER_EVENT_COMPARE)
+ {
+ slot = timer_trigger_compare_channel_get(timer_device->trigger_channel);
+ if (slot == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+ result = (HAL_TIM_OC_Stop(tim, slot->channel) == HAL_OK) ? RT_EOK : -RT_ERROR;
+ __HAL_TIM_CLEAR_FLAG(tim, slot->flag);
+ }
+ else
+ {
+ result = (HAL_TIM_Base_Stop(tim) == HAL_OK) ? RT_EOK : -RT_ERROR;
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+ }
+
+ __HAL_TIM_SET_COUNTER(tim, 0);
+ return result;
+}
+
+/**
+ * @brief Release and deinitialize hardware trigger output on one STM32 timer.
+ * @param timer Pointer to the RT-Thread clock timer device.
+ * @return Operation status.
+ * @note Timer trigger sources are dedicated to trigger output. Releasing a
+ * trigger source stops the timer, clears the trigger output when the HAL
+ * exposes a reset selector, and deinitializes the HAL TIM base state. It
+ * does not unregister the RT-Thread timer device object.
+ */
+static rt_err_t timer_trigger_release(rt_clock_timer_t *timer)
+{
+ struct stm32_clock_timer *timer_device;
+ TIM_HandleTypeDef *tim;
+ rt_err_t result = RT_EOK;
+
+ timer_device = (struct stm32_clock_timer *)timer;
+ if (timer_device->time_device.parent.user_data == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ tim = &timer_device->tim_handle;
+
+ if (timer_trigger_stop(timer) != RT_EOK)
+ {
+ result = -RT_ERROR;
+ }
+
+#if defined(TIM_TRGO_RESET)
+ TIM_MasterConfigTypeDef master = {0};
+ master.MasterOutputTrigger = TIM_TRGO_RESET;
+#if defined(TIM_MASTERSLAVEMODE_DISABLE)
+ master.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+#endif /* defined(TIM_MASTERSLAVEMODE_DISABLE) */
+ if (HAL_TIMEx_MasterConfigSynchronization(tim, &master) != HAL_OK)
+ {
+ result = -RT_ERROR;
+ }
+#endif /* defined(TIM_TRGO_RESET) */
+
+ if (HAL_TIM_Base_DeInit(tim) != HAL_OK)
+ {
+ result = -RT_ERROR;
+ }
+
+ timer_device->trigger_event = CLOCK_TIMER_TRIGGER_EVENT_UPDATE;
+ timer_device->trigger_channel = 0U;
+ return result;
+}
+
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+
static rt_err_t timer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg)
{
TIM_HandleTypeDef *tim = RT_NULL;
@@ -492,7 +976,6 @@ static rt_err_t timer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg)
uint32_t pclk1_doubler, pclk2_doubler;
RT_ASSERT(timer != RT_NULL);
- RT_ASSERT(arg != RT_NULL);
tim = (TIM_HandleTypeDef *)timer->parent.user_data;
@@ -503,6 +986,12 @@ static rt_err_t timer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg)
rt_uint32_t freq;
rt_uint16_t val=0;
+ if (arg == RT_NULL)
+ {
+ result = -RT_EINVAL;
+ break;
+ }
+
/* set timer frequence */
freq = *((rt_uint32_t *)arg);
@@ -581,6 +1070,33 @@ static rt_err_t timer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg)
result = RT_EOK;
}
break;
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+ case CLOCK_TIMER_CTRL_TRIGGER_CONFIG:
+ {
+ if (arg == RT_NULL)
+ {
+ result = -RT_EINVAL;
+ break;
+ }
+ result = timer_trigger_config(timer, (const struct rt_clock_timer_trigger_cfg *)arg);
+ }
+ break;
+ case CLOCK_TIMER_CTRL_TRIGGER_START:
+ {
+ result = timer_trigger_start(timer);
+ }
+ break;
+ case CLOCK_TIMER_CTRL_TRIGGER_STOP:
+ {
+ result = timer_trigger_stop(timer);
+ }
+ break;
+ case CLOCK_TIMER_CTRL_TRIGGER_RELEASE:
+ {
+ result = timer_trigger_release(timer);
+ }
+ break;
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
default:
{
result = -RT_EINVAL;
diff --git a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml
index 6b62ab697a..a823a64aeb 100644
--- a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml
+++ b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml
@@ -155,6 +155,22 @@ online-packages.ai.llmchat:
- CONFIG_PKG_USING_LLMCHAT=y
- CONFIG_PKG_USING_LLMCHAT_LATEST_VERSION=y
# ------ peripheral CI ------
+peripheral.adc_v2:
+ kconfig:
+ - CONFIG_RT_USING_ADC_V2=y
+ - CONFIG_BSP_USING_ADC_V2=y
+ - CONFIG_BSP_USING_ADC1=y
+ - CONFIG_RT_ADC_V2_USING_MSH=y
+ - CONFIG_RT_ADC_USING_STREAM=y
+ - CONFIG_RT_ADC_STREAM_USING_LATEST=y
+ - CONFIG_RT_ADC_STREAM_USING_FIFO=y
+ - CONFIG_BSP_ADC1_USING_DMA=y
+ - CONFIG_BSP_ADC_USING_TRIGGER=y
+ - CONFIG_BSP_ADC_USING_TIMER_TRIGGER=y
+ - CONFIG_BSP_ADC_USING_ANALOG_COMPARE_TRIGGER=y
+ - CONFIG_RT_USING_CLOCK_TIME=y
+ - CONFIG_BSP_USING_TIM=y
+ - CONFIG_BSP_USING_TIM11=y
peripheral.aht21:
kconfig:
- CONFIG_BSP_USING_AHT21=y
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index db0334f42b..7ceb0720b4 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -5,6 +5,7 @@ rsource "ipc/Kconfig"
rsource "serial/Kconfig"
rsource "can/Kconfig"
+rsource "adc/Kconfig"
rsource "clock_time/Kconfig"
rsource "i2c/Kconfig"
rsource "phy/Kconfig"
diff --git a/components/drivers/adc/Kconfig b/components/drivers/adc/Kconfig
new file mode 100644
index 0000000000..28d9ec47a0
--- /dev/null
+++ b/components/drivers/adc/Kconfig
@@ -0,0 +1,121 @@
+menuconfig RT_USING_ADC
+ bool "Using ADC device drivers"
+ default n
+
+if RT_USING_ADC
+ config RT_USING_ADC_V2
+ bool "Using ADC V2 device drivers"
+ default n
+ help
+ Enable the standalone ADC V2 framework. ADC V2 uses the legacy ADC
+ public namespace, so it cannot be enabled together with ADC V1.
+
+ config RT_USING_ADC_V1
+ bool
+ default y if !RT_USING_ADC_V2
+
+if RT_USING_DM && RT_USING_ADC_V1
+ osource "$(SOC_DM_ADC_DIR)/Kconfig"
+endif
+
+if RT_USING_ADC_V2
+
+
+config RT_ADC_USING_TRIGGER
+ bool "Enable ADC trigger framework"
+ default n
+ help
+ Enable device-level ADC trigger requests, framework validation, caching,
+ and stream lifecycle coordination. Timer trigger frequency and TRGO
+ start/stop are delegated to the timer trigger backend.
+
+config RT_ADC_TRIGGER_USING_TIMER
+ bool "Enable ADC timer trigger selector support"
+ depends on RT_ADC_USING_TRIGGER
+ default n
+ help
+ Enable timer update/TRGO and timer compare events as ADC stream
+ trigger sources.
+
+config RT_ADC_TRIGGER_USING_COMPARE
+ bool "Enable ADC analog comparator trigger selector support"
+ depends on RT_ADC_USING_TRIGGER
+ default n
+ help
+ Enable analog comparator output events as ADC stream trigger sources.
+
+
+config RT_ADC_USING_STREAM
+ bool "Enable ADC stream framework"
+ default n
+ help
+ Enable long-running ADC stream sessions.
+
+ Disable this option to remove ADC stream runtime state, stream APIs,
+ and stream backend hooks from the ADC V2 framework.
+
+if RT_ADC_USING_STREAM
+
+menu "ADC stream buffering policies"
+
+config RT_ADC_STREAM_USING_LATEST
+ bool "Enable ADC stream latest-frame policy"
+ default y
+ help
+ Enable the latest-frame ADC stream policy.
+
+ This mode is intended for slow-changing or status-like ADC values, such
+ as battery voltage, temperature, potentiometer input, resistor-divider
+ voltage, or board health monitoring.
+
+ The DMA buffer stores exactly one complete ADC scan frame. Old values
+ may be overwritten. This mode does not require DMA half-transfer or
+ transfer-complete data interrupts, and it does not allocate a framework
+ FIFO.
+
+ This option may be enabled together with RT_ADC_STREAM_USING_FIFO. The
+ active policy is selected per stream at runtime.
+
+config RT_ADC_STREAM_USING_FIFO
+ bool "Enable ADC stream FIFO policy"
+ default n
+ help
+ Enable the FIFO ADC stream policy.
+
+ This mode is intended for continuous and loss-sensitive sampling. The
+ DMA buffer is used as a staging buffer, and completed DMA data events
+ are copied into a ringbuffer for ordered blocking reads.
+
+ FIFO mode requires DMA data events. The default DMA event mode uses both
+ half-transfer and transfer-complete events to reduce read latency. A
+ stream configuration may select full-only events to reduce interrupt
+ frequency, at the cost of higher latency and larger data bursts.
+
+ This option may be enabled together with RT_ADC_STREAM_USING_LATEST. The
+ active policy is selected per stream at runtime.
+
+comment "At least one ADC stream buffering policy should be enabled"
+ depends on !RT_ADC_STREAM_USING_LATEST && !RT_ADC_STREAM_USING_FIFO
+
+endmenu
+
+endif
+
+config RT_ADC_V2_USING_MSH
+ bool "Enable ADC V2 MSH command"
+ depends on RT_USING_FINSH
+ default y
+ help
+ Enable the ADC V2 MSH command.
+
+ This option exports the "adc" shell command for probing ADC devices,
+ configuring channels, reading raw samples, reading voltage values, and
+ reading one ADC sequence. When RT_ADC_USING_STREAM is enabled, stream
+ subcommands are also available.
+
+ Disable this option to remove the ADC V2 shell command while keeping
+ the ADC V2 framework and driver APIs available.
+
+endif
+
+endif
diff --git a/components/drivers/adc/SConscript b/components/drivers/adc/SConscript
new file mode 100644
index 0000000000..94101138f0
--- /dev/null
+++ b/components/drivers/adc/SConscript
@@ -0,0 +1,23 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = []
+CPPPATH = [cwd + '/../include']
+group = []
+
+if GetDepend(['RT_USING_ADC']) and not GetDepend(['RT_USING_ADC_V2']):
+ src += ['adc.c']
+
+if GetDepend(['RT_USING_ADC_V2']):
+ src += ['adc_v2.c']
+
+if GetDepend(['RT_USING_ADC_V2', 'RT_ADC_USING_TRIGGER']):
+ src += ['adc_v2_trigger.c']
+
+if GetDepend(['RT_USING_ADC_V2', 'RT_USING_FINSH', 'RT_ADC_V2_USING_MSH']):
+ src += ['adc_v2_msh.c']
+
+if len(src):
+ group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_ADC'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/misc/adc.c b/components/drivers/adc/adc.c
index 056c1f6c30..056c1f6c30 100644
--- a/components/drivers/misc/adc.c
+++ b/components/drivers/adc/adc.c
diff --git a/components/drivers/adc/adc_v2.c b/components/drivers/adc/adc_v2.c
new file mode 100644
index 0000000000..9ec3b6ac11
--- /dev/null
+++ b/components/drivers/adc/adc_v2.c
@@ -0,0 +1,1779 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add standalone adc v2 framework implementation
+ */
+
+/**
+ * @file adc_v2.c
+ * @brief Standalone ADC V2 framework implementation.
+ */
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2)
+
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#define DBG_TAG "adc.v2"
+#define DBG_LVL DBG_LOG
+#include <rtdbg.h>
+
+#include <drivers/adc_v2.h>
+#include "adc_v2_internal.h"
+
+/**
+ * @brief Get the current ADC framework state atomically.
+ * @param device Pointer to the ADC device object.
+ * @return Current ADC runtime state.
+ */
+enum rt_adc_state adc_get_state(rt_adc_device_t device)
+{
+ return (enum rt_adc_state)rt_atomic_load(&device->state);
+}
+
+#if DBG_LVL >= DBG_LOG
+/**
+ * @brief Convert one ADC framework state to a debug log string.
+ * @param state ADC runtime state.
+ * @return Constant state name string.
+ */
+static const char *adc_state_name(enum rt_adc_state state)
+{
+ switch (state)
+ {
+ case RT_ADC_STATE_IDLE:
+ return "IDLE";
+
+ case RT_ADC_STATE_LOCKED:
+ return "BUSY";
+
+#ifdef RT_ADC_USING_STREAM
+ case RT_ADC_STATE_STREAM:
+ return "STREAM";
+#endif /* RT_ADC_USING_STREAM */
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/** @brief ADC control command string table offset base. */
+#define RT_ADC_CMD_NAME_BASE RT_ADC_CMD_GET_RESOLUTION
+
+/** @brief ADC control command string table entry count. */
+#define RT_ADC_CMD_NAME_COUNT (RT_ADC_CMD_CLEAR_CHANNEL_CONFIG - RT_ADC_CMD_GET_RESOLUTION + 1)
+
+/**
+ * @brief ADC control command name table.
+ */
+static const char * const rt_adc_control_cmd_names[RT_ADC_CMD_NAME_COUNT] =
+{
+ [RT_ADC_CMD_GET_RESOLUTION - RT_ADC_CMD_NAME_BASE] = "GET_RESOLUTION",
+ [RT_ADC_CMD_CALIBRATE - RT_ADC_CMD_NAME_BASE] = "CALIBRATE",
+ [RT_ADC_CMD_SET_VREF - RT_ADC_CMD_NAME_BASE] = "SET_VREF",
+ [RT_ADC_CMD_CALC_VREF - RT_ADC_CMD_NAME_BASE] = "CALC_VREF",
+ [RT_ADC_CMD_GET_VREF_CHANNEL - RT_ADC_CMD_NAME_BASE] = "GET_VREF_CHANNEL",
+ [RT_ADC_CMD_SET_SESSION - RT_ADC_CMD_NAME_BASE] = "SET_SESSION",
+ [RT_ADC_CMD_SET_CONFIG - RT_ADC_CMD_NAME_BASE] = "SET_CONFIG",
+ [RT_ADC_CMD_GET_CONFIG - RT_ADC_CMD_NAME_BASE] = "GET_CONFIG",
+ [RT_ADC_CMD_CLEAR_CHANNEL_CONFIG - RT_ADC_CMD_NAME_BASE] = "CLEAR_CHANNEL_CONFIG",
+};
+
+/**
+ * @brief Get ADC control command name.
+ * @param cmd ADC control command identifier.
+ * @return ADC control command name string.
+ */
+static const char *rt_adc_control_cmd_name(int cmd)
+{
+ int index;
+
+ index = cmd - RT_ADC_CMD_NAME_BASE;
+ if ((index < 0) || (index >= RT_ADC_CMD_NAME_COUNT) || (rt_adc_control_cmd_names[index] == RT_NULL))
+ {
+ return "UNKNOWN";
+ }
+
+ return rt_adc_control_cmd_names[index];
+}
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief Convert one ADC stream policy to a debug log string.
+ * @param policy ADC stream buffering policy.
+ * @return Constant stream policy name string.
+ */
+static const char *adc_stream_policy_name(enum rt_adc_stream_policy policy)
+{
+ switch (policy)
+ {
+#ifdef RT_ADC_STREAM_USING_LATEST
+ case RT_ADC_STREAM_POLICY_LATEST:
+ return "LATEST";
+#endif /* RT_ADC_STREAM_USING_LATEST */
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+ case RT_ADC_STREAM_POLICY_FIFO:
+ return "FIFO";
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ default:
+ return "UNKNOWN";
+ }
+}
+#endif /* RT_ADC_USING_STREAM */
+
+#endif /* DBG_LVL >= DBG_LOG */
+
+/**
+ * @brief Store one ADC framework state atomically.
+ * @param device Pointer to the ADC device object.
+ * @param state New ADC runtime state.
+ */
+static void adc_set_state(rt_adc_device_t device, enum rt_adc_state state)
+{
+ LOG_D("state set: device=%s state=%s", device->parent.parent.name, adc_state_name(state));
+ rt_atomic_store(&device->state, (rt_atomic_t)state);
+}
+
+/**
+ * @brief Clear the cached active ADC session configuration.
+ * @param device Pointer to the ADC device object.
+ */
+static void adc_clear_session_ctrl(rt_adc_device_t device)
+{
+ rt_memset(&device->session_ctrl, 0, sizeof(device->session_ctrl));
+}
+
+/**
+ * @brief Cache one ADC session while the caller owns the device BUSY state.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t adc_cache_session_ctrl(rt_adc_device_t device, rt_uint32_t channels)
+{
+ rt_size_t channel_count;
+
+ if ((device == RT_NULL) || (channels == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ channel_count = rt_adc_channel_mask_count(channels);
+ if (channel_count == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ device->session_ctrl.channels = channels;
+ device->session_ctrl.channel_count = channel_count;
+ device->session_ctrl.configured = RT_TRUE;
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Try to change the ADC framework state atomically.
+ * @param device Pointer to the ADC device object.
+ * @param expected Expected current ADC runtime state.
+ * @param target Target ADC runtime state.
+ * @return RT_TRUE if the state transition succeeded.
+ */
+static rt_bool_t adc_try_set_state(rt_adc_device_t device, enum rt_adc_state expected, enum rt_adc_state target)
+{
+ rt_atomic_t old_state;
+ rt_bool_t matched;
+
+ old_state = (rt_atomic_t)expected;
+ matched = (rt_atomic_compare_exchange_strong(&device->state, &old_state, (rt_atomic_t)target) != 0) ? RT_TRUE : RT_FALSE;
+ if (matched == RT_TRUE)
+ {
+ LOG_D("state transition: device=%s %s -> %s", device->parent.parent.name, adc_state_name(expected), adc_state_name(target));
+ }
+ else
+ {
+ LOG_W("state transition rejected: device=%s expected=%d actual=%d target=%d", device->parent.parent.name, (int)expected, (int)old_state, (int)target);
+ }
+
+ return matched;
+}
+
+/**
+ * @brief Apply one ADC conversion session to the backend driver.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+static rt_err_t adc_session_config(rt_adc_device_t device, rt_uint32_t channels)
+{
+ rt_size_t channel_count;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (channels == 0U) ||
+ (device->ops == RT_NULL) || (device->ops->core == RT_NULL) ||
+ (device->ops->core->session_config == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ channel_count = rt_adc_channel_mask_count(channels);
+ LOG_D("session config: device=%s channels=0x%08x count=%d",
+ device->parent.parent.name, channels, channel_count);
+
+ result = device->ops->core->session_config(device, channels);
+ if (result != RT_EOK)
+ {
+ goto fail;
+ }
+
+ result = adc_cache_session_ctrl(device, channels);
+ if (result != RT_EOK)
+ {
+ goto fail;
+ }
+
+ LOG_D("session configure done: device=%s", device->parent.parent.name);
+ return RT_EOK;
+
+fail:
+ adc_clear_session_ctrl(device);
+ LOG_E("session configure failed: device=%s result=%d", device->parent.parent.name, result);
+
+ return result;
+}
+
+/**
+ * @brief Get the raw sample index of one channel in a configured session.
+ * @param session_channels Configured ADC session channel mask.
+ * @param channel Single-channel mask to locate.
+ * @param index Pointer to the output raw sample index.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_session_channel_index(rt_uint32_t session_channels, rt_uint32_t channel, rt_size_t *index)
+{
+ if ((index == RT_NULL) || (session_channels == 0U) || (rt_adc_channel_mask_count(channel) != 1U) || ((session_channels & channel) == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ *index = rt_adc_channel_mask_count(session_channels & (channel - 1U));
+ return RT_EOK;
+}
+
+/**
+ * @brief Transfer ADC sequence samples after the session has been selected.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the sequence request object.
+ * @param sample_total Number of samples to read.
+ * @param read_count Pointer to the stored sample count.
+ * @return Operation status.
+ */
+static rt_err_t adc_sequence_transfer_locked(rt_adc_device_t device, rt_uint32_t channels,
+ const struct rt_adc_sequence_cfg *cfg, rt_size_t sample_total, rt_size_t *read_count)
+{
+ rt_err_t result;
+ rt_err_t stop_result;
+ rt_size_t index;
+
+ *read_count = 0U;
+ result = device->ops->sequence->start(device, channels, cfg);
+ if (result != RT_EOK)
+ {
+ LOG_E("sequence start failed: device=%s result=%d", device->parent.parent.name, result);
+ return result;
+ }
+
+ for (index = 0U; index < sample_total; index++)
+ {
+ result = device->ops->sequence->read(device, &cfg->buffer[index], cfg->timeout_ms);
+ if (result != RT_EOK)
+ {
+ LOG_E("sequence read failed: device=%s index=%u result=%d",
+ device->parent.parent.name, (unsigned int)index, result);
+ break;
+ }
+
+ (*read_count)++;
+ }
+
+ stop_result = device->ops->sequence->stop(device);
+ if (stop_result != RT_EOK)
+ {
+ LOG_E("sequence stop failed: device=%s result=%d", device->parent.parent.name, stop_result);
+ return (result != RT_EOK) ? result : stop_result;
+ }
+
+ return result;
+}
+
+/**
+ * @brief Open the ADC device.
+ * @param dev Pointer to the RT-Thread device object.
+ * @param oflag Open flags.
+ * @return Operation status.
+ */
+static rt_err_t adc_open_device(rt_device_t dev, rt_uint16_t oflag)
+{
+ rt_adc_device_t device;
+ rt_err_t result;
+
+ RT_UNUSED(oflag);
+
+ if (dev == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ device = (rt_adc_device_t)dev;
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) ||
+ (device->ops->core->open == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ LOG_D("open start: device=%s", device->parent.parent.name);
+ result = device->ops->core->open(device);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ if (result == RT_EOK)
+ {
+ LOG_I("open done: device=%s", device->parent.parent.name);
+ }
+ else
+ {
+ LOG_E("open failed: device=%s result=%d", device->parent.parent.name, result);
+ }
+ return result;
+}
+
+/**
+ * @brief Close the ADC device.
+ * @param dev Pointer to the RT-Thread device object.
+ * @return Operation status.
+ */
+static rt_err_t adc_close_device(rt_device_t dev)
+{
+ rt_adc_device_t device;
+ rt_err_t result;
+
+ if (dev == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ device = (rt_adc_device_t)dev;
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) || (device->ops->core->close == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+#ifdef RT_ADC_USING_STREAM
+ enum rt_adc_state state = adc_get_state(device);
+ if (state == RT_ADC_STATE_STREAM)
+ {
+ result = rt_adc_stream_stop(device);
+ if (result != RT_EOK)
+ {
+ LOG_E("stop stream before close failed: device=%s result=%d", device->parent.parent.name, result);
+ return result;
+ }
+ }
+ else if (state != RT_ADC_STATE_IDLE)
+ {
+ return -RT_EBUSY;
+ }
+#endif /* RT_ADC_USING_STREAM */
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ LOG_D("close start: device=%s", device->parent.parent.name);
+ result = device->ops->core->close(device);
+ if (result == RT_EOK)
+ {
+ adc_clear_session_ctrl(device);
+ }
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ if (result == RT_EOK)
+ {
+ LOG_I("close done: device=%s", device->parent.parent.name);
+ }
+ else
+ {
+ LOG_E("close failed: device=%s result=%d", device->parent.parent.name, result);
+ }
+ return result;
+}
+
+/**
+ * @brief Read ADC raw samples from the configured session.
+ * @param dev Pointer to the RT-Thread device object.
+ * @param pos Unused read position.
+ * @param buffer Pointer to the output sample buffer.
+ * @param size Output sample buffer length in samples.
+ * @return Number of samples read, or negative error code on failure.
+ *
+ * @note @p size must match the configured session channel count. The output
+ * order follows the ascending bit order of the configured channel mask.
+ */
+static rt_ssize_t adc_read_device(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+ rt_adc_device_t device;
+ rt_uint32_t *values;
+ rt_err_t result;
+
+ RT_UNUSED(pos);
+
+ if ((dev == RT_NULL) || (buffer == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ device = (rt_adc_device_t)dev;
+ values = (rt_uint32_t *)buffer;
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ if ((device->session_ctrl.configured != RT_TRUE) || (device->session_ctrl.channel_count == 0U) ||
+ (size != device->session_ctrl.channel_count))
+ {
+ result = -RT_EINVAL;
+ goto out;
+ }
+
+ struct rt_adc_sequence_cfg sequence_cfg;
+ rt_size_t read_count;
+
+ rt_memset(&sequence_cfg, 0, sizeof(sequence_cfg));
+ sequence_cfg.buffer = values;
+ sequence_cfg.buffer_length = size;
+ sequence_cfg.timeout_ms = -1;
+
+ result = adc_sequence_transfer_locked(device, device->session_ctrl.channels,
+ &sequence_cfg, size, &read_count);
+ if ((result == RT_EOK) && (read_count != size))
+ {
+ result = -RT_ERROR;
+ }
+
+out:
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+
+ return (result == RT_EOK) ? (rt_ssize_t)size : (rt_ssize_t)result;
+}
+
+/**
+ * @brief Handle ADC control commands.
+ * @param dev Pointer to the RT-Thread device object.
+ * @param cmd Control command.
+ * @param args Pointer to the control argument buffer.
+ * @return Operation status.
+ */
+static rt_err_t adc_control_device(rt_device_t dev, int cmd, void *args)
+{
+ rt_adc_device_t device;
+ rt_err_t result;
+
+ if (dev == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ device = (rt_adc_device_t)dev;
+ LOG_D("control request: device=%s cmd=%s(0x%x)", device->parent.parent.name, rt_adc_control_cmd_name(cmd), cmd);
+ switch (cmd)
+ {
+ case RT_ADC_CMD_GET_RESOLUTION:
+ case RT_ADC_CMD_GET_VREF_CHANNEL:
+ case RT_ADC_CMD_CALC_VREF:
+ case RT_ADC_CMD_CALIBRATE:
+ case RT_ADC_CMD_SET_CONFIG:
+ case RT_ADC_CMD_GET_CONFIG:
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) ||
+ (device->ops->core->control == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+ result = device->ops->core->control(device, cmd, args);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+
+ case RT_ADC_CMD_CLEAR_CHANNEL_CONFIG:
+ if (args != RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((dev->open_flag & RT_DEVICE_OFLAG_OPEN) == 0U)
+ {
+ return -RT_EIO;
+ }
+
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) ||
+ (device->ops->core->control == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ result = device->ops->core->control(device, cmd, RT_NULL);
+ if (result == RT_EOK)
+ {
+ adc_clear_session_ctrl(device);
+ }
+
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+
+ case RT_ADC_CMD_SET_VREF:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_uint32_t vref_mv = *((rt_uint32_t *)args);
+ if (vref_mv == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+ device->default_vref_mv = vref_mv;
+ LOG_I("fallback vref updated: %lu mV", (unsigned long)device->default_vref_mv);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return RT_EOK;
+
+ case RT_ADC_CMD_SET_SESSION:
+ if (args == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+ result = adc_session_config(device, *((const rt_uint32_t *)args));
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+
+ default:
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) ||
+ (device->ops->core->control == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+ result = device->ops->core->control(device, cmd, args);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+ }
+}
+
+#ifdef RT_USING_DEVICE_OPS
+/**
+ * @brief ADC device-framework operation table.
+ */
+static const struct rt_device_ops adc_device_ops = {
+ RT_NULL,
+ adc_open_device,
+ adc_close_device,
+ adc_read_device,
+ RT_NULL,
+ adc_control_device,
+};
+#endif /* RT_USING_DEVICE_OPS */
+
+/**
+ * @brief Register an ADC device.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the device name string.
+ * @param ops Pointer to the ADC driver operation table.
+ * @param user_data Pointer to the driver private data.
+ * @return Operation status.
+ */
+rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data)
+{
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL) ||
+ (ops->core == RT_NULL) || (ops->core->session_config == RT_NULL) ||
+ (ops->sequence == RT_NULL) || (ops->sequence->start == RT_NULL) ||
+ (ops->sequence->read == RT_NULL) || (ops->sequence->stop == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ device->parent.type = RT_Device_Class_ADC;
+ device->parent.rx_indicate = RT_NULL;
+ device->parent.tx_complete = RT_NULL;
+#ifdef RT_USING_DEVICE_OPS
+ device->parent.ops = &adc_device_ops;
+#else
+ device->parent.init = RT_NULL;
+ device->parent.open = adc_open_device;
+ device->parent.close = adc_close_device;
+ device->parent.read = adc_read_device;
+ device->parent.write = RT_NULL;
+ device->parent.control = adc_control_device;
+#endif /* RT_USING_DEVICE_OPS */
+ device->ops = ops;
+ rt_spin_lock_init(&device->spinlock);
+ rt_atomic_store(&device->state, (rt_atomic_t)RT_ADC_STATE_IDLE);
+ device->default_vref_mv = 0;
+ adc_clear_session_ctrl(device);
+#if defined(RT_ADC_USING_TRIGGER)
+ adc_trigger_init(device);
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+#ifdef RT_ADC_USING_STREAM
+ rt_memset(&device->stream_ctrl, 0, sizeof(device->stream_ctrl));
+#endif /* RT_ADC_USING_STREAM */
+ device->parent.user_data = (void *)user_data;
+
+ result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
+ if (result == RT_EOK)
+ {
+ LOG_I("device registered: %s", name);
+ }
+ else
+ {
+ LOG_E("device register failed: %s result=%d", name, result);
+ }
+
+ return result;
+}
+
+/**
+ * @brief Read one validated ADC sequence while the caller owns the device state.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the validated sequence request object.
+ * @param keep_state_on_success Whether to keep BUSY state after a successful read.
+ * @param read_count Pointer to the stored sample count.
+ * @return Operation status.
+ *
+ * @note A synchronous sequence request reads one scan frame only. Partial
+ * samples are reported through @p read_count when a read error or timeout
+ * happens after at least one sample is stored.
+ */
+static rt_err_t adc_read_sequence_locked(rt_adc_device_t device, rt_uint32_t channels,
+ const struct rt_adc_sequence_cfg *cfg, rt_bool_t keep_state_on_success, rt_size_t *read_count)
+{
+ rt_err_t result;
+ rt_size_t channel_count;
+
+ *read_count = 0U;
+ channel_count = rt_adc_channel_mask_count(channels);
+
+ result = adc_session_config(device, channels);
+ if (result != RT_EOK)
+ {
+ LOG_E("sequence config failed: device=%s result=%d", device->parent.parent.name, result);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+ }
+
+ result = adc_sequence_transfer_locked(device, channels, cfg, channel_count, read_count);
+
+ if ((result != RT_EOK) || (keep_state_on_success != RT_TRUE))
+ {
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ }
+
+ return result;
+}
+
+/**
+ * @brief Read one ADC sequence frame.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the sequence request object.
+ * @param read_count Pointer to the stored sample count.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_read_sequence(rt_adc_device_t device, rt_uint32_t channels,
+ const struct rt_adc_sequence_cfg *cfg, rt_size_t *read_count)
+{
+ rt_size_t channel_count;
+
+ if ((device == RT_NULL) || (cfg == RT_NULL) || (cfg->buffer == RT_NULL) ||
+ (read_count == RT_NULL) || (channels == 0U) ||
+ (device->ops == RT_NULL) || (device->ops->sequence == RT_NULL) || (device->ops->sequence->start == RT_NULL) ||
+ (device->ops->sequence->read == RT_NULL) || (device->ops->sequence->stop == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ *read_count = 0U;
+ channel_count = rt_adc_channel_mask_count(channels);
+ if ((channel_count == 0U) || (cfg->buffer_length < channel_count))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ return adc_read_sequence_locked(device, channels, cfg, RT_FALSE, read_count);
+}
+
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief Check whether an ADC stream policy is enabled by configuration.
+ * @param policy ADC stream buffering policy.
+ * @return RT_TRUE if the policy is supported, otherwise RT_FALSE.
+ */
+static rt_bool_t adc_stream_policy_is_supported(enum rt_adc_stream_policy policy)
+{
+ switch (policy)
+ {
+#ifdef RT_ADC_STREAM_USING_LATEST
+ case RT_ADC_STREAM_POLICY_LATEST:
+ return RT_TRUE;
+#endif /* RT_ADC_STREAM_USING_LATEST */
+#ifdef RT_ADC_STREAM_USING_FIFO
+ case RT_ADC_STREAM_POLICY_FIFO:
+ return RT_TRUE;
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ default:
+ return RT_FALSE;
+ }
+}
+
+/**
+ * @brief Resolve the effective DMA data event mode for one stream request.
+ * @param policy Active stream buffering policy.
+ * @param request Requested DMA event mode.
+ * @param effective Pointer to the output effective event mode.
+ * @return Operation status.
+ */
+static rt_err_t adc_stream_resolve_dma_event_mode(enum rt_adc_stream_policy policy,
+ enum rt_adc_stream_dma_event_mode request,
+ enum rt_adc_stream_dma_event_mode *effective)
+{
+ if (request == RT_ADC_STREAM_DMA_EVENT_AUTO)
+ {
+#ifdef RT_ADC_STREAM_USING_LATEST
+ if (policy == RT_ADC_STREAM_POLICY_LATEST)
+ {
+ *effective = RT_ADC_STREAM_DMA_EVENT_NONE;
+ return RT_EOK;
+ }
+#endif /* RT_ADC_STREAM_USING_LATEST */
+#ifdef RT_ADC_STREAM_USING_FIFO
+ if (policy == RT_ADC_STREAM_POLICY_FIFO)
+ {
+ *effective = RT_ADC_STREAM_DMA_EVENT_HALF_FULL;
+ return RT_EOK;
+ }
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ return -RT_ENOSYS;
+ }
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+ if ((policy == RT_ADC_STREAM_POLICY_FIFO) && (request == RT_ADC_STREAM_DMA_EVENT_NONE))
+ {
+ return -RT_EINVAL;
+ }
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ if ((request != RT_ADC_STREAM_DMA_EVENT_NONE) &&
+ (request != RT_ADC_STREAM_DMA_EVENT_FULL_ONLY) &&
+ (request != RT_ADC_STREAM_DMA_EVENT_HALF_FULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ *effective = request;
+ return RT_EOK;
+}
+
+/**
+ * @brief Reset one ADC stream runtime control block.
+ * @param ctrl Pointer to the stream control block.
+ */
+static void adc_stream_ctrl_reset(struct rt_adc_stream_ctrl *ctrl)
+{
+ rt_memset(ctrl, 0, sizeof(*ctrl));
+}
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+/**
+ * @brief Wake FIFO stream readers when the active stream owns a FIFO.
+ * @param ctrl Pointer to the stream control block.
+ */
+static void adc_stream_fifo_wakeup(struct rt_adc_stream_ctrl *ctrl)
+{
+ if ((ctrl->policy == RT_ADC_STREAM_POLICY_FIFO) && (ctrl->fifo_enabled == RT_TRUE))
+ {
+ rt_completion_done(&ctrl->rx_cpt);
+ }
+}
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+/**
+ * @brief Validate a stream request and initialize the stream control block.
+ * @param device Pointer to the ADC device object.
+ * @param cfg Pointer to the stream configuration object.
+ * @param frame_length Samples in one ADC scan frame.
+ * @return Operation status.
+ */
+static rt_err_t adc_stream_ctrl_configure(rt_adc_device_t device, const struct rt_adc_stream_cfg *cfg, rt_size_t frame_length)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ enum rt_adc_stream_dma_event_mode dma_event_mode;
+ rt_err_t result;
+
+ if ((cfg->dma_buffer == RT_NULL) || (cfg->dma_buffer_length == 0U) || (frame_length == 0U) ||
+ (adc_stream_policy_is_supported(cfg->policy) != RT_TRUE))
+ {
+ LOG_E("stream ctrl config invalid args: device=%s buffer=%p len=%u frame=%u",
+ device->parent.parent.name, cfg->dma_buffer, (unsigned int)cfg->dma_buffer_length, (unsigned int)frame_length);
+ return -RT_EINVAL;
+ }
+
+ result = adc_stream_resolve_dma_event_mode(cfg->policy, cfg->dma_event_mode, &dma_event_mode);
+ if (result != RT_EOK)
+ {
+ LOG_E("stream ctrl config invalid event mode: device=%s policy=%d mode=%d",
+ device->parent.parent.name, (int)cfg->policy, (int)cfg->dma_event_mode);
+ return result;
+ }
+
+ LOG_D("stream ctrl config start: device=%s policy=%s frame=%u dma=%u event_mode=%d",
+ device->parent.parent.name, adc_stream_policy_name(cfg->policy),
+ (unsigned int)frame_length, (unsigned int)cfg->dma_buffer_length, (int)dma_event_mode);
+ ctrl = &device->stream_ctrl;
+ adc_stream_ctrl_reset(ctrl);
+
+#ifdef RT_ADC_STREAM_USING_LATEST
+ if (cfg->policy == RT_ADC_STREAM_POLICY_LATEST)
+ {
+ if (cfg->dma_buffer_length != frame_length)
+ {
+ LOG_E("latest stream invalid length: device=%s dma=%u frame=%u",
+ device->parent.parent.name, (unsigned int)cfg->dma_buffer_length, (unsigned int)frame_length);
+ return -RT_EINVAL;
+ }
+
+ ctrl->active = RT_TRUE;
+ ctrl->policy = cfg->policy;
+ ctrl->dma_event_mode = dma_event_mode;
+ ctrl->dma_buffer = cfg->dma_buffer;
+ ctrl->dma_buffer_length = cfg->dma_buffer_length;
+ ctrl->frame_length = frame_length;
+ LOG_D("latest stream configured: device=%s frame=%u", device->parent.parent.name, (unsigned int)frame_length);
+ return RT_EOK;
+ }
+#endif /* RT_ADC_STREAM_USING_LATEST */
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+ if (cfg->policy == RT_ADC_STREAM_POLICY_FIFO)
+ {
+ if ((cfg->fifo_buffer == RT_NULL) || (cfg->fifo_buffer_length == 0U))
+ {
+ LOG_E("fifo stream invalid fifo buffer: device=%s len=%u",
+ device->parent.parent.name, (unsigned int)cfg->fifo_buffer_length);
+ return -RT_EINVAL;
+ }
+
+ if ((cfg->watermark != 0U) && (cfg->watermark > cfg->fifo_buffer_length))
+ {
+ LOG_E("fifo stream invalid watermark: device=%s watermark=%u fifo=%u",
+ device->parent.parent.name, (unsigned int)cfg->watermark, (unsigned int)cfg->fifo_buffer_length);
+ return -RT_EINVAL;
+ }
+
+ if (cfg->dma_buffer_length < frame_length)
+ {
+ LOG_E("fifo stream invalid dma length: device=%s dma=%u frame=%u",
+ device->parent.parent.name, (unsigned int)cfg->dma_buffer_length, (unsigned int)frame_length);
+ return -RT_EINVAL;
+ }
+
+ /* The default FIFO start path accepts generic DMA staging buffers and
+ * reports runtime overflow through last_error. Use
+ * rt_adc_stream_start_frame_aligned_fifo() when the caller requires a DMA
+ * data-event block layout that never splits ADC scan frames.
+ */
+ ctrl->active = RT_TRUE;
+ ctrl->policy = cfg->policy;
+ ctrl->dma_event_mode = dma_event_mode;
+ ctrl->dma_buffer = cfg->dma_buffer;
+ ctrl->dma_buffer_length = cfg->dma_buffer_length;
+ ctrl->frame_length = frame_length;
+ ctrl->watermark = cfg->watermark;
+ ctrl->callback = cfg->callback;
+ ctrl->user_data = cfg->user_data;
+ ctrl->overflow_count = 0U;
+ rt_atomic_store(&ctrl->last_error, (rt_atomic_t)RT_EOK);
+ rt_ringbuffer_init(&ctrl->fifo, (rt_uint8_t *)cfg->fifo_buffer, (rt_int32_t)(cfg->fifo_buffer_length * sizeof(rt_uint32_t)));
+ rt_completion_init(&ctrl->rx_cpt);
+ ctrl->fifo_enabled = RT_TRUE;
+ LOG_D("fifo stream configured: device=%s frame=%u dma=%u fifo=%u watermark=%u event_mode=%d",
+ device->parent.parent.name, (unsigned int)frame_length, (unsigned int)cfg->dma_buffer_length,
+ (unsigned int)cfg->fifo_buffer_length, (unsigned int)cfg->watermark, (int)dma_event_mode);
+ return RT_EOK;
+ }
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ LOG_E("stream policy unsupported: device=%s policy=%d", device->parent.parent.name, (int)cfg->policy);
+ return -RT_ENOSYS;
+}
+
+#ifdef RT_ADC_STREAM_USING_LATEST
+/**
+ * @brief Read the latest ADC rank values from the DMA buffer.
+ * @param device Pointer to the ADC device object.
+ * @param buffer Pointer to the destination sample buffer.
+ * @param sample_count Destination buffer length in samples.
+ * @param timeout_ms Unused timeout parameter.
+ * @return Number of samples read, or a negative RT-Thread error code.
+ *
+ * @note Latest mode is a lockless DMA-buffer view. CPU-side atomic operations,
+ * spin locks, mutexes, or read-write locks cannot prevent the DMA engine
+ * from updating memory concurrently, because DMA does not participate in
+ * CPU locking protocols. This mode only guarantees that each buffer index
+ * maps to the corresponding ADC rank latest value; it does not guarantee
+ * that the copied frame is a single hardware scan-cycle snapshot. Use FIFO
+ * mode when ordered and frame-accurate samples are required.
+ */
+static rt_ssize_t rt_adc_stream_read_latest(rt_adc_device_t device, rt_uint32_t *buffer,
+ rt_size_t sample_count, rt_int32_t timeout_ms)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ rt_err_t result;
+
+ RT_UNUSED(timeout_ms);
+
+ ctrl = &device->stream_ctrl;
+ if (sample_count < ctrl->frame_length)
+ {
+ LOG_E("latest read buffer too small: device=%s samples=%u frame=%u",
+ device->parent.parent.name, (unsigned int)sample_count, (unsigned int)ctrl->frame_length);
+ return -RT_EINVAL;
+ }
+
+ result = (rt_err_t)rt_atomic_load(&ctrl->last_error);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ if ((device->ops != RT_NULL) && (device->ops->stream != RT_NULL) && (device->ops->stream->sync != RT_NULL))
+ {
+ result = device->ops->stream->sync(device, ctrl->dma_buffer, ctrl->frame_length);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ }
+
+ result = (rt_err_t)rt_atomic_load(&ctrl->last_error);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ rt_memcpy(buffer, ctrl->dma_buffer, ctrl->frame_length * sizeof(rt_uint32_t));
+ return (rt_ssize_t)ctrl->frame_length;
+}
+#endif /* RT_ADC_STREAM_USING_LATEST */
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+/**
+ * @brief Read ordered ADC samples from the framework FIFO.
+ * @param device Pointer to the ADC device object.
+ * @param buffer Pointer to the destination sample buffer.
+ * @param sample_count Number of samples to read before returning unless timeout or error occurs.
+ * @param timeout_ms Total read timeout in milliseconds; negative means wait forever.
+ * @return Number of samples read, or a negative RT-Thread error code.
+ * @note In blocking mode, this function waits until the requested sample count is read or timeout occurs.
+ * On timeout, the partial sample count is returned if any samples were read.
+ */
+static rt_ssize_t rt_adc_stream_read_fifo(rt_adc_device_t device, rt_uint32_t *buffer, rt_size_t sample_count, rt_int32_t timeout_ms)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ rt_size_t read_count;
+ rt_tick_t timeout_tick;
+ rt_tick_t begin_tick;
+
+ ctrl = &device->stream_ctrl;
+ read_count = 0U;
+ timeout_tick = (timeout_ms < 0) ? RT_WAITING_FOREVER : rt_tick_from_millisecond(timeout_ms);
+ begin_tick = rt_tick_get();
+
+ while (read_count < sample_count)
+ {
+ enum rt_adc_state state;
+ rt_base_t level;
+ rt_size_t got;
+ rt_err_t result;
+ rt_tick_t wait_tick;
+
+ state = adc_get_state(device);
+ if (state != RT_ADC_STATE_STREAM)
+ {
+ return (read_count > 0U) ? (rt_ssize_t)read_count : ((state == RT_ADC_STATE_IDLE) ? -RT_EINVAL : -RT_EBUSY);
+ }
+
+ level = rt_spin_lock_irqsave(&device->spinlock);
+ got = rt_ringbuffer_get(&ctrl->fifo, (rt_uint8_t *)&buffer[read_count],
+ (rt_uint32_t)((sample_count - read_count) * sizeof(rt_uint32_t)));
+ rt_spin_unlock_irqrestore(&device->spinlock, level);
+
+ read_count += got / sizeof(rt_uint32_t);
+ if (read_count >= sample_count)
+ {
+ return (rt_ssize_t)read_count;
+ }
+
+ result = (rt_err_t)rt_atomic_load(&ctrl->last_error);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ if (timeout_ms == RT_WAITING_NO)
+ {
+ return (read_count > 0U) ? (rt_ssize_t)read_count : -RT_ETIMEOUT;
+ }
+
+ if (timeout_ms < 0)
+ {
+ wait_tick = RT_WAITING_FOREVER;
+ }
+ else
+ {
+ rt_tick_t delta_tick;
+
+ delta_tick = rt_tick_get_delta(begin_tick);
+ if (delta_tick >= timeout_tick)
+ {
+ return (read_count > 0U) ? (rt_ssize_t)read_count : -RT_ETIMEOUT;
+ }
+
+ wait_tick = timeout_tick - delta_tick;
+ }
+
+ if (rt_completion_wait(&ctrl->rx_cpt, wait_tick) != RT_EOK)
+ {
+ return (read_count > 0U) ? (rt_ssize_t)read_count : -RT_ETIMEOUT;
+ }
+ }
+
+ return (rt_ssize_t)read_count;
+}
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+/**
+ * @brief Start one ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the stream configuration object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_start(rt_adc_device_t device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg)
+{
+ rt_size_t frame_length;
+ rt_err_t result;
+ rt_bool_t start_called;
+
+ if ((device == RT_NULL) || (cfg == RT_NULL) || (channels == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((device->ops == RT_NULL) || (device->ops->stream == RT_NULL) ||
+ (device->ops->stream->start == RT_NULL) || (device->ops->stream->stop == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+ start_called = RT_FALSE;
+#if defined(RT_ADC_USING_TRIGGER)
+ rt_bool_t trigger_started = RT_FALSE;
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ frame_length = rt_adc_channel_mask_count(channels);
+ result = adc_cache_session_ctrl(device, channels);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+
+ result = adc_stream_ctrl_configure(device, cfg, frame_length);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+
+#if defined(RT_ADC_USING_TRIGGER)
+ result = adc_trigger_preconfig(device);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ start_called = RT_TRUE;
+ result = device->ops->stream->start(device, channels, cfg);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+
+ result = (rt_err_t)rt_atomic_load(&device->stream_ctrl.last_error);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+
+#if defined(RT_ADC_USING_TRIGGER)
+ result = adc_trigger_source_control(device, ADC_TRIGGER_SOURCE_START, &trigger_started, RT_EOK);
+ if (result != RT_EOK)
+ {
+ goto fail_after_lock;
+ }
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ adc_set_state(device, RT_ADC_STATE_STREAM);
+ return RT_EOK;
+
+fail_after_lock:
+ if(result != RT_EOK)
+ {
+ LOG_E("stream start failed: device=%s result=%d", device->parent.parent.name, result);
+ }
+#if defined(RT_ADC_USING_TRIGGER)
+ result = adc_trigger_source_control(device, ADC_TRIGGER_SOURCE_STOP, &trigger_started, result);
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ if (start_called == RT_TRUE)
+ {
+ rt_err_t stop_result;
+ rt_bool_t hardware_stopped;
+
+ hardware_stopped = RT_FALSE;
+ stop_result = device->ops->stream->stop(device, &hardware_stopped);
+ if ((stop_result != RT_EOK) && (hardware_stopped != RT_TRUE))
+ {
+ adc_set_state(device, RT_ADC_STATE_STREAM);
+ return stop_result;
+ }
+ }
+
+ adc_stream_ctrl_reset(&device->stream_ctrl);
+ adc_clear_session_ctrl(device);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+}
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+/**
+ * @brief Start a FIFO ADC stream with strict frame-aligned buffer layout.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the stream configuration object.
+ * @return Operation status.
+ *
+ * @note This helper is intended for continuous FIFO sampling where DMA
+ * data-event blocks must not split ADC scan frames. It validates that
+ * each DMA event block contains complete frames and that the FIFO can
+ * accept at least one complete event block.
+ * @note Passing this validation does not prove that samples can never be lost.
+ * The reader must still drain the FIFO fast enough for the selected
+ * sample rate and scheduler latency. Runtime overflow is still reported
+ * through the stream error state.
+ */
+rt_err_t rt_adc_stream_start_frame_aligned_fifo(rt_adc_device_t device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg)
+{
+ rt_size_t frame_length;
+ rt_size_t block_length;
+ enum rt_adc_stream_dma_event_mode dma_event_mode;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (cfg == RT_NULL) || (channels == 0U) ||
+ (cfg->policy != RT_ADC_STREAM_POLICY_FIFO) ||
+ (cfg->dma_buffer == RT_NULL) || (cfg->dma_buffer_length == 0U) ||
+ (cfg->fifo_buffer == RT_NULL) || (cfg->fifo_buffer_length == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ frame_length = rt_adc_channel_mask_count(channels);
+ if (frame_length == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ result = adc_stream_resolve_dma_event_mode(cfg->policy, cfg->dma_event_mode, &dma_event_mode);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ block_length = (dma_event_mode == RT_ADC_STREAM_DMA_EVENT_FULL_ONLY) ? cfg->dma_buffer_length : (cfg->dma_buffer_length / 2U);
+ if ((cfg->dma_buffer_length < frame_length) || /* DMA buffer must contain at least one complete scan frame. */
+ ((cfg->dma_buffer_length % frame_length) != 0U) || /* DMA buffer length must be aligned to complete scan frames. */
+ (block_length == 0U) || /* The selected DMA event mode must produce a non-empty staging block. */
+ ((block_length % frame_length) != 0U) || /* Each staging block copied to FIFO must contain complete scan frames only. */
+ (cfg->fifo_buffer_length < block_length) || /* FIFO must be able to store at least one completed DMA staging block. */
+ ((cfg->fifo_buffer_length % frame_length) != 0U)) /* FIFO capacity must also be aligned to complete scan frames. */
+ {
+ LOG_E("frame-aligned fifo stream invalid layout: device=%s dma=%u block=%u frame=%u fifo=%u",
+ device->parent.parent.name, (unsigned int)cfg->dma_buffer_length,
+ (unsigned int)block_length, (unsigned int)frame_length,
+ (unsigned int)cfg->fifo_buffer_length);
+ return -RT_EINVAL;
+ }
+
+ if ((dma_event_mode == RT_ADC_STREAM_DMA_EVENT_HALF_FULL) && ((cfg->dma_buffer_length % 2U) != 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ return rt_adc_stream_start(device, channels, cfg);
+}
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+/**
+ * @brief Read converted samples from an active ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @param buffer Pointer to the destination sample buffer.
+ * @param sample_count Number of samples to read.
+ * @param timeout_ms Read timeout in milliseconds; negative means wait forever.
+ * @return Number of samples read, or a negative RT-Thread error code.
+ */
+rt_ssize_t rt_adc_stream_read(rt_adc_device_t device, rt_uint32_t *buffer, rt_size_t sample_count, rt_int32_t timeout_ms)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ rt_ssize_t read_count;
+
+ if ((device == RT_NULL) || (buffer == RT_NULL) || (sample_count == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (adc_get_state(device) != RT_ADC_STATE_STREAM)
+ {
+ return -RT_EINVAL;
+ }
+
+ ctrl = &device->stream_ctrl;
+ switch (ctrl->policy)
+ {
+#ifdef RT_ADC_STREAM_USING_LATEST
+ case RT_ADC_STREAM_POLICY_LATEST:
+ read_count = rt_adc_stream_read_latest(device, buffer, sample_count, timeout_ms);
+ break;
+#endif /* RT_ADC_STREAM_USING_LATEST */
+#ifdef RT_ADC_STREAM_USING_FIFO
+ case RT_ADC_STREAM_POLICY_FIFO:
+ read_count = rt_adc_stream_read_fifo(device, buffer, sample_count, timeout_ms);
+ break;
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ default:
+ read_count = -RT_EINVAL;
+ break;
+ }
+
+ return read_count;
+}
+
+/**
+ * @brief Cancel a blocked ADC stream reader before stream shutdown.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_cancel(rt_adc_device_t device)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ rt_atomic_t old_error;
+ enum rt_adc_state state;
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ state = adc_get_state(device);
+ if (state != RT_ADC_STATE_STREAM)
+ {
+ return (state == RT_ADC_STATE_IDLE) ? -RT_EINVAL : -RT_EBUSY;
+ }
+
+ ctrl = &device->stream_ctrl;
+ old_error = (rt_atomic_t)RT_EOK;
+ (void)rt_atomic_compare_exchange_strong(&ctrl->last_error, &old_error, (rt_atomic_t)-RT_EINTR);
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+ adc_stream_fifo_wakeup(ctrl);
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Stop one ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_stop(rt_adc_device_t device)
+{
+ rt_bool_t hardware_stopped;
+ rt_err_t result;
+ rt_err_t trigger_result;
+ enum rt_adc_state state;
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((device->ops == RT_NULL) || (device->ops->stream == RT_NULL) || (device->ops->stream->stop == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+ state = adc_get_state(device);
+ if (state == RT_ADC_STATE_IDLE)
+ {
+ return RT_EOK;
+ }
+ if (state != RT_ADC_STATE_STREAM)
+ {
+ return -RT_EBUSY;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_STREAM, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+#if defined(RT_ADC_USING_TRIGGER)
+ rt_bool_t trigger_started = RT_TRUE;
+ trigger_result = adc_trigger_source_control(device, ADC_TRIGGER_SOURCE_STOP, &trigger_started, RT_EOK);
+#else
+ trigger_result = RT_EOK;
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ hardware_stopped = RT_FALSE;
+ result = device->ops->stream->stop(device, &hardware_stopped);
+ if ((result == RT_EOK) && (trigger_result != RT_EOK))
+ {
+ result = trigger_result;
+ }
+
+ if ((result == RT_EOK) || (hardware_stopped == RT_TRUE))
+ {
+#ifdef RT_ADC_STREAM_USING_FIFO
+ rt_atomic_store(&device->stream_ctrl.last_error, (rt_atomic_t)((result == RT_EOK) ? -RT_EINVAL : result));
+ adc_stream_fifo_wakeup(&device->stream_ctrl);
+ device->stream_ctrl.fifo_enabled = RT_FALSE;
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ adc_stream_ctrl_reset(&device->stream_ctrl);
+ adc_clear_session_ctrl(device);
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ }
+ else
+ {
+ adc_set_state(device, RT_ADC_STATE_STREAM);
+ }
+
+ return result;
+}
+
+/**
+ * @brief ADC stream ISR event handler used by low-level drivers.
+ * @param device Pointer to the ADC device object.
+ * @param event Stream event.
+ * @param sample_buffer Pointer to the completed DMA sample block.
+ * @param sample_count Completed sample count.
+ * @return Operation status.
+ */
+rt_err_t rt_hw_adc_stream_isr(rt_adc_device_t device, enum rt_adc_stream_event event,
+ const rt_uint32_t *sample_buffer, rt_size_t sample_count)
+{
+ struct rt_adc_stream_ctrl *ctrl;
+ enum rt_adc_state state;
+#ifdef RT_ADC_STREAM_USING_FIFO
+ const rt_uint8_t *src;
+ rt_size_t bytes;
+ rt_size_t put_len;
+ rt_size_t data_len;
+ rt_base_t level;
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ ctrl = &device->stream_ctrl;
+ if (event == RT_ADC_STREAM_EVENT_ERROR)
+ {
+ rt_atomic_t old_error;
+
+ old_error = (rt_atomic_t)RT_EOK;
+ if (rt_atomic_compare_exchange_strong(&ctrl->last_error, &old_error, (rt_atomic_t)-RT_ERROR) == RT_TRUE)
+ {
+ LOG_W("stream error: device=%s event=%d", device->parent.parent.name, event);
+ }
+#ifdef RT_ADC_STREAM_USING_FIFO
+ adc_stream_fifo_wakeup(ctrl);
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ return RT_EOK;
+ }
+
+ state = adc_get_state(device);
+#ifdef RT_ADC_STREAM_USING_FIFO
+ if ((state != RT_ADC_STATE_STREAM) && !((state == RT_ADC_STATE_LOCKED) && (ctrl->fifo_enabled == RT_TRUE)))
+ {
+ return RT_EOK;
+ }
+#else
+ if (state != RT_ADC_STATE_STREAM)
+ {
+ return RT_EOK;
+ }
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+ if ((event != RT_ADC_STREAM_EVENT_DMA_HALF) && (event != RT_ADC_STREAM_EVENT_DMA_DONE))
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((rt_err_t)rt_atomic_load(&ctrl->last_error) != RT_EOK)
+ {
+ return RT_EOK;
+ }
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+ if ((ctrl->policy != RT_ADC_STREAM_POLICY_FIFO) || (ctrl->fifo_enabled != RT_TRUE))
+ {
+ return RT_EOK;
+ }
+
+ if ((sample_buffer == RT_NULL) || (sample_count == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ src = (const rt_uint8_t *)sample_buffer;
+ bytes = sample_count * sizeof(rt_uint32_t);
+
+ level = rt_spin_lock_irqsave(&device->spinlock);
+ put_len = rt_ringbuffer_put(&ctrl->fifo, src, (rt_uint32_t)bytes);
+ data_len = rt_ringbuffer_data_len(&ctrl->fifo);
+ rt_spin_unlock_irqrestore(&device->spinlock, level);
+
+ if (put_len < bytes)
+ {
+ rt_atomic_t old_error;
+ ctrl->overflow_count++;
+ old_error = (rt_atomic_t)RT_EOK;
+ if (rt_atomic_compare_exchange_strong(&ctrl->last_error, &old_error, (rt_atomic_t)-RT_EFULL) == RT_TRUE)
+ {
+ LOG_W("stream fifo overflow: device=%s put=%u expected=%u data_len=%u",
+ device->parent.parent.name, (unsigned int)put_len, (unsigned int)bytes, (unsigned int)data_len);
+ }
+ adc_stream_fifo_wakeup(ctrl);
+ }
+
+ if ((put_len > 0U) && ((ctrl->watermark == 0U) || (data_len >= (ctrl->watermark * sizeof(rt_uint32_t)))))
+ {
+ adc_stream_fifo_wakeup(ctrl);
+
+ if (ctrl->callback != RT_NULL)
+ {
+ ctrl->callback(device, put_len / sizeof(rt_uint32_t), ctrl->user_data);
+ }
+ }
+
+ return RT_EOK;
+#else
+ RT_UNUSED(sample_buffer);
+ RT_UNUSED(sample_count);
+ return RT_EOK;
+#endif /* RT_ADC_STREAM_USING_FIFO */
+}
+#endif /* RT_ADC_USING_STREAM */
+
+/**
+ * @brief Convert one ADC raw sample to millivolts.
+ * @param raw_value Raw ADC sample code.
+ * @param vref_mv ADC reference voltage in millivolts.
+ * @param resolution_bits ADC resolution in bits.
+ * @param voltage_mv Pointer to the output voltage in millivolts.
+ * @return Operation status.
+ *
+ * ADC codes are treated as an inclusive range from 0 to
+ * ``(1 << resolution_bits) - 1``. The calculation uses a 64-bit
+ * intermediate value and rounds to the nearest integer millivolt.
+ */
+rt_err_t rt_adc_raw_to_voltage_mv(rt_uint32_t raw_value, rt_uint32_t vref_mv,
+ rt_uint8_t resolution_bits, rt_uint32_t *voltage_mv)
+{
+ rt_uint64_t full_scale_code;
+
+ if ((voltage_mv == RT_NULL) || (vref_mv == 0U) || (resolution_bits == 0U) || (resolution_bits > 32U))
+ {
+ return -RT_EINVAL;
+ }
+
+ full_scale_code = ((rt_uint64_t)1 << resolution_bits) - 1ULL;
+ if ((rt_uint64_t)raw_value > full_scale_code)
+ {
+ return -RT_EINVAL;
+ }
+
+ /*
+ * Convert ADC code to millivolts:
+ *
+ * voltage_mv = raw * vref_mv / full_scale_code
+ * full_scale_code = (1 << resolution_bits) - 1
+ *
+ * ADC codes are treated as an inclusive range from 0 to full scale.
+ * The multiplication is promoted to 64-bit first, then half of the
+ * denominator is added to round to the nearest integer millivolt instead
+ * of truncating non-exact divisions toward zero.
+ */
+ *voltage_mv = (rt_uint32_t)(((rt_uint64_t)raw_value * (rt_uint64_t)vref_mv + (full_scale_code / 2ULL)) / full_scale_code);
+
+ return RT_EOK;
+}
+
+/**
+ * @brief Convert one ADC raw sample to a scaled voltage in millivolts.
+ * @param raw_value Raw ADC sample code.
+ * @param vref_mv ADC reference voltage in millivolts.
+ * @param resolution_bits ADC resolution in bits.
+ * @param scale_num Voltage scaling numerator.
+ * @param scale_den Voltage scaling denominator.
+ * @param voltage_mv Pointer to the output scaled voltage in millivolts.
+ * @return Operation status.
+ *
+ * The scaled voltage is calculated as:
+ *
+ * raw_to_voltage_mv(raw_value) * scale_num / scale_den
+ *
+ * @note @p scale_num and @p scale_den may describe any positive rational
+ * scaling ratio that does not overflow the internal calculation. The
+ * final scaled millivolt value must fit in rt_uint32_t.
+ *
+ * @retval RT_EOK The conversion completed successfully.
+ * @retval -RT_EINVAL A pointer is null, a scale argument is zero, the ADC
+ * conversion arguments are invalid, or the scaled result overflows
+ * rt_uint32_t.
+ */
+rt_err_t rt_adc_raw_to_scaled_voltage_mv(rt_uint32_t raw_value, rt_uint32_t vref_mv,
+ rt_uint8_t resolution_bits, rt_uint32_t scale_num,
+ rt_uint32_t scale_den, rt_uint32_t *voltage_mv)
+{
+ rt_uint32_t input_mv;
+ rt_uint64_t numerator;
+ rt_uint64_t rounding;
+ rt_uint64_t scaled_mv;
+ rt_err_t result;
+
+ if ((voltage_mv == RT_NULL) || (scale_num == 0U) || (scale_den == 0U))
+ {
+ return -RT_EINVAL;
+ }
+
+ result = rt_adc_raw_to_voltage_mv(raw_value, vref_mv, resolution_bits, &input_mv);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ numerator = (rt_uint64_t)input_mv * (rt_uint64_t)scale_num;
+ rounding = (rt_uint64_t)scale_den / 2ULL;
+
+ if (numerator > (((rt_uint64_t)~0ULL) - rounding))
+ {
+ return -RT_EINVAL;
+ }
+
+ scaled_mv = (numerator + rounding) / (rt_uint64_t)scale_den;
+ if (scaled_mv > RT_UINT32_MAX)
+ {
+ return -RT_EINVAL;
+ }
+
+ *voltage_mv = (rt_uint32_t)scaled_mv;
+ return RT_EOK;
+}
+
+/**
+ * @brief Read voltage values from the configured ADC session.
+ * @param device Pointer to the ADC device object.
+ * @param voltages_mv Pointer to the output voltage buffer in millivolts.
+ * @param size Output voltage buffer length in samples.
+ * @param timeout_ms Read timeout in milliseconds; negative means wait forever.
+ * @return Operation status.
+ *
+ * @note @p size must match the configured session channel count. The output
+ * order follows the ascending bit order of the configured channel mask.
+ * The configured default_vref_mv is preferred for voltage conversion. If
+ * default_vref_mv is not configured, the backend VREF channel is used for
+ * VDDA calculation only when it is present in the configured session.
+ */
+rt_err_t rt_adc_voltage(rt_adc_device_t device, rt_uint32_t *voltages_mv, rt_size_t size, rt_int32_t timeout_ms)
+{
+ rt_uint32_t vref_mv;
+ rt_uint32_t vref_value;
+ rt_uint8_t resolution_bits;
+ rt_uint8_t vref_channel;
+ rt_size_t vref_index;
+ rt_size_t index;
+ struct rt_adc_sequence_cfg sequence_cfg;
+ rt_size_t read_count;
+ rt_err_t result;
+
+ if ((device == RT_NULL) || (voltages_mv == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) || (device->ops->core->control == RT_NULL))
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (adc_try_set_state(device, RT_ADC_STATE_IDLE, RT_ADC_STATE_LOCKED) != RT_TRUE)
+ {
+ return -RT_EBUSY;
+ }
+
+ LOG_D("voltage request: device=%s count=%u timeout=%ld", device->parent.parent.name, (unsigned int)size, (long)timeout_ms);
+
+ if ((device->session_ctrl.configured != RT_TRUE) || (device->session_ctrl.channel_count == 0U) || (size != device->session_ctrl.channel_count))
+ {
+ result = -RT_EINVAL;
+ goto out;
+ }
+
+ rt_memset(&sequence_cfg, 0, sizeof(sequence_cfg));
+ sequence_cfg.buffer = voltages_mv;
+ sequence_cfg.buffer_length = size;
+ sequence_cfg.timeout_ms = timeout_ms;
+ result = adc_sequence_transfer_locked(device, device->session_ctrl.channels,
+ &sequence_cfg, size, &read_count);
+ if ((result == RT_EOK) && (read_count != size))
+ {
+ result = -RT_ERROR;
+ }
+ if (result != RT_EOK)
+ {
+ LOG_E("voltage sample read failed: device=%s result=%d", device->parent.parent.name, result);
+ goto out;
+ }
+
+ result = device->ops->core->control(device, RT_ADC_CMD_GET_RESOLUTION, &resolution_bits);
+ if (result != RT_EOK)
+ {
+ goto out;
+ }
+
+ vref_mv = 0U;
+ if (device->default_vref_mv != 0U)
+ {
+ vref_mv = device->default_vref_mv;
+ result = RT_EOK;
+ }
+ else
+ {
+ vref_channel = 0U;
+ result = device->ops->core->control(device, RT_ADC_CMD_GET_VREF_CHANNEL, &vref_channel);
+ if ((result == RT_EOK) && (vref_channel < 32U) && ((device->session_ctrl.channels & RT_ADC_CHANNEL_MASK(vref_channel)) != 0U))
+ {
+ result = rt_adc_session_channel_index(device->session_ctrl.channels, RT_ADC_CHANNEL_MASK(vref_channel), &vref_index);
+ if (result != RT_EOK)
+ {
+ goto out;
+ }
+
+ vref_value = voltages_mv[vref_index];
+ result = device->ops->core->control(device, RT_ADC_CMD_CALC_VREF, &vref_value);
+ if (result != RT_EOK)
+ {
+ LOG_E("vref calculate failed: device=%s raw=%lu result=%d",
+ device->parent.parent.name, (unsigned long)voltages_mv[vref_index], result);
+ goto out;
+ }
+
+ if (vref_value == 0U)
+ {
+ result = -RT_EINVAL;
+ goto out;
+ }
+
+ vref_mv = vref_value;
+ }
+ else
+ {
+ result = -RT_EINVAL;
+ goto out;
+ }
+ }
+
+ for (index = 0U; index < size; index++)
+ {
+ result = rt_adc_raw_to_voltage_mv(voltages_mv[index], vref_mv, resolution_bits, &voltages_mv[index]);
+ if (result != RT_EOK)
+ {
+ goto out;
+ }
+ }
+
+ LOG_D("voltage done: device=%s count=%u vref=%lu resolution=%u",
+ device->parent.parent.name, (unsigned int)size,
+ (unsigned long)vref_mv, (unsigned int)resolution_bits);
+ result = RT_EOK;
+
+out:
+ adc_set_state(device, RT_ADC_STATE_IDLE);
+ return result;
+}
+
+#endif /* defined(RT_USING_ADC_V2) */
diff --git a/components/drivers/adc/adc_v2_internal.h b/components/drivers/adc/adc_v2_internal.h
new file mode 100644
index 0000000000..1f97f17dd8
--- /dev/null
+++ b/components/drivers/adc/adc_v2_internal.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file adc_v2_internal.h
+ * @brief Internal ADC V2 framework declarations.
+ */
+
+#ifndef __ADC_V2_INTERNAL_H__
+#define __ADC_V2_INTERNAL_H__
+
+#include <rtconfig.h>
+#include <drivers/adc_v2.h>
+
+#if defined(RT_ADC_USING_TRIGGER)
+/**
+ * @brief Initialize the cached ADC trigger state to the default software-started mode.
+ * @param device Pointer to the ADC device object.
+ */
+void adc_trigger_init(rt_adc_device_t device);
+
+/**
+ * @brief Preconfigure the active device-level ADC trigger before hardware configuration.
+ * @param device Pointer to the ADC device object.
+ * @return RT_EOK on success, otherwise an RT-Thread error code.
+ */
+rt_err_t adc_trigger_preconfig(rt_adc_device_t device);
+
+/**
+ * @brief Get the active device-level ADC trigger configuration.
+ * @param device Pointer to the ADC device object.
+ * @return Pointer to the cached trigger configuration, or RT_NULL when no hardware trigger is configured.
+ */
+const struct rt_adc_trigger_cfg *adc_trigger_active_get(rt_adc_device_t device);
+
+/**
+ * @brief Trigger-source lifecycle actions used after ADC hardware is armed.
+ */
+enum adc_trigger_source_action
+{
+ ADC_TRIGGER_SOURCE_START = 0, /**< Start the active trigger source. */
+ ADC_TRIGGER_SOURCE_STOP /**< Stop the previously started trigger source. */
+};
+
+/**
+ * @brief Control the active trigger source around an armed ADC conversion path.
+ * @param device Pointer to the ADC device object.
+ * @param action Trigger-source lifecycle action.
+ * @param started Pointer to the trigger-start state.
+ * @param current_result Transfer result before trigger stop, ignored for start.
+ * @return For start, trigger-source start result; for stop, @p current_result unless trigger stop is the first
+ * observed failure.
+ */
+rt_err_t adc_trigger_source_control(rt_adc_device_t device, enum adc_trigger_source_action action,
+ rt_bool_t *started, rt_err_t current_result);
+
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#endif /* __ADC_V2_INTERNAL_H__ */
diff --git a/components/drivers/adc/adc_v2_msh.c b/components/drivers/adc/adc_v2_msh.c
new file mode 100644
index 0000000000..7bc42f6cbf
--- /dev/null
+++ b/components/drivers/adc/adc_v2_msh.c
@@ -0,0 +1,1225 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-09 wdfk-prog split adc v2 msh command implementation
+ */
+
+/**
+ * @file adc_v2_msh.c
+ * @brief ADC V2 FinSH/MSH command implementation.
+ */
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2) && defined(RT_USING_FINSH) && defined(RT_ADC_V2_USING_MSH)
+
+#include <stdlib.h>
+
+#include <rtdevice.h>
+#include <rtthread.h>
+#include <finsh.h>
+
+#include <drivers/adc_v2.h>
+
+/** @brief Default FinSH temporary read buffer capacity in samples. */
+#define RT_ADC_MSH_VALUE_BUFFER_SIZE 32U
+
+/** @brief Default timeout in milliseconds for ADC MSH sequence read command. */
+#define RT_ADC_MSH_SEQ_DEFAULT_TIMEOUT_MS 1000
+
+/** @brief Default FinSH stream read timeout in milliseconds. */
+#define RT_ADC_MSH_STREAM_READ_TIMEOUT_MS 1000
+
+/** @brief Default FinSH stream DMA buffer capacity in samples. */
+#define RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE 32U
+
+/** @brief Default FIFO storage capacity in samples for the ADC MSH FIFO stream test. */
+#define RT_ADC_MSH_FIFO_TEST_FIFO_BUFFER_SIZE 512U
+
+/**
+ * @brief Print backend-specific ADC FinSH command usage.
+ */
+rt_weak void rt_adc_msh_special_help(void)
+{
+}
+
+/**
+ * @brief Handle backend-specific ADC FinSH commands.
+ * @param device Pointer to the selected ADC device object.
+ * @param argc Argument count excluding the top-level adc command.
+ * @param argv Argument vector excluding the top-level adc command.
+ * @return Operation status.
+ */
+rt_weak rt_err_t rt_adc_msh_special(rt_adc_device_t device, int argc, char **argv)
+{
+ RT_UNUSED(device);
+ RT_UNUSED(argc);
+ RT_UNUSED(argv);
+
+ return -RT_ENOSYS;
+}
+
+#if defined(RT_ADC_USING_TRIGGER)
+/**
+ * @brief Print ADC trigger MSH command usage.
+ */
+static void adc_msh_usage_trigger(void)
+{
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ rt_kprintf(" adc trigger set timer_update <timer_device> <freq_hz>\n");
+ rt_kprintf(" adc trigger set timer_compare <timer_device> <timer_ch> <freq_hz>\n");
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+#if defined(RT_ADC_TRIGGER_USING_COMPARE)
+ rt_kprintf(" adc trigger set compare [comparator_device] <num> <rising|falling|both>, num: 0~31\n");
+#endif /* defined(RT_ADC_TRIGGER_USING_COMPARE) */
+ rt_kprintf(" adc trigger clear\n");
+ rt_kprintf(" adc trigger status\n");
+}
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#if defined(RT_ADC_USING_STREAM)
+/**
+ * @brief Print ADC stream MSH command usage.
+ */
+static void adc_msh_usage_stream(void)
+{
+ rt_kprintf(" adc stream start <num0> [num1 ...], num: 0~31\n");
+ rt_kprintf(" adc stream read [timeout_ms]\n");
+ rt_kprintf(" adc stream cancel\n");
+ rt_kprintf(" adc stream stop\n");
+#if defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO)
+ rt_kprintf(" adc fifo <timeout_ms> <num0> [num1 ...]\n");
+#endif /* defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO) */
+}
+#endif /* defined(RT_ADC_USING_STREAM) */
+
+/**
+ * @brief Print ADC FinSH command usage.
+ */
+static void adc_msh_usage(void)
+{
+ rt_kprintf("Usage:\n");
+ rt_kprintf(" adc probe <device>\n");
+ rt_kprintf(" adc close\n");
+ rt_kprintf(" adc config <num0> [num1 ...], num: 0~31, eg: 0 1 10\n");
+ rt_kprintf(" adc read\n");
+ rt_kprintf(" adc voltage <timeout_ms>\n");
+ rt_kprintf(" voltage reads the current session configured by adc config\n");
+ rt_kprintf(" if default_vref is absent, adc config must include the backend VREF channel\n");
+ rt_kprintf(" adc seq <timeout_ms> <num0> [num1 ...], num: 0~31, eg: 0 1 10\n");
+#if defined(RT_ADC_USING_TRIGGER)
+ adc_msh_usage_trigger();
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#if defined(RT_ADC_USING_STREAM)
+ adc_msh_usage_stream();
+#endif /* defined(RT_ADC_USING_STREAM) */
+
+ rt_adc_msh_special_help();
+}
+
+/**
+ * @brief Convert one shell argument to a single-channel mask.
+ * @param arg Pointer to the shell argument string.
+ * @param channels Pointer to the output channel mask.
+ * @return Operation status.
+ */
+static rt_err_t adc_msh_parse_channel_mask(const char *arg, rt_uint32_t *channels)
+{
+ char *endptr;
+ unsigned long value;
+
+ if ((*arg == '\0') || (*arg == '-'))
+ {
+ return -RT_EINVAL;
+ }
+
+ endptr = RT_NULL;
+ value = strtoul(arg, &endptr, 0);
+ if ((endptr == arg) || (endptr == RT_NULL) || (*endptr != '\0') || (value >= 32UL))
+ {
+ return -RT_EINVAL;
+ }
+
+ *channels = RT_ADC_CHANNEL_MASK(value);
+ return RT_EOK;
+}
+
+/**
+ * @brief Convert one shell argument to a timeout value.
+ * @param arg Pointer to the shell argument string.
+ * @return Timeout in milliseconds; negative means wait forever.
+ *
+ * @note This command keeps the permissive MSH parsing convention: strtol()
+ * is used without endptr validation, so a non-numeric string with no
+ * converted digits is treated as 0 by the C library conversion path. A
+ * timeout value of 0 means non-blocking/immediate timeout.
+ */
+static rt_int32_t adc_msh_parse_timeout(const char *arg)
+{
+ return (rt_int32_t)strtol(arg, RT_NULL, 0);
+}
+
+#if defined(RT_ADC_USING_TRIGGER) && (defined(RT_ADC_TRIGGER_USING_TIMER) || defined(RT_ADC_TRIGGER_USING_COMPARE))
+/**
+ * @brief Convert one shell argument to an unsigned integer.
+ * @param arg Pointer to the shell argument string.
+ * @param max_value Maximum accepted value.
+ * @param value Pointer to the output value.
+ * @return Operation status.
+ */
+static rt_err_t adc_msh_parse_ulong(const char *arg, unsigned long max_value, unsigned long *value)
+{
+ char *endptr;
+ unsigned long parsed;
+
+ if ((arg == RT_NULL) || (value == RT_NULL) || (*arg == '\0') || (*arg == '-'))
+ {
+ return -RT_EINVAL;
+ }
+
+ endptr = RT_NULL;
+ parsed = strtoul(arg, &endptr, 0);
+ if ((endptr == arg) || (endptr == RT_NULL) || (*endptr != '\0') || (parsed > max_value))
+ {
+ return -RT_EINVAL;
+ }
+
+ *value = parsed;
+ return RT_EOK;
+}
+
+#if defined(RT_ADC_TRIGGER_USING_COMPARE)
+/**
+ * @brief Convert one shell argument to an ADC trigger edge selector.
+ * @param arg Pointer to the shell argument string.
+ * @param edge Pointer to the output trigger edge selector.
+ * @return Operation status.
+ */
+static rt_err_t adc_msh_parse_trigger_edge(const char *arg, enum rt_adc_trigger_edge *edge)
+{
+ if ((arg == RT_NULL) || (edge == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!rt_strcmp(arg, "rising"))
+ {
+ *edge = RT_ADC_TRIGGER_EDGE_RISING;
+ return RT_EOK;
+ }
+
+ if (!rt_strcmp(arg, "falling"))
+ {
+ *edge = RT_ADC_TRIGGER_EDGE_FALLING;
+ return RT_EOK;
+ }
+
+ if (!rt_strcmp(arg, "both"))
+ {
+ *edge = RT_ADC_TRIGGER_EDGE_BOTH;
+ return RT_EOK;
+ }
+
+ return -RT_EINVAL;
+}
+
+#endif /* defined(RT_ADC_TRIGGER_USING_COMPARE) */
+
+/**
+ * @brief Find one trigger source device by shell argument.
+ * @param name Pointer to the source device name string.
+ * @param source Pointer to the output source device object.
+ * @return Operation status.
+ */
+static rt_err_t adc_msh_find_trigger_source(const char *name, rt_device_t *source)
+{
+ rt_device_t dev;
+
+ if ((name == RT_NULL) || (source == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ dev = rt_device_find(name);
+ if (dev == RT_NULL)
+ {
+ rt_kprintf("trigger source %s not found\n", name);
+ return -RT_ERROR;
+ }
+
+ *source = dev;
+ return RT_EOK;
+}
+#endif /* defined(RT_ADC_USING_TRIGGER) && (defined(RT_ADC_TRIGGER_USING_TIMER) || defined(RT_ADC_TRIGGER_USING_COMPARE)) */
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief Clear the FinSH stream scratch buffer owner.
+ * @param stream_device Pointer to the saved stream device owner.
+ */
+static void adc_msh_clear_stream_owner(rt_adc_device_t *stream_device)
+{
+ if (stream_device != RT_NULL)
+ {
+ *stream_device = RT_NULL;
+ }
+}
+
+/**
+ * @brief Get the current ADC framework state for the FinSH command.
+ * @param device Pointer to the ADC device object.
+ * @return Current ADC runtime state.
+ */
+static enum rt_adc_state adc_msh_get_state(rt_adc_device_t device)
+{
+ return (enum rt_adc_state)rt_atomic_load(&device->state);
+}
+
+/**
+ * @brief Check whether the FinSH stream scratch buffer is still owned by an active stream.
+ * @param stream_device Saved stream device owner.
+ * @return RT_TRUE if the stream buffer is still owned by an active stream.
+ */
+static rt_bool_t adc_msh_stream_buffer_is_active(rt_adc_device_t stream_device)
+{
+ if (stream_device == RT_NULL)
+ {
+ return RT_FALSE;
+ }
+
+ return (adc_msh_get_state(stream_device) == RT_ADC_STATE_STREAM) ? RT_TRUE : RT_FALSE;
+}
+#endif /* RT_ADC_USING_STREAM */
+
+static rt_adc_device_t device = RT_NULL;
+#ifdef RT_ADC_USING_STREAM
+static rt_adc_device_t stream_device = RT_NULL;
+static rt_uint32_t stream_dma_buffer[RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE];
+#if defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO)
+static rt_uint32_t stream_fifo_buffer[RT_ADC_MSH_FIFO_TEST_FIFO_BUFFER_SIZE];
+#endif /* defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO) */
+#endif /* RT_ADC_USING_STREAM */
+
+
+#if defined(RT_ADC_USING_TRIGGER)
+/**
+ * @brief Handle ADC trigger subcommands.
+ * @param device Pointer to the selected ADC device object.
+ * @param argc Argument count excluding "adc trigger".
+ * @param argv Argument vector excluding "adc trigger".
+ * @return Command status.
+ */
+static rt_err_t adc_msh_trigger(rt_adc_device_t device, int argc, char **argv)
+{
+ rt_err_t result;
+
+ if (argc < 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if (!rt_strcmp(argv[0], "clear"))
+ {
+ if (argc != 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ result = rt_adc_trigger_clear(device);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("adc trigger cleared\n");
+ }
+ return result;
+ }
+
+ if (!rt_strcmp(argv[0], "status"))
+ {
+ if (argc != 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ rt_kprintf("adc trigger: %s\n", rt_adc_trigger_is_set(device) == RT_TRUE ? "set" : "clear");
+ return RT_EOK;
+ }
+
+ if (!rt_strcmp(argv[0], "set"))
+ {
+ struct rt_adc_trigger_cfg trigger_cfg;
+
+ if (argc < 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ rt_memset(&trigger_cfg, 0, sizeof(trigger_cfg));
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ if (!rt_strcmp(argv[1], "timer_update"))
+ {
+ unsigned long freq_hz;
+
+ if (argc != 4)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ result = adc_msh_find_trigger_source(argv[2], &trigger_cfg.event.timer.timer);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = adc_msh_parse_ulong(argv[3], 0xffffffffUL, &freq_hz);
+ if ((result != RT_EOK) || (freq_hz == 0UL))
+ {
+ rt_kprintf("invalid adc trigger timer frequency: %s\n", argv[3]);
+ return (result != RT_EOK) ? result : -RT_EINVAL;
+ }
+
+ trigger_cfg.type = RT_ADC_TRIGGER_TIMER_UPDATE;
+ trigger_cfg.event.timer.freq_hz = (rt_uint32_t)freq_hz;
+ trigger_cfg.event.timer.channel = 0U;
+ }
+ else if (!rt_strcmp(argv[1], "timer_compare"))
+ {
+ unsigned long channel;
+ unsigned long freq_hz;
+
+ if (argc != 5)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ result = adc_msh_find_trigger_source(argv[2], &trigger_cfg.event.timer.timer);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = adc_msh_parse_ulong(argv[3], 65535UL, &channel);
+ if ((result != RT_EOK) || (channel == 0UL))
+ {
+ rt_kprintf("invalid adc trigger timer channel: %s\n", argv[3]);
+ return (result != RT_EOK) ? result : -RT_EINVAL;
+ }
+
+ result = adc_msh_parse_ulong(argv[4], 0xffffffffUL, &freq_hz);
+ if ((result != RT_EOK) || (freq_hz == 0UL))
+ {
+ rt_kprintf("invalid adc trigger timer frequency: %s\n", argv[4]);
+ return (result != RT_EOK) ? result : -RT_EINVAL;
+ }
+
+ trigger_cfg.type = RT_ADC_TRIGGER_TIMER_COMPARE;
+ trigger_cfg.event.timer.freq_hz = (rt_uint32_t)freq_hz;
+ trigger_cfg.event.timer.channel = (rt_uint16_t)channel;
+ }
+ else
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+#if defined(RT_ADC_TRIGGER_USING_COMPARE)
+ if (!rt_strcmp(argv[1], "compare"))
+ {
+ unsigned long channel;
+ int channel_arg;
+ int edge_arg;
+
+ if ((argc != 4) && (argc != 5))
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if (argc == 5)
+ {
+ result = adc_msh_find_trigger_source(argv[2], &trigger_cfg.event.compare.comparator);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+ channel_arg = 3;
+ edge_arg = 4;
+ }
+ else
+ {
+ channel_arg = 2;
+ edge_arg = 3;
+ }
+
+ result = adc_msh_parse_ulong(argv[channel_arg], 65535UL, &channel);
+ if ((result != RT_EOK) || (channel == 0UL))
+ {
+ rt_kprintf("invalid adc trigger compare channel: %s\n", argv[channel_arg]);
+ return (result != RT_EOK) ? result : -RT_EINVAL;
+ }
+
+ result = adc_msh_parse_trigger_edge(argv[edge_arg], &trigger_cfg.event.compare.edge);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("invalid adc trigger edge: %s\n", argv[edge_arg]);
+ return result;
+ }
+
+ trigger_cfg.type = RT_ADC_TRIGGER_ANALOG_COMPARE;
+ trigger_cfg.event.compare.channel = (rt_uint16_t)channel;
+ }
+ else
+#endif /* defined(RT_ADC_TRIGGER_USING_COMPARE) */
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ result = rt_adc_trigger_set(device, &trigger_cfg);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("adc trigger set: %s\n", argv[1]);
+ }
+ return result;
+ }
+
+ adc_msh_usage();
+ return -RT_EINVAL;
+}
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief Handle ADC stream subcommands.
+ * @param device Pointer to the selected ADC device object.
+ * @param argc Argument count excluding "adc stream".
+ * @param argv Argument vector excluding "adc stream".
+ * @return Command status.
+ */
+static rt_err_t adc_msh_stream(rt_adc_device_t device, int argc, char **argv)
+{
+ rt_uint32_t values[RT_ADC_MSH_VALUE_BUFFER_SIZE];
+ rt_size_t count;
+ rt_size_t index;
+ rt_err_t result;
+
+ if (argc < 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if (!rt_strcmp(argv[0], "start"))
+ {
+#ifndef RT_ADC_STREAM_USING_LATEST
+ return -RT_ENOSYS;
+#else
+ struct rt_adc_stream_cfg stream_cfg;
+ rt_uint32_t channels;
+ rt_uint32_t channel_mask;
+
+ if (argc < 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if (adc_msh_get_state(device) == RT_ADC_STATE_STREAM)
+ {
+ rt_kprintf("adc stream is already running, stop it first\n");
+ return -RT_EBUSY;
+ }
+
+ channels = 0U;
+ for (index = 0U; index < (rt_size_t)(argc - 1); index++)
+ {
+ result = adc_msh_parse_channel_mask(argv[index + 1], &channel_mask);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("invalid adc channel: %s\n", argv[index + 1]);
+ return result;
+ }
+ channels |= channel_mask;
+ }
+
+ count = rt_adc_channel_mask_count(channels);
+ if (count == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (adc_msh_stream_buffer_is_active(stream_device) == RT_TRUE)
+ {
+ rt_kprintf("adc stream is already running, stop it first\n");
+ return -RT_EBUSY;
+ }
+ adc_msh_clear_stream_owner(&stream_device);
+
+ if (count > RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE)
+ {
+ rt_kprintf("adc stream buffer too large, max %u samples\n", (unsigned int)RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE);
+ return -RT_EINVAL;
+ }
+
+ rt_memset(&stream_cfg, 0, sizeof(stream_cfg));
+ stream_cfg.policy = RT_ADC_STREAM_POLICY_LATEST;
+ stream_cfg.dma_event_mode = RT_ADC_STREAM_DMA_EVENT_AUTO;
+ stream_cfg.dma_buffer = stream_dma_buffer;
+ stream_cfg.dma_buffer_length = count;
+
+ result = rt_adc_stream_start(device, channels, &stream_cfg);
+ if (result == RT_EOK)
+ {
+ stream_device = device;
+ }
+ else if (adc_msh_get_state(device) == RT_ADC_STATE_STREAM)
+ {
+ stream_device = device;
+ rt_kprintf("adc stream start failed but stream hardware may still be running, stop it first\n");
+ }
+ else
+ {
+ adc_msh_clear_stream_owner(&stream_device);
+ }
+ return result;
+#endif /* RT_ADC_STREAM_USING_LATEST */
+ }
+
+ if (!rt_strcmp(argv[0], "read"))
+ {
+ rt_ssize_t read_count;
+ rt_int32_t timeout_ms;
+
+ if (argc > 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if ((stream_device != RT_NULL) && (stream_device != device))
+ {
+ rt_kprintf("adc stream belongs to another device\n");
+ return -RT_EBUSY;
+ }
+
+ if (adc_msh_get_state(device) != RT_ADC_STATE_STREAM)
+ {
+ rt_kprintf("adc stream is not running\n");
+ return -RT_EINVAL;
+ }
+
+ count = device->stream_ctrl.frame_length;
+ if (count == 0U)
+ {
+ rt_kprintf("adc stream channel count is zero\n");
+ return -RT_EINVAL;
+ }
+
+ if (count > RT_ADC_MSH_VALUE_BUFFER_SIZE)
+ {
+ rt_kprintf("adc stream read count too large, max %u samples\n", (unsigned int)RT_ADC_MSH_VALUE_BUFFER_SIZE);
+ return -RT_EINVAL;
+ }
+
+ timeout_ms = (argc == 2) ? adc_msh_parse_timeout(argv[1]) : RT_ADC_MSH_STREAM_READ_TIMEOUT_MS;
+ read_count = rt_adc_stream_read(device, values, count, timeout_ms);
+ if (read_count > 0)
+ {
+ for (index = 0U; index < (rt_size_t)read_count; index++)
+ {
+ rt_kprintf("[%u]=%lu\n", (unsigned int)index, (unsigned long)values[index]);
+ }
+ }
+
+ return (read_count >= 0) ? RT_EOK : (rt_err_t)read_count;
+ }
+
+ if (!rt_strcmp(argv[0], "stop"))
+ {
+ if (argc != 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if ((stream_device != RT_NULL) && (stream_device != device))
+ {
+ rt_kprintf("adc stream belongs to another device\n");
+ return -RT_EBUSY;
+ }
+
+ result = rt_adc_stream_stop(device);
+ if (result == RT_EOK)
+ {
+ adc_msh_clear_stream_owner(&stream_device);
+ }
+ return result;
+ }
+
+ if (!rt_strcmp(argv[0], "cancel"))
+ {
+ if (argc != 1)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if ((stream_device != RT_NULL) && (stream_device != device))
+ {
+ rt_kprintf("adc stream belongs to another device\n");
+ return -RT_EBUSY;
+ }
+
+ return rt_adc_stream_cancel(device);
+ }
+
+ adc_msh_usage();
+ return -RT_EINVAL;
+}
+#endif /* RT_ADC_USING_STREAM */
+
+#if defined(RT_ADC_USING_STREAM) && defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO)
+#define RT_ADC_MSH_FIFO_TEST_READ_FRAME_COUNT 16U
+#define RT_ADC_MSH_FIFO_TEST_READ_TIMEOUT_MS 1000
+/**
+ * @brief Handle the ADC FIFO stream test command.
+ * @param device Pointer to the selected ADC device object.
+ * @param argc Argument count excluding "adc fifo".
+ * @param argv Argument vector excluding "adc fifo".
+ * @return Command status.
+ */
+static rt_err_t adc_msh_fifo_test(rt_adc_device_t device, int argc, char **argv)
+{
+ struct rt_adc_stream_cfg stream_cfg;
+ rt_uint32_t *buffer;
+ rt_uint32_t channels;
+ rt_uint32_t channel_mask;
+ rt_size_t channel_count;
+ rt_size_t sample_count;
+ rt_size_t dma_buffer_length;
+ rt_size_t fifo_buffer_length;
+ rt_size_t read_times;
+ rt_size_t index;
+ rt_size_t full_count;
+ rt_size_t partial_count;
+ rt_size_t timeout_count;
+ rt_size_t error_count;
+ rt_size_t total_samples;
+ rt_tick_t begin_tick;
+ rt_tick_t end_tick;
+ rt_tick_t timeout_tick;
+ rt_int32_t timeout_ms;
+ rt_err_t result;
+ rt_err_t stop_result;
+
+ if (argc < 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ timeout_ms = adc_msh_parse_timeout(argv[0]);
+ if (timeout_ms <= 0)
+ {
+ rt_kprintf("fifo test timeout_ms must be greater than 0\n");
+ return -RT_EINVAL;
+ }
+
+ if (adc_msh_get_state(device) == RT_ADC_STATE_STREAM)
+ {
+ rt_kprintf("adc stream is already running, stop it first\n");
+ return -RT_EBUSY;
+ }
+
+ if (adc_msh_stream_buffer_is_active(stream_device) == RT_TRUE)
+ {
+ rt_kprintf("adc stream is already running, stop it first\n");
+ return -RT_EBUSY;
+ }
+ adc_msh_clear_stream_owner(&stream_device);
+
+ channels = 0U;
+ for (index = 0U; index < (rt_size_t)(argc - 1); index++)
+ {
+ result = adc_msh_parse_channel_mask(argv[index + 1], &channel_mask);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("invalid adc channel: %s\n", argv[index + 1]);
+ return result;
+ }
+ channels |= channel_mask;
+ }
+
+ channel_count = rt_adc_channel_mask_count(channels);
+ if (channel_count == 0U)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE < (channel_count * 2U))
+ {
+ rt_kprintf("adc fifo test dma buffer too small, min %u samples\n", (unsigned int)(channel_count * 2U));
+ return -RT_EINVAL;
+ }
+
+ sample_count = channel_count * RT_ADC_MSH_FIFO_TEST_READ_FRAME_COUNT;
+ if ((sample_count == 0U) || (sample_count > (((rt_size_t)-1) / sizeof(rt_uint32_t))))
+ {
+ rt_kprintf("adc fifo test read sample count is too large\n");
+ return -RT_EINVAL;
+ }
+
+ dma_buffer_length = (RT_ADC_MSH_STREAM_DMA_BUFFER_SIZE / (channel_count * 2U)) * (channel_count * 2U);
+ fifo_buffer_length = (RT_ADC_MSH_FIFO_TEST_FIFO_BUFFER_SIZE / channel_count) * channel_count;
+ if (fifo_buffer_length < (dma_buffer_length / 2U))
+ {
+ rt_kprintf("adc fifo test fifo buffer too small, min %u samples\n", (unsigned int)(dma_buffer_length / 2U));
+ return -RT_EINVAL;
+ }
+
+ buffer = (rt_uint32_t *)rt_malloc(sample_count * sizeof(rt_uint32_t));
+ if (buffer == RT_NULL)
+ {
+ rt_kprintf("no memory for fifo test buffer\n");
+ return -RT_ENOMEM;
+ }
+
+ rt_memset(&stream_cfg, 0, sizeof(stream_cfg));
+ stream_cfg.policy = RT_ADC_STREAM_POLICY_FIFO;
+ stream_cfg.dma_event_mode = RT_ADC_STREAM_DMA_EVENT_HALF_FULL;
+ stream_cfg.dma_buffer = stream_dma_buffer;
+ stream_cfg.dma_buffer_length = dma_buffer_length;
+ stream_cfg.fifo_buffer = stream_fifo_buffer;
+ stream_cfg.fifo_buffer_length = fifo_buffer_length;
+ stream_cfg.watermark = dma_buffer_length / 2U;
+
+ result = rt_adc_stream_start_frame_aligned_fifo(device, channels, &stream_cfg);
+ if (result != RT_EOK)
+ {
+ rt_free(buffer);
+ return result;
+ }
+ stream_device = device;
+
+ result = RT_EOK;
+ read_times = 0U;
+ full_count = 0U;
+ partial_count = 0U;
+ timeout_count = 0U;
+ error_count = 0U;
+ total_samples = 0U;
+ begin_tick = rt_tick_get();
+ timeout_tick = rt_tick_from_millisecond(timeout_ms);
+
+ while (rt_tick_get_delta(begin_tick) < timeout_tick)
+ {
+ rt_ssize_t read_count;
+
+ read_count = rt_adc_stream_read(device, buffer, sample_count, RT_ADC_MSH_FIFO_TEST_READ_TIMEOUT_MS);
+ read_times++;
+ if (read_count < 0)
+ {
+ if (read_count == -RT_ETIMEOUT)
+ {
+ timeout_count++;
+ continue;
+ }
+
+ result = (rt_err_t)read_count;
+ error_count++;
+ rt_kprintf("stream fifo test failed at %u: %d\n", (unsigned int)read_times, (int)read_count);
+ break;
+ }
+
+ total_samples += (rt_size_t)read_count;
+ if ((rt_size_t)read_count == sample_count)
+ {
+ full_count++;
+ }
+ else
+ {
+ partial_count++;
+ }
+ }
+
+ end_tick = rt_tick_get();
+ stop_result = rt_adc_stream_stop(device);
+ if (stop_result == RT_EOK)
+ {
+ adc_msh_clear_stream_owner(&stream_device);
+ }
+
+ rt_size_t elapsed_tick;
+ rt_size_t total_frames;
+ rt_size_t read_frames;
+ rt_size_t dma_frames;
+ rt_size_t fifo_frames;
+ rt_size_t frame_rate;
+ rt_size_t sample_rate_per_channel;
+
+ elapsed_tick = end_tick - begin_tick;
+ total_frames = total_samples / channel_count;
+ read_frames = sample_count / channel_count;
+ dma_frames = dma_buffer_length / channel_count;
+ fifo_frames = fifo_buffer_length / channel_count;
+
+ if (elapsed_tick > 0U)
+ {
+ frame_rate = (total_frames * RT_TICK_PER_SECOND) / elapsed_tick;
+ sample_rate_per_channel = frame_rate;
+ }
+ else
+ {
+ frame_rate = 0U;
+ sample_rate_per_channel = 0U;
+ }
+
+ rt_kprintf("adc fifo_test: %s\n", (error_count == 0U && timeout_count == 0U && partial_count == 0U) ? "PASS" : "FAIL");
+ rt_kprintf(" duration : %d ms\n", (int)timeout_ms);
+ rt_kprintf(" channels : %u\n", (unsigned int)channel_count);
+ rt_kprintf(" read block : %u frames, %u samples\n",
+ (unsigned int)read_frames, (unsigned int)sample_count);
+ rt_kprintf(" dma buffer : %u frames, %u samples\n",
+ (unsigned int)dma_frames, (unsigned int)dma_buffer_length);
+ rt_kprintf(" fifo buffer : %u frames, %u samples\n",
+ (unsigned int)fifo_frames, (unsigned int)fifo_buffer_length);
+ rt_kprintf(" read count : %u\n", (unsigned int)read_times);
+ rt_kprintf(" full reads : %u\n", (unsigned int)full_count);
+ rt_kprintf(" partial reads : %u\n", (unsigned int)partial_count);
+ rt_kprintf(" timeouts : %u\n", (unsigned int)timeout_count);
+ rt_kprintf(" errors : %u\n", (unsigned int)error_count);
+ rt_kprintf(" total frames : %u\n", (unsigned int)total_frames);
+ rt_kprintf(" total samples : %u\n", (unsigned int)total_samples);
+ rt_kprintf(" frame rate : %u frames/s\n", (unsigned int)frame_rate);
+ rt_kprintf(" sample rate/ch : %u samples/s\n", (unsigned int)sample_rate_per_channel);
+ rt_kprintf(" elapsed tick : %u\n", (unsigned int)elapsed_tick);
+
+ rt_free(buffer);
+ if (error_count > 0U)
+ {
+ return result;
+ }
+
+ if (timeout_count > 0U)
+ {
+ return -RT_ETIMEOUT;
+ }
+
+ return stop_result;
+}
+#endif /* defined(RT_ADC_USING_STREAM) && defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO) */
+
+/**
+ * @brief Handle the ADC FinSH command.
+ * @param argc Argument count.
+ * @param argv Argument vector.
+ * @return Command status.
+ */
+static int adc(int argc, char **argv)
+{
+ rt_uint32_t values_buf[RT_ADC_MSH_VALUE_BUFFER_SIZE];
+ rt_uint32_t *values;
+ rt_uint32_t channels;
+ rt_uint32_t channel_mask;
+ rt_size_t index;
+ rt_size_t count;
+ rt_ssize_t read_count;
+ rt_err_t result;
+
+ if (argc < 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ values = values_buf;
+ if (!rt_strcmp(argv[1], "probe"))
+ {
+ rt_device_t new_dev;
+ rt_adc_device_t new_device;
+
+ if (argc != 3)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+#ifdef RT_ADC_USING_STREAM
+ if (adc_msh_stream_buffer_is_active(stream_device) == RT_TRUE)
+ {
+ rt_kprintf("adc stream is running, stop it first\n");
+ return -RT_EBUSY;
+ }
+ adc_msh_clear_stream_owner(&stream_device);
+#endif /* RT_ADC_USING_STREAM */
+
+ new_dev = rt_device_find(argv[2]);
+ if (new_dev == RT_NULL)
+ {
+ rt_kprintf("adc device %s not found\n", argv[2]);
+ return -RT_ERROR;
+ }
+
+ if (new_dev->type != RT_Device_Class_ADC)
+ {
+ rt_kprintf("%s is not an adc device\n", argv[2]);
+ return -RT_EINVAL;
+ }
+
+ new_device = (rt_adc_device_t)new_dev;
+ if (device == new_device)
+ {
+ rt_kprintf("probe %s: %d\n", argv[2], RT_EOK);
+ return RT_EOK;
+ }
+
+ result = rt_device_open(new_dev, RT_DEVICE_OFLAG_RDWR);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("probe %s failed: %d\n", argv[2], result);
+ return result;
+ }
+
+ if (device != RT_NULL)
+ {
+ rt_err_t close_result;
+
+ close_result = rt_device_close(&device->parent);
+ if (close_result != RT_EOK)
+ {
+ (void)rt_device_close(new_dev);
+ rt_kprintf("close previous adc device %s failed: %d\n", device->parent.parent.name, close_result);
+ return close_result;
+ }
+ }
+
+ device = new_device;
+ rt_kprintf("probe %s: %d\n", argv[2], result);
+ return result;
+ }
+
+ if (device == RT_NULL)
+ {
+ rt_kprintf("no adc device selected\n");
+ return -RT_EINVAL;
+ }
+
+ if (!rt_strcmp(argv[1], "config"))
+ {
+ if (argc < 3)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ channels = 0U;
+ for (index = 0U; index < (rt_size_t)(argc - 2); index++)
+ {
+ result = adc_msh_parse_channel_mask(argv[index + 2], &channel_mask);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("invalid adc channel: %s\n", argv[index + 2]);
+ return result;
+ }
+ channels |= channel_mask;
+ }
+
+ result = rt_device_control(&device->parent, RT_ADC_CMD_SET_SESSION, &channels);
+ if (result == RT_EOK)
+ {
+ rt_kprintf("config channels=0x%08lx count=%u\n",
+ (unsigned long)channels, (unsigned int)rt_adc_channel_mask_count(channels));
+ }
+ return result;
+ }
+
+ if (!rt_strcmp(argv[1], "read"))
+ {
+ if (argc > 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if ((device->session_ctrl.configured != RT_TRUE) || (device->session_ctrl.channel_count == 0U))
+ {
+ rt_kprintf("adc session is not configured, run adc config first\n");
+ return -RT_EINVAL;
+ }
+
+ count = device->session_ctrl.channel_count;
+ if (count > RT_ADC_MSH_VALUE_BUFFER_SIZE)
+ {
+ rt_kprintf("adc read count too large, max %u samples\n", (unsigned int)RT_ADC_MSH_VALUE_BUFFER_SIZE);
+ return -RT_EINVAL;
+ }
+
+ read_count = rt_device_read(&device->parent, 0, values, count);
+ if (read_count < 0)
+ {
+ result = (rt_err_t)read_count;
+ }
+ else if ((rt_size_t)read_count != count)
+ {
+ result = -RT_ERROR;
+ }
+ else
+ {
+ result = RT_EOK;
+ for (index = 0U; index < count; index++)
+ {
+ rt_kprintf("[%u]=%lu\n", (unsigned int)index, (unsigned long)values[index]);
+ }
+ }
+ return result;
+ }
+
+ if (!rt_strcmp(argv[1], "voltage"))
+ {
+ rt_int32_t timeout_ms;
+
+ if (argc != 3)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ if ((device->session_ctrl.configured != RT_TRUE) || (device->session_ctrl.channel_count == 0U))
+ {
+ rt_kprintf("adc session is not configured, run adc config first\n");
+ return -RT_EINVAL;
+ }
+
+ timeout_ms = adc_msh_parse_timeout(argv[2]);
+ count = device->session_ctrl.channel_count;
+ if (count > RT_ADC_MSH_VALUE_BUFFER_SIZE)
+ {
+ rt_kprintf("adc voltage count too large, max %u samples\n", (unsigned int)RT_ADC_MSH_VALUE_BUFFER_SIZE);
+ return -RT_EINVAL;
+ }
+
+ result = rt_adc_voltage(device, values, count, timeout_ms);
+ if (result == RT_EOK)
+ {
+ for (index = 0U; index < count; index++)
+ {
+ rt_kprintf("[%u]=%lu mV\n", (unsigned int)index, (unsigned long)values[index]);
+ }
+ }
+ else if (result == -RT_EINVAL)
+ {
+ rt_kprintf("adc voltage failed, check adc config and VREF channel/default_vref\n");
+ }
+
+ return result;
+ }
+
+ if (!rt_strcmp(argv[1], "seq"))
+ {
+ struct rt_adc_sequence_cfg sequence_cfg;
+ rt_size_t sequence_read_count;
+
+ if (argc < 4)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ channels = 0U;
+ for (index = 0U; index < (rt_size_t)(argc - 3); index++)
+ {
+ result = adc_msh_parse_channel_mask(argv[index + 3], &channel_mask);
+ if (result != RT_EOK)
+ {
+ rt_kprintf("invalid adc channel: %s\n", argv[index + 3]);
+ return result;
+ }
+ channels |= channel_mask;
+ }
+
+ count = rt_adc_channel_mask_count(channels);
+ if (count > RT_ADC_MSH_VALUE_BUFFER_SIZE)
+ {
+ rt_kprintf("adc seq count too large, max %u samples\n", (unsigned int)RT_ADC_MSH_VALUE_BUFFER_SIZE);
+ return -RT_EINVAL;
+ }
+
+ rt_memset(&sequence_cfg, 0, sizeof(sequence_cfg));
+ sequence_cfg.buffer = values;
+ sequence_cfg.buffer_length = count;
+ sequence_cfg.timeout_ms = adc_msh_parse_timeout(argv[2]);
+
+ result = rt_adc_read_sequence(device, channels, &sequence_cfg, &sequence_read_count);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ for (index = 0U; index < sequence_read_count; index++)
+ {
+ rt_kprintf("[%u]=%lu\n", (unsigned int)index, (unsigned long)values[index]);
+ }
+
+ return RT_EOK;
+ }
+
+#if defined(RT_ADC_USING_TRIGGER)
+ if (!rt_strcmp(argv[1], "trigger"))
+ {
+ return adc_msh_trigger(device, argc - 2, &argv[2]);
+ }
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ if (!rt_strcmp(argv[1], "close"))
+ {
+ rt_err_t close_result;
+
+ if (argc > 2)
+ {
+ adc_msh_usage();
+ return -RT_EINVAL;
+ }
+
+ close_result = rt_device_close(&device->parent);
+ if (close_result != RT_EOK)
+ {
+ rt_kprintf("close adc device %s failed: %d\n", device->parent.parent.name, close_result);
+ return close_result;
+ }
+
+ rt_kprintf("close %s: %d\n", device->parent.parent.name, close_result);
+ device = RT_NULL;
+ return RT_EOK;
+ }
+
+#ifdef RT_ADC_USING_STREAM
+ if (!rt_strcmp(argv[1], "stream"))
+ {
+ return adc_msh_stream(device, argc - 2, &argv[2]);
+ }
+
+#if defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO)
+ if (!rt_strcmp(argv[1], "fifo"))
+ {
+ return adc_msh_fifo_test(device, argc - 2, &argv[2]);
+ }
+#endif /* defined(RT_ADC_MSH_USING_FIFO_TEST) && defined(RT_ADC_STREAM_USING_FIFO) */
+#endif /* RT_ADC_USING_STREAM */
+
+ result = rt_adc_msh_special(device, argc - 1, &argv[1]);
+ if (result != -RT_ENOSYS)
+ {
+ return result;
+ }
+
+ adc_msh_usage();
+ return -RT_EINVAL;
+}
+MSH_CMD_EXPORT(adc, adc v2 command);
+#endif /* defined(RT_USING_ADC_V2) && defined(RT_USING_FINSH) && defined(RT_ADC_V2_USING_MSH) */
diff --git a/components/drivers/adc/adc_v2_trigger.c b/components/drivers/adc/adc_v2_trigger.c
new file mode 100644
index 0000000000..0521201c49
--- /dev/null
+++ b/components/drivers/adc/adc_v2_trigger.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-20 wdfk-prog add ADC V2 timer trigger framework implementation
+ */
+
+/**
+ * @file adc_v2_trigger.c
+ * @brief ADC V2 trigger framework implementation.
+ */
+
+#include <rtconfig.h>
+
+#if defined(RT_USING_ADC_V2) && defined(RT_ADC_USING_TRIGGER)
+
+#include <rtdevice.h>
+#include <rtthread.h>
+#if defined(RT_ADC_TRIGGER_USING_TIMER) && defined(RT_USING_CLOCK_TIMER_TRIGGER)
+#include <drivers/clock_time.h>
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) && defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+
+#define DBG_TAG "adc.v2.trigger"
+#define DBG_LVL DBG_LOG
+#include <rtdbg.h>
+
+#include "adc_v2_internal.h"
+
+/**
+ * @brief Validate an ADC hardware trigger configuration at framework level.
+ * @param cfg Pointer to the trigger configuration object.
+ * @return Operation status.
+ */
+static rt_err_t adc_validate_trigger_cfg_common(const struct rt_adc_trigger_cfg *cfg)
+{
+ switch (cfg->type)
+ {
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ if ((cfg->event.timer.timer == RT_NULL) || (cfg->event.timer.timer->type != RT_Device_Class_Timer) ||
+ (cfg->event.timer.freq_hz == 0U))
+ {
+ return -RT_EINVAL;
+ }
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ if ((cfg->event.timer.timer == RT_NULL) || (cfg->event.timer.timer->type != RT_Device_Class_Timer) ||
+ (cfg->event.timer.channel == 0U) || (cfg->event.timer.freq_hz == 0U))
+ {
+ return -RT_EINVAL;
+ }
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+
+ case RT_ADC_TRIGGER_ANALOG_COMPARE:
+#if defined(RT_ADC_TRIGGER_USING_COMPARE)
+ if ((cfg->event.compare.channel == 0U) || (cfg->event.compare.edge == RT_ADC_TRIGGER_EDGE_NONE))
+ {
+ return -RT_EINVAL;
+ }
+ return RT_EOK;
+#else
+ return -RT_ENOSYS;
+#endif /* defined(RT_ADC_TRIGGER_USING_COMPARE) */
+
+ case RT_ADC_TRIGGER_PWM_EDGE:
+ case RT_ADC_TRIGGER_EXTI_EDGE:
+ case RT_ADC_TRIGGER_BACKEND:
+ return -RT_ENOSYS;
+
+ default:
+ return -RT_EINVAL;
+ }
+}
+
+/**
+ * @brief Initialize the ADC trigger control state to software-started mode.
+ * @param device Pointer to the ADC device object.
+ */
+void adc_trigger_init(rt_adc_device_t device)
+{
+ rt_memset(&device->trigger_ctrl, 0, sizeof(device->trigger_ctrl));
+}
+
+/**
+ * @brief Get the active device-level ADC trigger configuration.
+ * @param device Pointer to the ADC device object.
+ * @return Pointer to the cached trigger configuration, or RT_NULL when no hardware trigger is configured.
+ */
+const struct rt_adc_trigger_cfg *adc_trigger_active_get(rt_adc_device_t device)
+{
+ if (device->trigger_ctrl.configured != RT_TRUE)
+ {
+ return RT_NULL;
+ }
+
+ return &device->trigger_ctrl.cfg;
+}
+
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+/**
+ * @brief Configure and start a timer-based ADC trigger source.
+ * @param cfg Pointer to the active ADC trigger configuration object.
+ * @return Operation status.
+ */
+static rt_err_t adc_trigger_timer_source_start(const struct rt_adc_trigger_cfg *cfg)
+{
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+ struct rt_clock_timer_trigger_cfg timer_cfg = {0};
+ rt_err_t result;
+
+ timer_cfg.freq_hz = cfg->event.timer.freq_hz;
+ timer_cfg.channel = cfg->event.timer.channel;
+
+ switch (cfg->type)
+ {
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+ timer_cfg.event = CLOCK_TIMER_TRIGGER_EVENT_UPDATE;
+ timer_cfg.channel = 0U;
+ break;
+
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+ timer_cfg.event = CLOCK_TIMER_TRIGGER_EVENT_COMPARE;
+ break;
+
+ default:
+ return -RT_ENOSYS;
+ }
+
+ result = rt_device_control(cfg->event.timer.timer, CLOCK_TIMER_CTRL_TRIGGER_CONFIG, &timer_cfg);
+ if (result != RT_EOK)
+ {
+ return result;
+ }
+
+ result = rt_device_control(cfg->event.timer.timer, CLOCK_TIMER_CTRL_TRIGGER_START, RT_NULL);
+ if (result != RT_EOK)
+ {
+ (void)rt_device_control(cfg->event.timer.timer, CLOCK_TIMER_CTRL_TRIGGER_RELEASE, RT_NULL);
+ return result;
+ }
+
+ return RT_EOK;
+#else
+ RT_UNUSED(cfg);
+ return -RT_ENOSYS;
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+}
+
+/**
+ * @brief Stop and release a timer-based ADC trigger source.
+ * @param cfg Pointer to the active ADC trigger configuration object.
+ * @return Operation status.
+ */
+static rt_err_t adc_trigger_timer_source_stop(const struct rt_adc_trigger_cfg *cfg)
+{
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+ rt_err_t stop_result;
+ rt_err_t release_result;
+
+ if ((cfg->type != RT_ADC_TRIGGER_TIMER_UPDATE) && (cfg->type != RT_ADC_TRIGGER_TIMER_COMPARE))
+ {
+ return -RT_ENOSYS;
+ }
+
+ stop_result = rt_device_control(cfg->event.timer.timer, CLOCK_TIMER_CTRL_TRIGGER_STOP, RT_NULL);
+ release_result = rt_device_control(cfg->event.timer.timer, CLOCK_TIMER_CTRL_TRIGGER_RELEASE, RT_NULL);
+
+ return (release_result != RT_EOK) ? release_result : stop_result;
+#else
+ RT_UNUSED(cfg);
+ return -RT_ENOSYS;
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+}
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+
+/**
+ * @brief Start the active trigger source after the ADC conversion path is armed.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t adc_trigger_source_start(rt_adc_device_t device)
+{
+ const struct rt_adc_trigger_cfg *cfg;
+
+ cfg = adc_trigger_active_get(device);
+ if (cfg == RT_NULL)
+ {
+ return RT_EOK;
+ }
+
+ switch (cfg->type)
+ {
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+ return adc_trigger_timer_source_start(cfg);
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+
+ default:
+ return RT_EOK;
+ }
+}
+
+/**
+ * @brief Stop the active trigger source before the ADC conversion path is disarmed.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+static rt_err_t adc_trigger_source_stop(rt_adc_device_t device)
+{
+ const struct rt_adc_trigger_cfg *cfg;
+
+ cfg = adc_trigger_active_get(device);
+ if (cfg == RT_NULL)
+ {
+ return RT_EOK;
+ }
+
+ switch (cfg->type)
+ {
+#if defined(RT_ADC_TRIGGER_USING_TIMER)
+ case RT_ADC_TRIGGER_TIMER_UPDATE:
+ case RT_ADC_TRIGGER_TIMER_COMPARE:
+ return adc_trigger_timer_source_stop(cfg);
+#endif /* defined(RT_ADC_TRIGGER_USING_TIMER) */
+
+ default:
+ return RT_EOK;
+ }
+}
+
+/**
+ * @brief Control the active trigger source around an armed ADC conversion path.
+ * @param device Pointer to the ADC device object.
+ * @param action Trigger-source lifecycle action.
+ * @param started Pointer to the trigger-start state.
+ * @param current_result Transfer result before trigger stop, ignored for start.
+ * @return For start, trigger-source start result; for stop, @p current_result unless trigger stop is the first
+ * observed failure.
+ */
+rt_err_t adc_trigger_source_control(rt_adc_device_t device, enum adc_trigger_source_action action,
+ rt_bool_t *started, rt_err_t current_result)
+{
+ rt_err_t stop_result;
+ rt_err_t result;
+
+ switch (action)
+ {
+ case ADC_TRIGGER_SOURCE_START:
+ *started = RT_FALSE;
+ if (adc_trigger_active_get(device) == RT_NULL)
+ {
+ return RT_EOK;
+ }
+
+ result = adc_trigger_source_start(device);
+ if (result != RT_EOK)
+ {
+ LOG_E("trigger source start failed: device=%s result=%d", device->parent.parent.name, result);
+ return result;
+ }
+
+ *started = RT_TRUE;
+ return RT_EOK;
+
+ case ADC_TRIGGER_SOURCE_STOP:
+ if (*started != RT_TRUE)
+ {
+ return current_result;
+ }
+
+ stop_result = adc_trigger_source_stop(device);
+ if (stop_result != RT_EOK)
+ {
+ LOG_E("trigger source stop failed: device=%s result=%d", device->parent.parent.name, stop_result);
+ if (current_result == RT_EOK)
+ {
+ current_result = stop_result;
+ }
+ }
+
+ *started = RT_FALSE;
+ return current_result;
+
+ default:
+ return (current_result != RT_EOK) ? current_result : -RT_EINVAL;
+ }
+}
+
+/**
+ * @brief Preconfigure the active device-level ADC trigger before hardware configuration.
+ * @param device Pointer to the ADC device object.
+ * @return RT_EOK on success, otherwise an RT-Thread error code.
+ *
+ * @note A null active trigger still has to be passed to the backend when the
+ * backend provides trigger_prepare(), because some backends cache the
+ * previously prepared hardware trigger selector. Passing RT_NULL asks the
+ * backend to prepare the software-start/default trigger path.
+ */
+rt_err_t adc_trigger_preconfig(rt_adc_device_t device)
+{
+ const struct rt_adc_trigger_cfg *cfg;
+
+ cfg = adc_trigger_active_get(device);
+
+ if ((device->ops == RT_NULL) || (device->ops->core == RT_NULL) || (device->ops->core->trigger_prepare == RT_NULL))
+ {
+ return (cfg == RT_NULL) ? RT_EOK : -RT_ENOSYS;
+ }
+
+ return device->ops->core->trigger_prepare(device, cfg);
+}
+
+/**
+ * @brief Set one device-level ADC hardware trigger request.
+ * @param device Pointer to the ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration object.
+ * @return Operation status.
+ * @note This function only checks the framework-level trigger structure and
+ * caches the request. It does not write ADC trigger registers immediately.
+ * Backend compatibility is reported when the cached trigger is
+ * preconfigured before a stream hardware configuration.
+ */
+rt_err_t rt_adc_trigger_set(rt_adc_device_t device, const struct rt_adc_trigger_cfg *cfg)
+{
+ struct rt_adc_trigger_cfg trigger_cfg;
+ rt_err_t result;
+ rt_atomic_t old_state;
+
+ if ((device == RT_NULL) || (cfg == RT_NULL))
+ {
+ return -RT_EINVAL;
+ }
+
+ trigger_cfg = *cfg;
+ old_state = (rt_atomic_t)RT_ADC_STATE_IDLE;
+ if (rt_atomic_compare_exchange_strong(&device->state, &old_state, (rt_atomic_t)RT_ADC_STATE_LOCKED) == 0)
+ {
+ return -RT_EBUSY;
+ }
+
+ result = adc_validate_trigger_cfg_common(&trigger_cfg);
+ if (result == RT_EOK)
+ {
+ device->trigger_ctrl.cfg = trigger_cfg;
+ device->trigger_ctrl.configured = RT_TRUE;
+ }
+
+ rt_atomic_store(&device->state, (rt_atomic_t)RT_ADC_STATE_IDLE);
+ if (result != RT_EOK)
+ {
+ LOG_E("trigger set cache failed: device=%s result=%d", device->parent.parent.name, result);
+ }
+ return result;
+}
+
+/**
+ * @brief Clear the cached ADC trigger configuration.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ * @note The ADC device must be idle so the cached trigger cannot be cleared while an active conversion is using it.
+ */
+rt_err_t rt_adc_trigger_clear(rt_adc_device_t device)
+{
+ rt_atomic_t old_state;
+
+ if (device == RT_NULL)
+ {
+ return -RT_EINVAL;
+ }
+
+ old_state = (rt_atomic_t)RT_ADC_STATE_IDLE;
+ if (rt_atomic_compare_exchange_strong(&device->state, &old_state, (rt_atomic_t)RT_ADC_STATE_LOCKED) == 0)
+ {
+ return -RT_EBUSY;
+ }
+
+ rt_memset(&device->trigger_ctrl, 0, sizeof(device->trigger_ctrl));
+ rt_atomic_store(&device->state, (rt_atomic_t)RT_ADC_STATE_IDLE);
+
+ LOG_D("trigger cleared: device=%s", device->parent.parent.name);
+ return RT_EOK;
+}
+
+/**
+ * @brief Check whether one ADC device has a cached hardware trigger request.
+ * @param device Pointer to the ADC device object.
+ * @return RT_TRUE if a hardware trigger request is set, otherwise RT_FALSE.
+ */
+rt_bool_t rt_adc_trigger_is_set(rt_adc_device_t device)
+{
+ if (device == RT_NULL)
+ {
+ return RT_FALSE;
+ }
+
+ return device->trigger_ctrl.configured;
+}
+
+#endif /* defined(RT_USING_ADC_V2) && defined(RT_ADC_USING_TRIGGER) */
diff --git a/components/drivers/clock_time/Kconfig b/components/drivers/clock_time/Kconfig
index d6259617aa..46dd271483 100644
--- a/components/drivers/clock_time/Kconfig
+++ b/components/drivers/clock_time/Kconfig
@@ -2,6 +2,17 @@ menuconfig RT_USING_CLOCK_TIME
bool "Clock time subsystem"
default n
+config RT_USING_CLOCK_TIMER_TRIGGER
+ bool "Enable clock timer hardware trigger output"
+ depends on RT_USING_CLOCK_TIME
+ default n
+ help
+ Enable clock timer hardware trigger output controls. Timer backends
+ may use this to expose update/TRGO trigger events to ADC drivers. The
+ selected timer must be dedicated to trigger output; the framework does
+ not arbitrate shared use with clock-time timeouts, PWM, or other timer
+ consumers.
+
if RT_USING_CLOCK_TIME
config CLOCK_TIMER_FREQ
int "Clock time timer freq"
diff --git a/components/drivers/include/drivers/adc_v2.h b/components/drivers/include/drivers/adc_v2.h
new file mode 100644
index 0000000000..bf369e3a50
--- /dev/null
+++ b/components/drivers/include/drivers/adc_v2.h
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-04-21 wdfk-prog add standalone adc v2 framework interface
+ */
+
+/**
+ * @file adc_v2.h
+ * @brief Standalone ADC V2 framework declarations.
+ */
+
+#ifndef __ADC_V2_H__
+#define __ADC_V2_H__
+
+#include <rtconfig.h>
+#include "misc.h"
+#if !defined(RT_USING_ADC_V2)
+#error "ADC V2 interface requires RT_USING_ADC_V2."
+#endif /* !defined(RT_USING_ADC_V2) */
+
+#include <rtatomic.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#if defined(RT_ADC_USING_TRIGGER)
+#include <drivers/adc_v2_trigger.h>
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#if defined(RT_ADC_USING_STREAM) && defined(RT_ADC_STREAM_USING_FIFO)
+#include <ipc/completion.h>
+#include <ipc/ringbuffer.h>
+#endif /* defined(RT_ADC_USING_STREAM) && defined(RT_ADC_STREAM_USING_FIFO) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief ADC control command identifiers.
+ */
+enum rt_adc_control_cmd
+{
+ RT_ADC_CMD_GET_RESOLUTION = RT_DEVICE_CTRL_BASE(ADC) + 1, /**< Get resolution in bits. */
+ RT_ADC_CMD_CALIBRATE, /**< Run ADC calibration. */
+ RT_ADC_CMD_SET_VREF, /**< Set fallback VREF from rt_uint32_t mV. */
+ RT_ADC_CMD_CALC_VREF, /**< Calculate VDDA from a raw VREF sample. */
+ RT_ADC_CMD_GET_VREF_CHANNEL, /**< Get the backend VREF sample channel as rt_uint8_t. */
+ RT_ADC_CMD_SET_SESSION, /**< Configure and cache conversion channels from rt_uint32_t mask. */
+ RT_ADC_CMD_SET_CONFIG, /**< Set backend private device configuration. */
+ RT_ADC_CMD_GET_CONFIG, /**< Get backend private device configuration. */
+ RT_ADC_CMD_CLEAR_CHANNEL_CONFIG /**< Clear backend channel/rank configuration explicitly. */
+};
+
+/**
+ * @brief ADC input mode request flags.
+ */
+enum rt_adc_input_mode
+{
+ RT_ADC_INPUT_MODE_SINGLE_ENDED = 0x01U, /**< Single-ended ADC input mode. */
+ RT_ADC_INPUT_MODE_DIFFERENTIAL = 0x02U /**< Differential ADC input mode. */
+};
+
+/**
+ * @brief Build an ADC channel mask from one logical channel index.
+ * @param _channel Logical ADC channel index.
+ */
+#define RT_ADC_CHANNEL_MASK(_channel) (1UL << (rt_uint32_t)(_channel))
+
+/**
+ * @brief ADC framework runtime state.
+ */
+enum rt_adc_state
+{
+ RT_ADC_STATE_IDLE = 0, /**< The ADC device is idle. */
+ RT_ADC_STATE_LOCKED, /**< The ADC device is temporarily locked by a framework operation. */
+ RT_ADC_STATE_STREAM /**< The ADC device is owned by an active stream session. */
+};
+
+struct rt_adc_device;
+typedef struct rt_adc_device *rt_adc_device_t;
+
+struct rt_adc_sequence_cfg;
+struct rt_adc_stream_cfg;
+
+/**
+ * @brief ADC core driver operation table.
+ */
+struct rt_adc_core_ops
+{
+ /**
+ * @brief Open and initialize the ADC hardware.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+ rt_err_t (*open)(struct rt_adc_device *device);
+
+ /**
+ * @brief Close and deinitialize the ADC hardware.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+ rt_err_t (*close)(struct rt_adc_device *device);
+
+
+ /**
+ * @brief Configure one ADC conversion session before data transfer.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @return Operation status.
+ */
+ rt_err_t (*session_config)(struct rt_adc_device *device, rt_uint32_t channels);
+
+#if defined(RT_ADC_USING_TRIGGER)
+ /**
+ * @brief Preconfigure the ADC backend trigger state for the next hardware configuration pass.
+ * @param device Pointer to the ADC device object.
+ * @param cfg Pointer to the active ADC trigger configuration object.
+ * @return Operation status.
+ * @note The implementation may only validate @p cfg, update pending driver
+ * state, or fill HAL initialization fields. It must not start the
+ * trigger source or arm ADC conversions.
+ */
+ rt_err_t (*trigger_prepare)(struct rt_adc_device *device, const struct rt_adc_trigger_cfg *cfg);
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+ /**
+ * @brief Handle ADC control commands.
+ * @param device Pointer to the ADC device object.
+ * @param cmd Control command.
+ * @param args Pointer to the control argument buffer.
+ * @return Operation status.
+ */
+ rt_err_t (*control)(struct rt_adc_device *device, int cmd, void *args);
+};
+
+/**
+ * @brief ADC finite-sequence operation table.
+ */
+struct rt_adc_sequence_ops
+{
+ /**
+ * @brief Start one active finite transfer session.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the sequence request object.
+ * @return Operation status.
+ */
+ rt_err_t (*start)(struct rt_adc_device *device, rt_uint32_t channels, const struct rt_adc_sequence_cfg *cfg);
+
+ /**
+ * @brief Read one converted sample from an active finite transfer session.
+ * @param device Pointer to the ADC device object.
+ * @param value Pointer to the output sample value.
+ * @param timeout_ms Read timeout in milliseconds; negative means wait forever.
+ * @return Operation status.
+ */
+ rt_err_t (*read)(struct rt_adc_device *device, rt_uint32_t *value, rt_int32_t timeout_ms);
+
+ /**
+ * @brief Stop one active finite transfer session.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+ rt_err_t (*stop)(struct rt_adc_device *device);
+};
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief ADC stream operation table.
+ */
+struct rt_adc_stream_ops
+{
+ /**
+ * @brief Start one active stream session.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the stream configuration object.
+ * @return Operation status.
+ */
+ rt_err_t (*start)(struct rt_adc_device *device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg);
+
+ /**
+ * @brief Synchronize a backend DMA sample range before CPU access.
+ * @param device Pointer to the ADC device object.
+ * @param sample_buffer Pointer to the DMA sample buffer.
+ * @param sample_count Number of samples to synchronize.
+ * @return Operation status.
+ */
+ rt_err_t (*sync)(struct rt_adc_device *device, const rt_uint32_t *sample_buffer, rt_size_t sample_count);
+
+ /**
+ * @brief Stop one active stream session.
+ * @param device Pointer to the ADC device object.
+ * @param hardware_stopped Pointer to the hardware-stop state output.
+ * @return Operation status.
+ *
+ * The backend sets @p hardware_stopped to RT_TRUE after the ADC hardware
+ * conversion path has stopped. When this callback returns an error with
+ * @p hardware_stopped set to RT_TRUE, the framework treats it as a
+ * post-stop cleanup failure and moves the stream to IDLE.
+ */
+ rt_err_t (*stop)(struct rt_adc_device *device, rt_bool_t *hardware_stopped);
+};
+#endif /* RT_ADC_USING_STREAM */
+
+
+/**
+ * @brief ADC driver operation table.
+ */
+struct rt_adc_ops
+{
+ const struct rt_adc_core_ops *core; /**< Core operation table. */
+ const struct rt_adc_sequence_ops *sequence; /**< Sequence-session operations. */
+#ifdef RT_ADC_USING_STREAM
+ const struct rt_adc_stream_ops *stream; /**< Stream-session operations. */
+#endif /* RT_ADC_USING_STREAM */
+};
+
+/**
+ * @brief ADC synchronous one-frame sequence request.
+ */
+struct rt_adc_sequence_cfg
+{
+ rt_uint32_t *buffer; /**< Destination sample buffer. */
+ rt_size_t buffer_length; /**< Destination buffer length in samples. */
+ rt_int32_t timeout_ms; /**< Per-sample timeout; negative means wait forever. */
+};
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief ADC stream backend event.
+ */
+enum rt_adc_stream_event
+{
+ RT_ADC_STREAM_EVENT_DMA_HALF = 0x01U, /**< ADC stream DMA half-transfer event. */
+ RT_ADC_STREAM_EVENT_DMA_DONE = 0x02U, /**< ADC stream DMA transfer-complete event. */
+ RT_ADC_STREAM_EVENT_ERROR = 0x03U /**< ADC stream backend error event. */
+};
+
+/**
+ * @brief ADC stream buffering policy.
+ */
+enum rt_adc_stream_policy
+{
+#ifdef RT_ADC_STREAM_USING_LATEST
+ /**
+ * @brief Keep only the latest ADC rank values.
+ *
+ * This policy is intended for slow-changing ADC values such as battery
+ * voltage, temperature, potentiometer input, resistor-divider voltage, or
+ * board status monitoring. Old values may be overwritten.
+ *
+ * In this policy, @ref rt_adc_stream_cfg::dma_buffer_length must be exactly
+ * equal to the active ADC frame length, namely the number of enabled ADC
+ * ranks. The backend must expose the DMA buffer as a single latest-frame
+ * layout:
+ *
+ * - dma_buffer[0] stores the latest value of ADC rank 1.
+ * - dma_buffer[1] stores the latest value of ADC rank 2.
+ * - dma_buffer[n] stores the latest value of ADC rank n + 1.
+ *
+ * STM32 regular scan conversion with circular DMA naturally satisfies this
+ * layout when the DMA length equals the ADC rank count. Backends for other
+ * platforms may also support this policy if their DMA engine writes samples
+ * in scan-rank order. If a backend produces packed, interleaved,
+ * descriptor-based, hardware-FIFO, or otherwise non-rank-ordered data, it
+ * must either convert the data into this latest-frame layout internally or
+ * reject the configuration with -RT_ENOSYS.
+ *
+ * @note Latest mode is a low-overhead lockless DMA-buffer view. CPU-side
+ * atomic operations, spin locks, mutexes, or read-write locks cannot
+ * prevent the DMA engine from updating memory concurrently, because
+ * DMA does not participate in CPU locking protocols. This mode only
+ * guarantees that each buffer index maps to the corresponding ADC rank
+ * latest value; it does not guarantee that the copied frame is a
+ * single hardware scan-cycle snapshot. Use RT_ADC_STREAM_POLICY_FIFO
+ * when ordered and frame-accurate samples are required.
+ */
+ RT_ADC_STREAM_POLICY_LATEST = 0,
+#endif /* RT_ADC_STREAM_USING_LATEST */
+#ifdef RT_ADC_STREAM_USING_FIFO
+ /**
+ * @brief Preserve ADC samples in FIFO order.
+ *
+ * This policy is intended for continuous and loss-sensitive sampling such
+ * as waveform, current, vibration, audio-like, motor-control, or
+ * control-loop data where each sample matters.
+ *
+ * The backend reports completed DMA blocks to the ADC framework. The
+ * framework copies those blocks into a ringbuffer and wakes blocking readers
+ * through a completion object.
+ */
+ RT_ADC_STREAM_POLICY_FIFO,
+#endif /* RT_ADC_STREAM_USING_FIFO */
+};
+
+/**
+ * @brief ADC stream DMA data event mode.
+ */
+enum rt_adc_stream_dma_event_mode
+{
+ RT_ADC_STREAM_DMA_EVENT_AUTO = 0, /**< Use the default event mode for the selected stream policy. */
+ RT_ADC_STREAM_DMA_EVENT_NONE, /**< Disable DMA half/full data events; DMA error events remain enabled. */
+ RT_ADC_STREAM_DMA_EVENT_FULL_ONLY, /**< Report only DMA transfer-complete data events to reduce interrupt rate. */
+ RT_ADC_STREAM_DMA_EVENT_HALF_FULL /**< Report both DMA half-transfer and transfer-complete data events. */
+};
+
+/**
+ * @brief ADC stream FIFO data callback type.
+ * @param device Pointer to the ADC device object.
+ * @param sample_count Number of newly accepted samples.
+ * @param user_data Pointer to the user context.
+ * @note This callback is invoked from ADC stream ISR context. It must not
+ * block, sleep, or call APIs that may suspend the current context.
+ */
+typedef void (*rt_adc_stream_callback_t)(struct rt_adc_device *device, rt_size_t sample_count, void *user_data);
+
+/**
+ * @brief ADC stream configuration.
+ * @note The DMA buffer belongs to the caller and must remain valid until
+ * rt_adc_stream_stop() returns. The stream configuration object only
+ * needs to remain valid for the duration of rt_adc_stream_start(). A
+ * backend may use an internal cache-aligned DMA buffer when the caller
+ * buffer is not safe for platform cache maintenance. Backend drivers must
+ * copy scalar configuration fields they need after rt_adc_stream_start()
+ * returns.
+ */
+struct rt_adc_stream_cfg
+{
+ enum rt_adc_stream_policy policy; /**< Stream buffering policy. */
+ enum rt_adc_stream_dma_event_mode dma_event_mode; /**< DMA half/full data event mode. */
+
+ /**
+ * @brief DMA circular staging buffer.
+ *
+ * For RT_ADC_STREAM_POLICY_LATEST, this buffer stores exactly one latest
+ * ADC scan frame. dma_buffer_length must equal the active frame length.
+ * Each element maps to one configured ADC rank.
+ *
+ * For RT_ADC_STREAM_POLICY_FIFO, this buffer is a DMA staging buffer. The
+ * default rt_adc_stream_start() entry validates only basic buffer presence
+ * and capacity. It does not require each DMA data-event block to end on an
+ * ADC scan-frame boundary.
+ *
+ * Use rt_adc_stream_start_frame_aligned_fifo() when continuous FIFO sampling
+ * requires a strict frame-aligned DMA/FIFO layout before the stream starts.
+ */
+ rt_uint32_t *dma_buffer;
+
+ /**
+ * @brief DMA buffer length in samples.
+ */
+ rt_size_t dma_buffer_length;
+#ifdef RT_ADC_STREAM_USING_FIFO
+ rt_uint32_t *fifo_buffer; /**< FIFO storage for FIFO policy. */
+ rt_size_t fifo_buffer_length; /**< FIFO buffer length in samples. */
+ rt_size_t watermark; /**< FIFO wakeup or callback threshold in samples. */
+ rt_adc_stream_callback_t callback; /**< Optional ISR-context FIFO data callback. */
+ void *user_data; /**< User data passed to the FIFO data callback. */
+#endif /* RT_ADC_STREAM_USING_FIFO */
+};
+
+/**
+ * @brief ADC stream runtime control block owned by the ADC framework.
+ */
+struct rt_adc_stream_ctrl
+{
+ rt_bool_t active; /**< Whether a stream backend session is active. */
+ enum rt_adc_stream_policy policy; /**< Active stream buffering policy. */
+ enum rt_adc_stream_dma_event_mode dma_event_mode; /**< Active DMA data event mode. */
+ rt_uint32_t *dma_buffer; /**< DMA circular staging buffer. */
+ rt_size_t dma_buffer_length; /**< DMA buffer length in samples. */
+ rt_size_t frame_length; /**< Samples in one ADC scan frame. */
+#ifdef RT_ADC_STREAM_USING_FIFO
+ struct rt_ringbuffer fifo; /**< FIFO storage for FIFO policy. */
+ rt_bool_t fifo_enabled; /**< FIFO initialized flag. */
+ /**
+ * @brief Reader wake completion for FIFO stream.
+ *
+ * The FIFO ringbuffer is the source of truth for available data. This
+ * completion object is only a wakeup edge for blocking reads.
+ */
+ struct rt_completion rx_cpt;
+ rt_size_t overflow_count; /**< FIFO overrun count. */
+ rt_size_t watermark; /**< FIFO wakeup or callback threshold. */
+ rt_adc_stream_callback_t callback; /**< Optional FIFO data callback. */
+ void *user_data; /**< Callback private data. */
+#endif /* RT_ADC_STREAM_USING_FIFO */
+ rt_atomic_t last_error; /**< Atomic last stream backend error. */
+};
+#endif /* RT_ADC_USING_STREAM */
+
+/**
+ * @brief ADC active session runtime control block.
+ */
+struct rt_adc_session_ctrl
+{
+ rt_uint32_t channels; /**< Cached active ADC channel selection mask. */
+ rt_size_t channel_count; /**< Cached active session channel count. */
+ rt_bool_t configured; /**< Whether the cached session configuration is valid. */
+};
+
+/**
+ * @brief ADC device object.
+ */
+struct rt_adc_device
+{
+ struct rt_device parent; /**< RT-Thread device object. */
+ const struct rt_adc_ops *ops; /**< ADC driver operation table. */
+ rt_atomic_t state; /**< Atomic ADC runtime state. */
+ struct rt_spinlock spinlock; /**< Protects ADC stream FIFO shared by thread context and ISR. */
+ rt_uint32_t default_vref_mv; /**< Default reference voltage in millivolts. */
+ struct rt_adc_session_ctrl session_ctrl; /**< ADC active session control block. */
+#if defined(RT_ADC_USING_TRIGGER)
+ struct rt_adc_trigger_ctrl trigger_ctrl; /**< ADC trigger runtime control block. */
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+#ifdef RT_ADC_USING_STREAM
+ struct rt_adc_stream_ctrl stream_ctrl; /**< ADC stream runtime control block. */
+#endif /* RT_ADC_USING_STREAM */
+};
+
+/**
+ * @brief Count selected ADC channels in one channel mask.
+ * @param channels ADC channel selection mask.
+ * @return Number of selected channels.
+ */
+rt_inline rt_size_t rt_adc_channel_mask_count(rt_uint32_t channels)
+{
+#if defined(__GNUC__) || defined(__clang__)
+ return (rt_size_t)__builtin_popcount((unsigned int)channels);
+#else
+ rt_size_t count;
+
+ count = 0U;
+ while (channels != 0U)
+ {
+ channels &= channels - 1U;
+ count++;
+ }
+
+ return count;
+#endif /* defined(__GNUC__) || defined(__clang__) */
+}
+
+/**
+ * @brief Take the lowest selected ADC channel from one channel mask.
+ * @param channels Pointer to the ADC channel selection mask.
+ * @return Selected channel index, or 0xff if the mask is empty.
+ */
+rt_inline rt_uint8_t rt_adc_channel_mask_take_lsb(rt_uint32_t *channels)
+{
+ rt_uint8_t bit;
+
+ if ((channels == RT_NULL) || (*channels == 0U))
+ {
+ return 0xffU;
+ }
+
+#if defined(__GNUC__) || defined(__clang__)
+ bit = (rt_uint8_t)__builtin_ctz((unsigned int)*channels);
+#else
+ for (bit = 0U; bit < 32U; bit++)
+ {
+ if ((*channels & RT_ADC_CHANNEL_MASK(bit)) != 0U)
+ {
+ break;
+ }
+ }
+#endif /* defined(__GNUC__) || defined(__clang__) */
+
+ *channels &= ~RT_ADC_CHANNEL_MASK(bit);
+ return bit;
+}
+
+/**
+ * @brief Register an ADC device with the RT-Thread device framework.
+ * @param device Pointer to the ADC device object.
+ * @param name Pointer to the ADC device name string.
+ * @param ops Pointer to the ADC driver operation table.
+ * @param user_data Pointer to driver private data.
+ * @return Operation status.
+ */
+rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data);
+
+/**
+ * @brief Get the raw sample index of one channel in an ADC session mask.
+ * @param session_channels Configured ADC session channel mask.
+ * @param channel Single-channel mask to locate.
+ * @param index Pointer to the output raw sample index.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_session_channel_index(rt_uint32_t session_channels, rt_uint32_t channel, rt_size_t *index);
+
+
+/**
+ * @brief Read one ADC conversion sequence frame.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the ADC sequence request object.
+ * @param read_count Pointer to the stored sample count.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_read_sequence(rt_adc_device_t device, rt_uint32_t channels,
+ const struct rt_adc_sequence_cfg *cfg, rt_size_t *read_count);
+
+#ifdef RT_ADC_USING_STREAM
+/**
+ * @brief Start one ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the ADC stream configuration object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_start(rt_adc_device_t device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg);
+
+#ifdef RT_ADC_STREAM_USING_FIFO
+/**
+ * @brief Start one FIFO ADC stream with strict frame-aligned buffer layout.
+ * @param device Pointer to the ADC device object.
+ * @param channels ADC channel selection mask.
+ * @param cfg Pointer to the ADC stream configuration object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_start_frame_aligned_fifo(rt_adc_device_t device, rt_uint32_t channels, const struct rt_adc_stream_cfg *cfg);
+#endif /* RT_ADC_STREAM_USING_FIFO */
+
+/**
+ * @brief Read converted samples from an active ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @param buffer Pointer to the destination sample buffer.
+ * @param sample_count Number of samples to read.
+ * @param timeout_ms Read timeout in milliseconds; negative means wait forever.
+ * @return Number of samples read, or a negative RT-Thread error code.
+ */
+rt_ssize_t rt_adc_stream_read(rt_adc_device_t device, rt_uint32_t *buffer, rt_size_t sample_count, rt_int32_t timeout_ms);
+
+/**
+ * @brief Cancel a blocked ADC stream reader before stream shutdown.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_cancel(rt_adc_device_t device);
+
+/**
+ * @brief Stop one ADC stream session.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_stream_stop(rt_adc_device_t device);
+
+/**
+ * @brief Notify the ADC framework of one stream backend event.
+ * @param device Pointer to the ADC device object.
+ * @param event ADC stream event reported by the backend or ISR.
+ * @param sample_buffer Pointer to the completed sample buffer block.
+ * @param sample_count Number of samples in @p sample_buffer.
+ * @return Operation status.
+ */
+rt_err_t rt_hw_adc_stream_isr(rt_adc_device_t device, enum rt_adc_stream_event event,
+ const rt_uint32_t *sample_buffer, rt_size_t sample_count);
+#endif /* RT_ADC_USING_STREAM */
+
+/**
+ * @brief Convert one raw ADC sample to millivolts.
+ * @param raw_value Raw ADC sample value.
+ * @param vref_mv ADC reference voltage in millivolts.
+ * @param resolution_bits ADC resolution in bits.
+ * @param voltage_mv Pointer to the output voltage in millivolts.
+ * @return Operation status.
+ */
+rt_err_t rt_adc_raw_to_voltage_mv(rt_uint32_t raw_value, rt_uint32_t vref_mv, rt_uint8_t resolution_bits, rt_uint32_t *voltage_mv);
+
+/**
+ * @brief Convert one ADC raw sample to a scaled voltage in millivolts.
+ * @param raw_value Raw ADC sample code.
+ * @param vref_mv ADC reference voltage in millivolts.
+ * @param resolution_bits ADC resolution in bits.
+ * @param scale_num Voltage scaling numerator.
+ * @param scale_den Voltage scaling denominator.
+ * @param voltage_mv Pointer to the output scaled voltage in millivolts.
+ * @return Operation status.
+ *
+ * The scaled voltage is calculated as:
+ *
+ * raw_to_voltage_mv(raw_value) * scale_num / scale_den
+ *
+ * @note @p scale_num and @p scale_den may describe any positive rational
+ * scaling ratio that does not overflow the internal calculation. The
+ * final scaled millivolt value must fit in rt_uint32_t.
+ *
+ * @retval RT_EOK The conversion completed successfully.
+ * @retval -RT_EINVAL A pointer is null, a scale argument is zero, the ADC
+ * conversion arguments are invalid, or the scaled result overflows
+ * rt_uint32_t.
+ */
+rt_err_t rt_adc_raw_to_scaled_voltage_mv(rt_uint32_t raw_value, rt_uint32_t vref_mv, rt_uint8_t resolution_bits, rt_uint32_t scale_num, rt_uint32_t scale_den, rt_uint32_t *voltage_mv);
+
+/**
+ * @brief Read ADC samples and convert them to millivolts.
+ * @param device Pointer to the ADC device object.
+ * @param voltages_mv Pointer to the output voltage buffer in millivolts.
+ * @param size Output voltage buffer length.
+ * @param timeout_ms Per-sample timeout in milliseconds; negative means wait forever.
+ * @return Operation status.
+ *
+ * @note This API reads the currently configured ADC session and does not modify
+ * the active channel mask. If default_vref_mv is zero, callers that need
+ * backend-calculated VDDA must include the backend VREF channel in the
+ * configured session. The VREF sample is used only as the reference for
+ * conversion and is not auto-inserted by this API.
+ */
+rt_err_t rt_adc_voltage(rt_adc_device_t device, rt_uint32_t *voltages_mv, rt_size_t size, rt_int32_t timeout_ms);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ADC_V2_H__ */
diff --git a/components/drivers/include/drivers/adc_v2_trigger.h b/components/drivers/include/drivers/adc_v2_trigger.h
new file mode 100644
index 0000000000..bb328b8dba
--- /dev/null
+++ b/components/drivers/include/drivers/adc_v2_trigger.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-05-20 wdfk-prog add ADC V2 trigger declarations
+ */
+
+/**
+ * @file adc_v2_trigger.h
+ * @brief ADC V2 trigger framework declarations.
+ */
+
+#ifndef __ADC_V2_TRIGGER_H__
+#define __ADC_V2_TRIGGER_H__
+
+#include <rtconfig.h>
+#include <rtthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if defined(RT_ADC_USING_TRIGGER)
+struct rt_adc_device;
+struct rt_device;
+
+/**
+ * @brief ADC hardware trigger event type.
+ *
+ * @note A platform backend may support only part of these trigger types.
+ * Unsupported trigger types shall be rejected by the framework or backend
+ * with an error such as -RT_ENOSYS.
+ */
+enum rt_adc_trigger_type
+{
+ RT_ADC_TRIGGER_TIMER_UPDATE = 0, /**< Use a timer update/TRGO event. */
+ RT_ADC_TRIGGER_TIMER_COMPARE, /**< Use a timer compare event. */
+ RT_ADC_TRIGGER_PWM_EDGE, /**< Use a PWM edge event. */
+ RT_ADC_TRIGGER_EXTI_EDGE, /**< Use an external interrupt edge event. */
+ RT_ADC_TRIGGER_ANALOG_COMPARE, /**< Use an analog comparator event. */
+ RT_ADC_TRIGGER_BACKEND, /**< Use a backend-specific trigger event. */
+};
+
+/**
+ * @brief ADC trigger edge selector.
+ */
+enum rt_adc_trigger_edge
+{
+ RT_ADC_TRIGGER_EDGE_NONE = 0, /**< No edge selection is required. */
+ RT_ADC_TRIGGER_EDGE_RISING, /**< Use the rising edge. */
+ RT_ADC_TRIGGER_EDGE_FALLING, /**< Use the falling edge. */
+ RT_ADC_TRIGGER_EDGE_BOTH, /**< Use both rising and falling edges. */
+};
+
+/**
+ * @brief Timer-based ADC trigger event.
+ */
+struct rt_adc_trigger_timer_event
+{
+ struct rt_device *timer; /**< Timer device used as trigger source. */
+ rt_uint32_t freq_hz; /**< Timer trigger output frequency in hertz. */
+ rt_uint16_t channel; /**< Timer channel, or 0 for update/TRGO event. */
+ rt_uint16_t reserved; /**< Reserved for future extension. */
+};
+
+/**
+ * @brief PWM-based ADC trigger event.
+ */
+struct rt_adc_trigger_pwm_event
+{
+ struct rt_device *pwm; /**< PWM device used as trigger source. */
+ rt_uint16_t channel; /**< PWM channel. */
+ enum rt_adc_trigger_edge edge; /**< PWM edge used as trigger event. */
+};
+
+/**
+ * @brief External interrupt ADC trigger event.
+ */
+struct rt_adc_trigger_exti_event
+{
+ struct rt_device *pin; /**< Pin or GPIO controller device. */
+ rt_uint16_t line; /**< External interrupt line or pin number. */
+ enum rt_adc_trigger_edge edge; /**< Interrupt edge used as trigger event. */
+};
+
+/**
+ * @brief Analog comparator ADC trigger event.
+ */
+struct rt_adc_trigger_compare_event
+{
+ struct rt_device *comparator; /**< Optional comparator device used as trigger source. */
+ rt_uint16_t channel; /**< Comparator channel or instance index. */
+ enum rt_adc_trigger_edge edge; /**< Comparator output edge used as trigger event. */
+};
+
+/**
+ * @brief Backend-specific ADC trigger event.
+ */
+struct rt_adc_trigger_backend_event
+{
+ rt_uint32_t selector; /**< Backend-specific trigger selector. */
+ rt_uint32_t edge; /**< Backend-specific edge selector. */
+ const void *data; /**< Optional backend-specific configuration. */
+ rt_size_t data_size; /**< Size of backend-specific configuration. */
+};
+
+/**
+ * @brief ADC trigger configuration.
+ */
+struct rt_adc_trigger_cfg
+{
+ enum rt_adc_trigger_type type; /**< Trigger event type. */
+ rt_uint32_t flags; /**< Common trigger flags, reserved for future extension. */
+
+ union
+ {
+ struct rt_adc_trigger_timer_event timer; /**< Timer trigger event. */
+ struct rt_adc_trigger_pwm_event pwm; /**< PWM trigger event. */
+ struct rt_adc_trigger_exti_event exti; /**< External interrupt trigger event. */
+ struct rt_adc_trigger_compare_event compare; /**< Comparator trigger event. */
+ struct rt_adc_trigger_backend_event backend; /**< Backend-specific trigger event. */
+ } event; /**< Trigger event payload. */
+};
+
+/**
+ * @brief ADC trigger runtime control block.
+ */
+struct rt_adc_trigger_ctrl
+{
+ struct rt_adc_trigger_cfg cfg; /**< Cached device-level hardware trigger configuration. */
+ rt_bool_t configured; /**< Whether cfg contains a cached hardware trigger request. */
+};
+
+/**
+ * @brief Set one device-level ADC hardware trigger request.
+ * @param device Pointer to the ADC device object.
+ * @param cfg Pointer to the ADC trigger configuration object.
+ * @return Operation status.
+ * @note This function only checks the framework-level trigger structure and
+ * caches the request. It does not write ADC trigger registers immediately.
+ * Backend compatibility is reported when the cached trigger is
+ * preconfigured before a conversion hardware configuration.
+ */
+rt_err_t rt_adc_trigger_set(struct rt_adc_device *device, const struct rt_adc_trigger_cfg *cfg);
+
+/**
+ * @brief Clear the cached device-level ADC hardware trigger request.
+ * @param device Pointer to the ADC device object.
+ * @return Operation status.
+ * @note This function does not write ADC trigger registers immediately. The
+ * next conversion hardware configuration preconfigures the backend
+ * software/default trigger state.
+ */
+rt_err_t rt_adc_trigger_clear(struct rt_adc_device *device);
+
+/**
+ * @brief Check whether one ADC device has a cached hardware trigger request.
+ * @param device Pointer to the ADC device object.
+ * @return RT_TRUE if a hardware trigger request is set, otherwise RT_FALSE.
+ */
+rt_bool_t rt_adc_trigger_is_set(struct rt_adc_device *device);
+#endif /* defined(RT_ADC_USING_TRIGGER) */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ADC_V2_TRIGGER_H__ */
diff --git a/components/drivers/include/drivers/clock_time.h b/components/drivers/include/drivers/clock_time.h
index 7374b97d00..c43c079eb0 100644
--- a/components/drivers/include/drivers/clock_time.h
+++ b/components/drivers/include/drivers/clock_time.h
@@ -47,9 +47,41 @@ typedef enum
CLOCK_TIMER_CTRL_FREQ_SET = RT_DEVICE_CTRL_BASE(Timer) + 0x01,
CLOCK_TIMER_CTRL_STOP = RT_DEVICE_CTRL_BASE(Timer) + 0x02,
CLOCK_TIMER_CTRL_INFO_GET = RT_DEVICE_CTRL_BASE(Timer) + 0x03,
- CLOCK_TIMER_CTRL_MODE_SET = RT_DEVICE_CTRL_BASE(Timer) + 0x04
+ CLOCK_TIMER_CTRL_MODE_SET = RT_DEVICE_CTRL_BASE(Timer) + 0x04,
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+ CLOCK_TIMER_CTRL_TRIGGER_CONFIG = RT_DEVICE_CTRL_BASE(Timer) + 0x05,
+ CLOCK_TIMER_CTRL_TRIGGER_START = RT_DEVICE_CTRL_BASE(Timer) + 0x06,
+ CLOCK_TIMER_CTRL_TRIGGER_STOP = RT_DEVICE_CTRL_BASE(Timer) + 0x07,
+ CLOCK_TIMER_CTRL_TRIGGER_RELEASE = RT_DEVICE_CTRL_BASE(Timer) + 0x08
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
} rt_clock_timer_ctrl_t;
+#if defined(RT_USING_CLOCK_TIMER_TRIGGER)
+/**
+ * @brief Hardware timer trigger output event type.
+ */
+enum rt_clock_timer_trigger_event
+{
+ CLOCK_TIMER_TRIGGER_EVENT_UPDATE = 0, /**< Generate trigger on timer update/overflow event. */
+ CLOCK_TIMER_TRIGGER_EVENT_COMPARE, /**< Generate trigger on timer compare match event. */
+ CLOCK_TIMER_TRIGGER_EVENT_PWM_EDGE, /**< Generate trigger on timer PWM output reference edge. */
+ CLOCK_TIMER_TRIGGER_EVENT_BACKEND /**< Generate trigger from a backend-specific timer event. */
+};
+
+/**
+ * @brief Hardware trigger output configuration.
+ * @note This interface does not arbitrate timer ownership. Callers must
+ * provide a timer dedicated to hardware trigger output.
+ */
+struct rt_clock_timer_trigger_cfg
+{
+ rt_uint32_t freq_hz; /**< Trigger output frequency in hertz. */
+ enum rt_clock_timer_trigger_event event; /**< Timer event used as trigger output. */
+ rt_uint16_t channel; /**< Timer compare channel, or 0 for update event. */
+ rt_uint16_t reserved; /**< Reserved for future extension. */
+};
+#endif /* defined(RT_USING_CLOCK_TIMER_TRIGGER) */
+
typedef enum
{
CLOCK_TIMER_MODE_ONESHOT = 0x01,
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index e6eb43bc57..a9da14d322 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -272,9 +272,11 @@ extern "C" {
#include "drivers/dev_audio.h"
#endif /* RT_USING_AUDIO */
-#ifdef RT_USING_ADC
+#ifdef RT_USING_ADC_V2
+#include "drivers/adc_v2.h"
+#elif defined(RT_USING_ADC)
#include "drivers/adc.h"
-#endif /* RT_USING_ADC */
+#endif /* RT_USING_ADC_V2 */
#ifdef RT_USING_DAC
#include "drivers/dac.h"
diff --git a/components/drivers/misc/Kconfig b/components/drivers/misc/Kconfig
index 0a7788bce5..71f42ee67b 100644
--- a/components/drivers/misc/Kconfig
+++ b/components/drivers/misc/Kconfig
@@ -1,11 +1,3 @@
-menuconfig RT_USING_ADC
- bool "Using ADC device drivers"
- default n
-
-if RT_USING_DM && RT_USING_ADC
- osource "$(SOC_DM_ADC_DIR)/Kconfig"
-endif
-
config RT_USING_DAC
bool "Using DAC device drivers"
default n
diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript
index 5b74ac93e5..23727a5ce9 100644
--- a/components/drivers/misc/SConscript
+++ b/components/drivers/misc/SConscript
@@ -5,9 +5,6 @@ src = []
CPPPATH = [cwd + '/../include']
group = []
-if GetDepend(['RT_USING_ADC']):
- src = src + ['adc.c']
-
if GetDepend(['RT_USING_DAC']):
src = src + ['dac.c']