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

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 7abfbddb2f1 Add additional support for STM32H5 ADC
7abfbddb2f1 is described below

commit 7abfbddb2f1b13696687be51e874db2c0b198b62
Author: kywwilson11 <kwil...@2g-eng.com>
AuthorDate: Thu Jul 10 13:46:37 2025 -0500

    Add additional support for STM32H5 ADC
    
    Put define guard around call to adc_oversample. Fixed formatting.
---
 arch/arm/src/stm32h5/Kconfig     |  94 ++++++++++++++++++++++++++++
 arch/arm/src/stm32h5/stm32_adc.c | 132 ++++++++++++++++++++++++++++++++++++++-
 arch/arm/src/stm32h5/stm32_adc.h |  16 +++++
 3 files changed, 241 insertions(+), 1 deletion(-)

diff --git a/arch/arm/src/stm32h5/Kconfig b/arch/arm/src/stm32h5/Kconfig
index d480668e4f5..18ffdcfbb88 100644
--- a/arch/arm/src/stm32h5/Kconfig
+++ b/arch/arm/src/stm32h5/Kconfig
@@ -895,6 +895,14 @@ config STM32H5_ADC_MAX_SAMPLES
                for all supported devices, the user can change the default
                values in the board initialization logic and avoid ADC overrun.
 
+config STM32H5_ADC1_RESOLUTION
+       int "ADC1 resolution"
+       depends on STM32H5_ADC1
+       default 0
+       range 0 3
+       ---help---
+               ADC1 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit
+
 config STM32H5_ADC1_DMA
        bool "ADC1 DMA Enable"
        depends on STM32H5_ADC1 && STM32H5_DMA
@@ -921,6 +929,53 @@ config STM32H5_ADC1_DMA_CFG
        ---help---
                0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode
 
+config STM32H5_ADC1_OVERSAMPLE
+       bool "Enable ADC1 hardware oversampling support"
+       depends on STM32H5_ADC1
+       default n
+       ---help---
+               Enable the on-chip ADC oversampling/accumulation block 
(CFGR2.OVSE).
+               Only STM32G0 and STM32L0 series include this hardware block.
+
+if STM32H5_ADC1_OVERSAMPLE
+
+config STM32H5_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).
+
+config STM32H5_ADC1_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 STM32H5_ADC1_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 # STM32H5_ADC1_OVERSAMPLE
+
+config STM32H5_ADC2_RESOLUTION
+       int "ADC2 resolution"
+       depends on STM32H5_ADC2
+       default 0
+       range 0 3
+       ---help---
+               ADC1 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit
+
 config STM32H5_ADC2_DMA
        bool "ADC2 DMA Enable"
        depends on STM32H5_ADC2 && STM32H5_DMA
@@ -948,6 +1003,45 @@ config STM32H5_ADC2_DMA_CFG
        ---help---
                0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode
 
+config STM32H5_ADC2_OVERSAMPLE
+       bool "Enable ADC2 hardware oversampling support"
+       depends on STM32H5_ADC2
+       default n
+       ---help---
+               Enable the on-chip ADC oversampling/accumulation block 
(CFGR2.OVSE).
+               Only STM32G0 and STM32L0 series include this hardware block.
+
+if STM32H5_ADC2_OVERSAMPLE
+
+config STM32H5_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 STM32H5_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 STM32H5_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 # STM32H5_ADC2_OVERSAMPLE
+
 endmenu # ADC Configuration
 
 menu "SPI Configuration"
diff --git a/arch/arm/src/stm32h5/stm32_adc.c b/arch/arm/src/stm32h5/stm32_adc.c
index 391dcd6412d..1f74265c184 100644
--- a/arch/arm/src/stm32h5/stm32_adc.c
+++ b/arch/arm/src/stm32h5/stm32_adc.c
@@ -63,6 +63,10 @@
 #pragma message "Power Management not implemented in H5 ADC driver. "
 #endif
 
+#ifndef ANIOC_SET_OVERSAMPLE
+#  define ANIOC_SET_OVERSAMPLE _ANIOC(0x0f)
+#endif
+
 /* ADC Channels/DMA *********************************************************/
 
 #define ADC_SMPR_DEFAULT    ADC_SMPR_640p5
@@ -101,6 +105,7 @@ struct stm32_dev_s
   uint8_t cchannels;    /* Number of configured channels */
   uint8_t intf;         /* ADC interface number */
   uint8_t current;      /* Current ADC channel being converted */
+  uint8_t resolution;   /* ADC resolution (0-3) */
   bool     hasdma;      /* True: This ADC supports DMA */
 #ifdef ADC_HAVE_DMA
   uint16_t dmabatch;    /* Number of conversions for DMA batch */
@@ -138,6 +143,13 @@ struct stm32_dev_s
   uint16_t *r_dmabuffer;
 #endif
 
+  bool oversample;
+#ifdef ADC_HAVE_OVERSAMPLE
+  bool trovs;
+  uint8_t ovsr;
+  uint8_t ovss;
+#endif
+
   /* List of selected ADC channels to sample */
 
   uint8_t  chanlist[CONFIG_STM32H5_ADC_MAX_SAMPLES];
@@ -190,6 +202,10 @@ static void adc_dmacfg(struct stm32_dev_s *priv,
                                struct stm32_gpdma_cfg_s *cfg);
 #endif
 
+#ifdef ADC_HAVE_OVERSAMPLE
+static void adc_oversample(struct adc_dev_s *dev);
+#endif
+
 /* ADC Interrupt Handler */
 
 static int adc_interrupt(struct adc_dev_s *dev, uint32_t regval);
@@ -235,6 +251,7 @@ static struct stm32_dev_s g_adcpriv1 =
   .irq         = STM32_IRQ_ADC1,
   .isr         = adc12_interrupt,
   .intf        = 1,
+  .resolution  = CONFIG_STM32H5_ADC1_RESOLUTION,
   .base        = STM32_ADC1_BASE,
   .mbase       = STM32_ADC1_BASE,
   .initialized = false,
@@ -259,6 +276,19 @@ static struct stm32_dev_s g_adcpriv1 =
 #else
   .hasdma      = false,
 #endif
+
+#ifdef ADC1_HAVE_OVERSAMPLE
+  .oversample = true,
+#  ifdef CONFIG_STM32H5_ADC1_TROVS
+  .trovs = true,
+#  else
+  .trovs = false,
+#  endif
+  .ovsr = CONFIG_STM32H5_ADC1_OVSR,
+  .ovss = CONFIG_STM32H5_ADC1_OVSS,
+#else
+  .oversample = false,
+#endif
 };
 
 static struct adc_dev_s g_adcdev1 =
@@ -282,6 +312,7 @@ static struct stm32_dev_s g_adcpriv2 =
   .irq         = STM32_IRQ_ADC2,
   .isr         = adc12_interrupt,
   .intf        = 2,
+  .resolution  = CONFIG_STM32H5_ADC2_RESOLUTION,
   .base        = STM32_ADC2_BASE,
   .mbase       = STM32_ADC2_BASE,
   .initialized = false,
@@ -306,6 +337,19 @@ static struct stm32_dev_s g_adcpriv2 =
 #else
   .hasdma      = false,
 #endif
+
+#ifdef ADC2_HAVE_OVERSAMPLE
+  .oversample = true,
+#  ifdef CONFIG_STM32H5_ADC2_TROVS
+  .trovs = true,
+#  else
+  .trovs = false,
+#  endif
+  .ovsr = CONFIG_STM32H5_ADC2_OVSR,
+  .ovss = CONFIG_STM32H5_ADC2_OVSS,
+#else
+  .oversample = false,
+#endif
 };
 
 static struct adc_dev_s g_adcdev2 =
@@ -776,6 +820,28 @@ static void adc_setupclock(struct stm32_dev_s *priv)
   adc_modifyreg(priv, STM32_ADC_CCR_OFFSET, ADC_CCR_PRESC_MASK, setbits);
 }
 
+#ifdef ADC_HAVE_OVERSAMPLE
+/****************************************************************************
+ * Name: adc_oversample
+ ****************************************************************************/
+
+static void adc_oversample(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  uint32_t clrbits = ADC_CFGR2_ROVSE | ADC_CFGR2_TROVS |
+                     ADC_CFGR2_OVSR_MASK | ADC_CFGR2_OVSS_MASK;
+
+  uint32_t setbits = ADC_CFGR2_ROVSE |
+                     (priv->ovsr << ADC_CFGR2_OVSR_SHIFT) |
+                     (priv->ovss << ADC_CFGR2_OVSS_SHIFT);
+
+  setbits |= priv->trovs;
+
+  adc_modifyreg(priv, STM32_ADC_CFGR2_OFFSET, clrbits, setbits);
+}
+#endif
+
 /****************************************************************************
  * Name: adc_reset
  *
@@ -965,7 +1031,7 @@ static int adc_setup(struct adc_dev_s *dev)
   /* Set the resolution of the conversion. */
 
   clrbits = ADC_CFGR_RES_MASK | ADC_CFGR_DMACFG | ADC_CFGR_DMAEN;
