Skip to content

stm32/adc: add support for differential mode (DIFSEL) and calibration - #20152

Merged
acassis merged 1 commit into
apache:masterfrom
daniel-p-carvalho:feat/stm32-adc-difsel
Sep 18, 2026
Merged

acassis merged 1 commit into
apache:masterfrom
daniel-p-carvalho:feat/stm32-adc-difsel

Conversation

@daniel-p-carvalho

Copy link
Copy Markdown
Contributor

Summary

This PR adds support for ADC differential mode selection (DIFSEL) and fixes auto-calibration for STM32 ADC IPv2 and IPv2G4 (STM32F3 and STM32G4 families).

  1. Hardware Headers (stm32_adc_v2.h and stm32_adc_v2g4.h):
    • Fixed register comments and added ADC_DIFSEL shift/masks.
  2. Kconfig (Kconfig.adc):
    • Added menuconfig STM32_ADC_DIFSEL under STM32_HAVE_IP_ADC_M3M4_V2.
    • Added per-ADC configuration options: CONFIG_STM32_ADCx_DIFSEL and CONFIG_STM32_ADCx_DIFSEL_VALUE bitmask (bit $n$ = channel $n$).
  3. Driver Architecture (stm32_adc_m3m4_v1v2.h / stm32_adc_m3m4_v1v2.c):
    • Added difselcfg to ADC private structure and difselcfg_set to lower-half operations.
    • Configured DIFSEL in adc_configure() prior to enabling the ADC (adc_enable(priv, true)), strictly adhering to the ST Reference Manual (RM0440 / RM0316).
    • Re-enabled and fixed adc_calibrate() for HAVE_IP_ADC_V2: performs single-ended calibration (ADCALDIF=0) and, if differential channels are configured, differential calibration (ADCALDIF=1).
    • Cleaned up pre-existing nxstyle issues across the driver.

Impact

  • New feature: Allows configuring differential analog channels on STM32F3 and STM32G4 microcontrollers.
  • User impact: Differential mode can now be enabled cleanly via menuconfig or board headers.
  • Build impact: None. Zero impact when CONFIG_STM32_ADC_DIFSEL is disabled.
  • Hardware compatibility: Fully backwards compatible with existing single-ended ADC configurations.

Testing

  • Build Host: Linux x86_64, arm-none-eabi-gcc 13.3.rel1
  • Target: STM32G431KB (Nucleo-G431KB), configuration based on nucleo-g431rb:adc
  • Linter: ./tools/checkpatch.sh -m -g upstream/master..HEAD passes with 0 errors and 0 warnings (✔️ All checks pass.)

Hardware Validation Details

Tested on Nucleo-G431KB with ADC1 Channel 1 configured as differential input:

  • Non-inverting input ($V_{INP}$): PA0 (Pin A0)
  • Inverting input ($V_{INN}$): PA1 (Pin A1)
  1. Zero differential ($V_{INP} = V_{INN} = 0\text{ V}$, both connected to GND):
    • Before calibration: reading fluctuated around ~1999 (offset of ~48 LSB).
    • After calibration: stabilized cleanly at 2015 (expected 12-bit bipolar midpoint 2048 with minor board noise).
Sample:
1: channel: 1 value: 2015
2: channel: 2 value: 20
3: channel: 15 value: 112
  1. Positive full scale ($V_{INP} = 3.3\text{ V}$, $V_{INN} = 0\text{ V}$):
    • Pin A0 connected to 3V3, Pin A1 connected to GND ($V_{diff} = +3.3\text{ V}$).
    • Reading: 4095 (maximum positive full-scale).
Sample:
1: channel: 1 value: 4095
2: channel: 2 value: 0
3: channel: 15 value: 1863
  1. Negative full scale ($V_{INP} = 0\text{ V}$, $V_{INN} = 3.3\text{ V}$):
    • Pin A0 connected to GND, Pin A1 connected to 3V3 ($V_{diff} = -3.3\text{ V}$).
    • Reading: 0 (minimum negative full-scale).
Sample:
1: channel: 1 value: 0
2: channel: 2 value: 4095
3: channel: 15 value: 2247

jerpelea
jerpelea previously approved these changes Sep 15, 2026

@raiden00pl raiden00pl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use approach like in STM32H5:

#ifdef BOARD_ADC1_DIFSEL
.difsel = BOARD_ADC1_DIFSEL,
#else
.difsel = ADC_DIFSEL_DEFAULT,
#endif

@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Size: M The size of the change in this PR is medium labels Sep 15, 2026
@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@daniel-p-carvalho

Copy link
Copy Markdown
Contributor Author

Updated as suggested.

Refactored to follow the STM32H5 approach:

  • Removed all Kconfig options and custom lower-half operations.
  • Added difsel to struct stm32_dev_s, initialized from BOARD_ADCx_DIFSEL (if defined) or defaulting to ADC_DIFSEL_DEFAULT (0).
  • Written directly to STM32_ADC_DIFSEL_OFFSET in adc_configure().
  • Implemented calibration in adc_calibrate() supporting single-ended (ADCALDIF=0) and differential (ADCALDIF=1) calibration based on priv->difsel (matching the STM32H5 pattern).
  • Tested and verified on physical hardware (Nucleo-G431KB) with differential channel 1 against 0V, +3.3V, and -3.3V.

@github-actions github-actions Bot added Size: S The size of the change in this PR is small and removed Size: M The size of the change in this PR is medium labels Sep 16, 2026
Add board-level configuration and driver support for differential input
channels and auto-calibration on STM32 ADC IPv2 and IPv2G4 (STM32F3,
STM32G4), following the STM32H5 architecture pattern requested in review:

- In hardware headers (stm32_adc_v2.h and stm32_adc_v2g4.h), fix register
  comments and define ADC_DIFSEL register shift and masks.
- In stm32_adc_m3m4_v1v2.c:
  - Add difsel field to struct stm32_dev_s initialized from
    BOARD_ADCx_DIFSEL if defined, falling back to ADC_DIFSEL_DEFAULT (0).
  - Configure DIFSEL before enabling the ADC in adc_configure().
  - Fix and enable adc_calibrate() for HAVE_IP_ADC_V2, supporting both
    single-ended calibration (ADCALDIF=0) and differential calibration
    (ADCALDIF=1) based on the channel selection.

Verified on Nucleo-G431KB (single-ended and differential channel 1).

Assisted-by: Gemini:gemini-2.5-pro
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
@acassis
acassis merged commit 9e93888 into apache:master Sep 18, 2026
33 of 38 checks passed
@daniel-p-carvalho
daniel-p-carvalho deleted the feat/stm32-adc-difsel branch September 18, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants