This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 4cdbe98aefa arch/arm/src/common/stm32: add hardware oversampling to
the G4 ADC
4cdbe98aefa is described below
commit 4cdbe98aefaee0233195a656f8d5e1d8d17d8cfe
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Sun Oct 25 14:43:00 2026 -0300
arch/arm/src/common/stm32: add hardware oversampling to the G4 ADC
The STM32G4 ADC can oversample the regular group in hardware (CFGR2:
ROVSE, OVSR, OVSS and TROVS), but the driver never set these bits.
Enable it per ADC with STM32_ADCn_OVERSAMPLE, STM32_ADCn_OVSR,
STM32_ADCn_OVSS and STM32_ADCn_TROVS, written when the ADC is
configured and still disabled.
The options already existed for ADC1 and ADC2 of the STM32H5, which uses
the same register layout and meaning. They move to a menu shared by the
H5 and the G4, which also gets ADC3 to ADC5. The data register is 16
bits wide, so the Kconfig help warns that the accumulated sum overflows
it silently when OVSS is too small for the ratio.
Tested on an STM32G474RE board, ADC1 with 8 channels and 64x
oversampling (OVSR=5, OVSS=2): CFGR2 reads 0x055 and the standard
deviation of the channels drops from 0.36-1.5 LSB to 0.06-0.22 LSB. An
STM32H5 build with ADC1 and ADC2 oversampling still compiles.
Assisted-by: Claude Code:claude-sonnet-5-5
Signed-off-by: Daniel P. Carvalho <[email protected]>
---
arch/arm/src/common/stm32/Kconfig.adc | 232 +++++++++++++++++++-----
arch/arm/src/common/stm32/Kconfig.have | 4 +
arch/arm/src/common/stm32/stm32_adc_m3m4_v1v2.c | 92 ++++++++++
3 files changed, 278 insertions(+), 50 deletions(-)
diff --git a/arch/arm/src/common/stm32/Kconfig.adc
b/arch/arm/src/common/stm32/Kconfig.adc
index 2c7040df2bb..068752b124b 100644
--- a/arch/arm/src/common/stm32/Kconfig.adc
+++ b/arch/arm/src/common/stm32/Kconfig.adc
@@ -284,16 +284,16 @@ endmenu #STM32L4 ADCx triggering Configuration
endmenu
-menu "ADC Configuration"
- depends on STM32_HAVE_ADC_H5 && STM32_ADC
+menu "ADC Oversampling Configuration"
+ depends on (STM32_HAVE_ADC_H5 || STM32_HAVE_ADC_OVERSAMPLE_G4) &&
STM32_ADC
config STM32_ADC1_OVERSAMPLE
bool "Enable ADC1 hardware oversampling support"
depends on STM32_ADC1
default n
---help---
- Enable the on-chip ADC oversampling/accumulation block
(CFGR2.OVSE).
- Only STM32G0 and STM32L0 series include this hardware block.
+ Enable the on-chip ADC oversampling/accumulation block for the
+ regular group (CFGR2.ROVSE).
if STM32_ADC1_OVERSAMPLE
@@ -301,8 +301,9 @@ config STM32_ADC1_TROVS
bool "Enable triggered oversampling (CFGR2.TROVS)"
default n
---help---
- If set, oversampling will only occur when a trigger event
occurs.
- If not set, oversampling occurs continuously (TOVS=0).
+ If set, each trigger starts one conversion of the whole
+ oversampling ratio. If not set, a trigger starts a single
+ conversion and the remaining ones follow automatically.
config STM32_ADC1_OVSR
int "Oversampling ratio (CFGR2.OVSR)"
@@ -310,11 +311,11 @@ config STM32_ADC1_OVSR
range 0 7
---help---
Sets the oversampling ratio as 2^(OVSR+1). For example:
- 0 -> 2×
- 1 -> 4×
- 2 -> 8×
+ 0 -> 2x
+ 1 -> 4x
+ 2 -> 8x
...
- 7 -> 256×
+ 7 -> 256x
config STM32_ADC1_OVSS
int "Oversampling right-shift bits (CFGR2.OVSS)"
@@ -322,10 +323,180 @@ config STM32_ADC1_OVSS
range 0 8
---help---
Sets how many bits the accumulated result is right-shifted.
- Max of 8-bits.
+ The data register is 16 bits wide: ratios above 16x with
+ OVSS below log2(ratio) - 4 overflow it silently.
endif # STM32_ADC1_OVERSAMPLE
+config STM32_ADC2_OVERSAMPLE
+ bool "Enable ADC2 hardware oversampling support"
+ depends on STM32_ADC2
+ default n
+ ---help---
+ Enable the on-chip ADC oversampling/accumulation block for the
+ regular group (CFGR2.ROVSE).
+
+if STM32_ADC2_OVERSAMPLE
+
+config STM32_ADC2_TROVS
+ bool "Enable triggered oversampling (CFGR2.TROVS)"
+ default n
+ ---help---
+ If set, each trigger starts one conversion of the whole
+ oversampling ratio. If not set, a trigger starts a single
+ conversion and the remaining ones follow automatically.
+
+config STM32_ADC2_OVSR
+ int "Oversampling ratio (CFGR2.OVSR)"
+ default 0
+ range 0 7
+ ---help---
+ Sets the oversampling ratio as 2^(OVSR+1). For example:
+ 0 -> 2x
+ 1 -> 4x
+ 2 -> 8x
+ ...
+ 7 -> 256x
+
+config STM32_ADC2_OVSS
+ int "Oversampling right-shift bits (CFGR2.OVSS)"
+ default 0
+ range 0 8
+ ---help---
+ Sets how many bits the accumulated result is right-shifted.
+ The data register is 16 bits wide: ratios above 16x with
+ OVSS below log2(ratio) - 4 overflow it silently.
+
+endif # STM32_ADC2_OVERSAMPLE
+
+config STM32_ADC3_OVERSAMPLE
+ bool "Enable ADC3 hardware oversampling support"
+ depends on STM32_ADC3 && STM32_HAVE_ADC_OVERSAMPLE_G4
+ default n
+ ---help---
+ Enable the on-chip ADC oversampling/accumulation block for the
+ regular group (CFGR2.ROVSE).
+
+if STM32_ADC3_OVERSAMPLE
+
+config STM32_ADC3_TROVS
+ bool "Enable triggered oversampling (CFGR2.TROVS)"
+ default n
+ ---help---
+ If set, each trigger starts one conversion of the whole
+ oversampling ratio. If not set, a trigger starts a single
+ conversion and the remaining ones follow automatically.
+
+config STM32_ADC3_OVSR
+ int "Oversampling ratio (CFGR2.OVSR)"
+ default 0
+ range 0 7
+ ---help---
+ Sets the oversampling ratio as 2^(OVSR+1). For example:
+ 0 -> 2x
+ 1 -> 4x
+ 2 -> 8x
+ ...
+ 7 -> 256x
+
+config STM32_ADC3_OVSS
+ int "Oversampling right-shift bits (CFGR2.OVSS)"
+ default 0
+ range 0 8
+ ---help---
+ Sets how many bits the accumulated result is right-shifted.
+ The data register is 16 bits wide: ratios above 16x with
+ OVSS below log2(ratio) - 4 overflow it silently.
+
+endif # STM32_ADC3_OVERSAMPLE
+
+config STM32_ADC4_OVERSAMPLE
+ bool "Enable ADC4 hardware oversampling support"
+ depends on STM32_ADC4 && STM32_HAVE_ADC_OVERSAMPLE_G4
+ default n
+ ---help---
+ Enable the on-chip ADC oversampling/accumulation block for the
+ regular group (CFGR2.ROVSE).
+
+if STM32_ADC4_OVERSAMPLE
+
+config STM32_ADC4_TROVS
+ bool "Enable triggered oversampling (CFGR2.TROVS)"
+ default n
+ ---help---
+ If set, each trigger starts one conversion of the whole
+ oversampling ratio. If not set, a trigger starts a single
+ conversion and the remaining ones follow automatically.
+
+config STM32_ADC4_OVSR
+ int "Oversampling ratio (CFGR2.OVSR)"
+ default 0
+ range 0 7
+ ---help---
+ Sets the oversampling ratio as 2^(OVSR+1). For example:
+ 0 -> 2x
+ 1 -> 4x
+ 2 -> 8x
+ ...
+ 7 -> 256x
+
+config STM32_ADC4_OVSS
+ int "Oversampling right-shift bits (CFGR2.OVSS)"
+ default 0
+ range 0 8
+ ---help---
+ Sets how many bits the accumulated result is right-shifted.
+ The data register is 16 bits wide: ratios above 16x with
+ OVSS below log2(ratio) - 4 overflow it silently.
+
+endif # STM32_ADC4_OVERSAMPLE
+
+config STM32_ADC5_OVERSAMPLE
+ bool "Enable ADC5 hardware oversampling support"
+ depends on STM32_ADC5 && STM32_HAVE_ADC_OVERSAMPLE_G4
+ default n
+ ---help---
+ Enable the on-chip ADC oversampling/accumulation block for the
+ regular group (CFGR2.ROVSE).
+
+if STM32_ADC5_OVERSAMPLE
+
+config STM32_ADC5_TROVS
+ bool "Enable triggered oversampling (CFGR2.TROVS)"
+ default n
+ ---help---
+ If set, each trigger starts one conversion of the whole
+ oversampling ratio. If not set, a trigger starts a single
+ conversion and the remaining ones follow automatically.
+
+config STM32_ADC5_OVSR
+ int "Oversampling ratio (CFGR2.OVSR)"
+ default 0
+ range 0 7
+ ---help---
+ Sets the oversampling ratio as 2^(OVSR+1). For example:
+ 0 -> 2x
+ 1 -> 4x
+ 2 -> 8x
+ ...
+ 7 -> 256x
+
+config STM32_ADC5_OVSS
+ int "Oversampling right-shift bits (CFGR2.OVSS)"
+ default 0
+ range 0 8
+ ---help---
+ Sets how many bits the accumulated result is right-shifted.
+ The data register is 16 bits wide: ratios above 16x with
+ OVSS below log2(ratio) - 4 overflow it silently.
+
+endif # STM32_ADC5_OVERSAMPLE
+
+endmenu # ADC Oversampling Configuration
+
+menu "ADC Configuration"
+ depends on STM32_HAVE_ADC_H5 && STM32_ADC
+
config STM32_ADC1_WDG1
bool "Enable STM32H5 ADC1 Watchdog 1"
depends on STM32_ADC1
@@ -376,45 +547,6 @@ config STM32_ADC1_WDG1_CHAN
---help---
Select the channel to enable for ADC1 Watchdog 1.
-config STM32_ADC2_OVERSAMPLE
- bool "Enable ADC2 hardware oversampling support"
- depends on STM32_ADC2
- default n
- ---help---
- Enable the on-chip ADC oversampling/accumulation block
(CFGR2.OVSE).
- Only STM32G0 and STM32L0 series include this hardware block.
-
-if STM32_ADC2_OVERSAMPLE
-
-config STM32_ADC2_TROVS
- bool "Enable triggered oversampling (CFGR2.TROVS)"
- default n
- ---help---
- If set, oversampling will only occur when a trigger event
occurs.
- If not set, oversampling occurs continuously (TOVS=0).
-
-config STM32_ADC2_OVSR
- int "Oversampling ratio (CFGR2.OVSR)"
- default 0
- range 0 7
- ---help---
- Sets the oversampling ratio as 2^(OVSR+1). For example:
- 0 -> 2×
- 1 -> 4×
- 2 -> 8×
- ...
- 7 -> 256×
-
-config STM32_ADC2_OVSS
- int "Oversampling right-shift bits (CFGR2.OVSS)"
- default 0
- range 0 8
- ---help---
- Sets how many bits the accumulated result is right-shifted.
- Max of 8-bits.
-
-endif # STM32_ADC2_OVERSAMPLE
-
config STM32_ADC2_WDG1
bool "Enable STM32H5 ADC2 Watchdog 1"
depends on STM32_ADC2
diff --git a/arch/arm/src/common/stm32/Kconfig.have
b/arch/arm/src/common/stm32/Kconfig.have
index 4b203d3ce83..b4078735ea7 100644
--- a/arch/arm/src/common/stm32/Kconfig.have
+++ b/arch/arm/src/common/stm32/Kconfig.have
@@ -77,6 +77,10 @@ config STM32_HAVE_ADC_OVERSAMPLE
bool
default STM32_STM32L0 || STM32_STM32G0 || STM32_STM32C0 || STM32_STM32U0
+config STM32_HAVE_ADC_OVERSAMPLE_G4
+ bool
+ default ARCH_CHIP_STM32G4
+
config STM32_HAVE_SDADC1
bool
diff --git a/arch/arm/src/common/stm32/stm32_adc_m3m4_v1v2.c
b/arch/arm/src/common/stm32/stm32_adc_m3m4_v1v2.c
index 61688e281a6..abaf3378b83 100644
--- a/arch/arm/src/common/stm32/stm32_adc_m3m4_v1v2.c
+++ b/arch/arm/src/common/stm32/stm32_adc_m3m4_v1v2.c
@@ -405,6 +405,15 @@
# define ADC_DIFSEL_ALL_DIFF 0x7ffff
#endif
+#if defined(HAVE_IP_ADC_V2) && \
+ (defined(CONFIG_STM32_ADC1_OVERSAMPLE) || \
+ defined(CONFIG_STM32_ADC2_OVERSAMPLE) || \
+ defined(CONFIG_STM32_ADC3_OVERSAMPLE) || \
+ defined(CONFIG_STM32_ADC4_OVERSAMPLE) || \
+ defined(CONFIG_STM32_ADC5_OVERSAMPLE))
+# define ADC_HAVE_OVERSAMPLE
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -2907,6 +2916,83 @@ static void adc_dma_start(struct adc_dev_s *dev)
}
#endif /* ADC_HAVE_DMA */
+#ifdef ADC_HAVE_OVERSAMPLE
+/****************************************************************************
+ * Name: adc_oversample_set
+ *
+ * Description:
+ * Configure the regular group hardware oversampler (CFGR2). The fields
+ * can only be written while ADSTART is 0, which is the case here because
+ * the ADC is configured before the first conversion is started.
+ *
+ ****************************************************************************/
+
+static void adc_oversample_set(struct stm32_dev_s *priv)
+{
+ uint32_t regval = 0;
+
+ switch (priv->intf)
+ {
+#ifdef CONFIG_STM32_ADC1_OVERSAMPLE
+ case 1:
+ regval = ADC_CFGR2_ROVSE |
+ (CONFIG_STM32_ADC1_OVSR << ADC_CFGR2_OVSR_SHIFT) |
+ (CONFIG_STM32_ADC1_OVSS << ADC_CFGR2_OVSS_SHIFT);
+# ifdef CONFIG_STM32_ADC1_TROVS
+ regval |= ADC_CFGR2_TROVS;
+# endif
+ break;
+#endif
+#ifdef CONFIG_STM32_ADC2_OVERSAMPLE
+ case 2:
+ regval = ADC_CFGR2_ROVSE |
+ (CONFIG_STM32_ADC2_OVSR << ADC_CFGR2_OVSR_SHIFT) |
+ (CONFIG_STM32_ADC2_OVSS << ADC_CFGR2_OVSS_SHIFT);
+# ifdef CONFIG_STM32_ADC2_TROVS
+ regval |= ADC_CFGR2_TROVS;
+# endif
+ break;
+#endif
+#ifdef CONFIG_STM32_ADC3_OVERSAMPLE
+ case 3:
+ regval = ADC_CFGR2_ROVSE |
+ (CONFIG_STM32_ADC3_OVSR << ADC_CFGR2_OVSR_SHIFT) |
+ (CONFIG_STM32_ADC3_OVSS << ADC_CFGR2_OVSS_SHIFT);
+# ifdef CONFIG_STM32_ADC3_TROVS
+ regval |= ADC_CFGR2_TROVS;
+# endif
+ break;
+#endif
+#ifdef CONFIG_STM32_ADC4_OVERSAMPLE
+ case 4:
+ regval = ADC_CFGR2_ROVSE |
+ (CONFIG_STM32_ADC4_OVSR << ADC_CFGR2_OVSR_SHIFT) |
+ (CONFIG_STM32_ADC4_OVSS << ADC_CFGR2_OVSS_SHIFT);
+# ifdef CONFIG_STM32_ADC4_TROVS
+ regval |= ADC_CFGR2_TROVS;
+# endif
+ break;
+#endif
+#ifdef CONFIG_STM32_ADC5_OVERSAMPLE
+ case 5:
+ regval = ADC_CFGR2_ROVSE |
+ (CONFIG_STM32_ADC5_OVSR << ADC_CFGR2_OVSR_SHIFT) |
+ (CONFIG_STM32_ADC5_OVSS << ADC_CFGR2_OVSS_SHIFT);
+# ifdef CONFIG_STM32_ADC5_TROVS
+ regval |= ADC_CFGR2_TROVS;
+# endif
+ break;
+#endif
+ default:
+ break;
+ }
+
+ adc_modifyreg(priv, STM32_ADC_CFGR2_OFFSET,
+ ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_MASK |
+ ADC_CFGR2_OVSS_MASK | ADC_CFGR2_TROVS, regval);
+}
+#endif /* ADC_HAVE_OVERSAMPLE */
+
/****************************************************************************
* Name: adc_configure
****************************************************************************/
@@ -2992,6 +3078,12 @@ static void adc_configure(struct adc_dev_s *dev)
adc_putreg(priv, STM32_ADC_DIFSEL_OFFSET, priv->difsel);
#endif
+#ifdef ADC_HAVE_OVERSAMPLE
+ /* Configure hardware oversampling */
+
+ adc_oversample_set(priv);
+#endif
+
/* Enable ADC */
adc_enable(priv, true);