-  setbits = ADC_CFGR_RES_12BIT;
+  setbits = (priv->resolution << ADC_CFGR_RES_SHIFT) & ADC_CFGR_RES_MASK;
 
 #ifdef ADC_HAVE_DMA
   if (priv->hasdma)
@@ -1031,6 +1097,13 @@ static int adc_setup(struct adc_dev_s *dev)
 
   adc_setupclock(priv);
 
+#ifdef ADC_HAVE_OVERSAMPLE
+  if (priv->oversample)
+    {
+      adc_oversample(dev);
+    }
+#endif
+
 #ifdef ADC_HAVE_DMA
 
   /* Enable DMA */
@@ -1235,6 +1308,55 @@ static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch)
   return OK;
 }
 
+#ifdef ADC_HAVE_OVERSAMPLE
+/****************************************************************************
+ * Name: adc_ioc_set_oversample
+ *
+ * Description:
+ *   For STM32G0 and STM32L0: Configure hardware oversampling via CFGR2.
+ *
+ * Input:
+ *   dev - pointer to the ADC device
+ *   arg - Packed 32-bit value that matches CFGR2 layout for OVSE, TOVS,
+ *         OVSR[2:0] and OVSS[3:0].
+ *
+ *         Bit fields (match ADC_CFGR2 register layout):
+ *           [0]     = OVSE  (enable oversampling)
+ *           [1]     = TOVS  (triggered oversampling)
+ *           [4:2]   = OVSR  (ratio: 000=2x, ..., 111=256x)
+ *           [9:5]   = OVSS  (right shift: 00000=no shift, ..., 11111=31-bit)
+ *
+ * Returned Value:
+ *   OK (0) on success
+ *
+ ****************************************************************************/
+
+static int adc_ioc_set_oversample(struct adc_dev_s *dev, uint32_t arg)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t clrbits;
+  uint32_t setbits;
+
+  /* Mask out the oversampling-related fields from CFGR2:
+   * OVSE | TOVS | OVSR[2:0] | OVSS[3:0]
+   */
+
+  clrbits = ADC_CFGR2_ROVSE     |
+            ADC_CFGR2_TROVS     |
+            ADC_CFGR2_OVSR_MASK |
+            ADC_CFGR2_OVSS_MASK;
+
+  setbits = arg & (ADC_CFGR2_ROVSE     |
+                   ADC_CFGR2_TROVS     |
+                   ADC_CFGR2_OVSR_MASK |
+                   ADC_CFGR2_OVSS_MASK);
+
+  adc_modifyreg(priv, STM32_ADC_CFGR2_OFFSET, clrbits, setbits);
+  return OK;
+}
+
+#endif
+
 /****************************************************************************
  * Name: adc_ioctl
  *
@@ -1321,6 +1443,14 @@ static int adc_ioctl(struct adc_dev_s *dev, int cmd, 
unsigned long arg)
         }
         break;
 
+#ifdef ADC_HAVE_OVERSAMPLE
+      case ANIOC_SET_OVERSAMPLE:
+        {
+          ret = adc_ioc_set_oversample(dev, arg);
+          break;
+        }
+#endif
+
       default:
         aerr("ERROR: Unknown cmd: %d\n", cmd);
         ret = -ENOTTY;
diff --git a/arch/arm/src/stm32h5/stm32_adc.h b/arch/arm/src/stm32h5/stm32_adc.h
index eec3fc4e5fc..a83b7173e66 100644
--- a/arch/arm/src/stm32h5/stm32_adc.h
+++ b/arch/arm/src/stm32h5/stm32_adc.h
@@ -97,6 +97,22 @@
 #  define ADC2_HAVE_DMA 1
 #endif
 
+/* Oversampling support */
+
+#undef ADC_HAVE_OVERSAMPLE
+#if defined(CONFIG_STM32H5_ADC1_OVERSAMPLE) || \
+    defined(CONFIG_STM32H5_ADC2_OVERSAMPLE)
+#  define ADC_HAVE_OVERSAMPLE 1
+#endif
+
+#if defined(CONFIG_STM32H5_ADC1_OVERSAMPLE)
+#  define ADC1_HAVE_OVERSAMPLE 1
+#endif
+
+#if defined(CONFIG_STM32H5_ADC2_OVERSAMPLE)
+#  define ADC2_HAVE_OVERSAMPLE 1
+#endif
+
 /* Timer configuration:  If a timer trigger is specified, then get
  * information about the timer.
  */

Reply via email to