@@ -109,9 +109,17 @@ LOG_MODULE_REGISTER(adc_stm32);
109109 st_adc_oversampler,\
110110 value) 0)
111111
112+ #define ANY_CHILD_NODE_IS_DIFFERENTIAL (inst ) \
113+ (DT_INST_FOREACH_CHILD_VARGS(inst, IS_EQ_NODE_PROP_OR, \
114+ zephyr_differential, \
115+ 0, 1) 0)
116+
112117#define IS_EQ_PROP_OR (inst , prop , default_value , compare_value ) \
113118 IS_EQ(DT_INST_PROP_OR(inst, prop, default_value), compare_value) ||
114119
120+ #define IS_EQ_NODE_PROP_OR (node , prop , default_value , compare_value ) \
121+ IS_EQ(DT_PROP_OR(node, prop, default_value), compare_value) ||
122+
115123#define IS_EQ_STRING_PROP (inst , prop , compare_value ) \
116124 IS_EQ(DT_INST_STRING_UPPER_TOKEN(inst, prop), compare_value) ||
117125
@@ -187,6 +195,7 @@ struct adc_stm32_cfg {
187195 size_t pclk_len ;
188196 uint32_t clk_prescaler ;
189197 const struct pinctrl_dev_config * pcfg ;
198+ bool differential_channels_used ;
190199 const uint16_t sampling_time_table [STM32_NB_SAMPLING_TIME ];
191200 int8_t num_sampling_time_common_channels ;
192201 int8_t sequencer_type ;
@@ -484,11 +493,16 @@ static void adc_stm32_calibration_measure(ADC_TypeDef *adc, uint32_t *calibratio
484493}
485494#endif
486495
487- static void adc_stm32_calibration_start (const struct device * dev )
496+ static void adc_stm32_calibration_start (const struct device * dev , bool single_ended )
488497{
489498 const struct adc_stm32_cfg * config =
490499 (const struct adc_stm32_cfg * )dev -> config ;
491500 ADC_TypeDef * adc = config -> base ;
501+ #ifdef LL_ADC_SINGLE_ENDED
502+ uint32_t calib_type = single_ended ? LL_ADC_SINGLE_ENDED : LL_ADC_DIFFERENTIAL_ENDED ;
503+ #else
504+ ARG_UNUSED (single_ended );
505+ #endif
492506
493507#if defined(STM32F3XX_ADC ) || \
494508 defined(CONFIG_SOC_SERIES_STM32L4X ) || \
@@ -497,7 +511,7 @@ static void adc_stm32_calibration_start(const struct device *dev)
497511 defined(CONFIG_SOC_SERIES_STM32H7RSX ) || \
498512 defined(CONFIG_SOC_SERIES_STM32WBX ) || \
499513 defined(CONFIG_SOC_SERIES_STM32G4X )
500- LL_ADC_StartCalibration (adc , LL_ADC_SINGLE_ENDED );
514+ LL_ADC_StartCalibration (adc , calib_type );
501515#elif defined(CONFIG_SOC_SERIES_STM32C0X ) || \
502516 defined(CONFIG_SOC_SERIES_STM32F0X ) || \
503517 DT_HAS_COMPAT_STATUS_OKAY (st_stm32f1_adc ) || \
@@ -509,6 +523,7 @@ static void adc_stm32_calibration_start(const struct device *dev)
509523
510524 LL_ADC_StartCalibration (adc );
511525#elif defined(CONFIG_SOC_SERIES_STM32U5X )
526+ ARG_UNUSED (calib_type );
512527 if (adc != ADC4 ) {
513528 uint32_t dev_id = LL_DBGMCU_GetDeviceID ();
514529 uint32_t rev_id = LL_DBGMCU_GetRevisionID ();
@@ -531,9 +546,11 @@ static void adc_stm32_calibration_start(const struct device *dev)
531546 }
532547 LL_ADC_StartCalibration (adc , LL_ADC_CALIB_OFFSET );
533548#elif defined(CONFIG_SOC_SERIES_STM32H7X )
534- LL_ADC_StartCalibration (adc , LL_ADC_CALIB_OFFSET , LL_ADC_SINGLE_ENDED );
549+ LL_ADC_StartCalibration (adc , LL_ADC_CALIB_OFFSET , calib_type );
535550#elif defined(CONFIG_SOC_SERIES_STM32N6X )
536551 uint32_t calibration_factor ;
552+
553+ ARG_UNUSED (calib_type );
537554 /* Start ADC calibration */
538555 LL_ADC_StartCalibration (adc , LL_ADC_SINGLE_ENDED );
539556 /* Disable additional offset before calibration start */
@@ -580,7 +597,10 @@ static int adc_stm32_calibrate(const struct device *dev)
580597#if !DT_HAS_COMPAT_STATUS_OKAY (st_stm32f1_adc ) && \
581598 !defined(CONFIG_SOC_SERIES_STM32N6X )
582599 adc_stm32_disable (adc );
583- adc_stm32_calibration_start (dev );
600+ adc_stm32_calibration_start (dev , true);
601+ if (config -> differential_channels_used ) {
602+ adc_stm32_calibration_start (dev , false);
603+ }
584604 adc_stm32_calibration_delay (dev );
585605#endif /* !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */
586606
@@ -592,7 +612,7 @@ static int adc_stm32_calibrate(const struct device *dev)
592612#if DT_HAS_COMPAT_STATUS_OKAY (st_stm32f1_adc ) || \
593613 defined(CONFIG_SOC_SERIES_STM32N6X )
594614 adc_stm32_calibration_delay (dev );
595- adc_stm32_calibration_start (dev );
615+ adc_stm32_calibration_start (dev , true );
596616#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */
597617
598618#if defined(CONFIG_SOC_SERIES_STM32H7X ) && \
@@ -1287,18 +1307,64 @@ static int adc_stm32_sampling_time_setup(const struct device *dev, uint8_t id,
12871307 return 0 ;
12881308}
12891309
1310+ #if defined(STM32F3XX_ADC ) || \
1311+ defined(CONFIG_SOC_SERIES_STM32G4X ) || \
1312+ defined(CONFIG_SOC_SERIES_STM32H5X ) || \
1313+ defined(CONFIG_SOC_SERIES_STM32H7X ) || \
1314+ defined(CONFIG_SOC_SERIES_STM32H7RSX ) || \
1315+ defined(CONFIG_SOC_SERIES_STM32L4X ) || \
1316+ defined(CONFIG_SOC_SERIES_STM32L5X ) || \
1317+ defined(CONFIG_SOC_SERIES_STM32U5X ) || \
1318+ defined(CONFIG_SOC_SERIES_STM32WBX )
1319+ #define DIFFERENTIAL_MODE_SUPPORTED 1
1320+ #else
1321+ #define DIFFERENTIAL_MODE_SUPPORTED 0
1322+ #endif
1323+
1324+ #if DIFFERENTIAL_MODE_SUPPORTED
1325+ static void set_channel_differential_mode (ADC_TypeDef * adc , uint8_t channel_id , bool differential )
1326+ {
1327+ const uint32_t mode = differential ? LL_ADC_DIFFERENTIAL_ENDED : LL_ADC_SINGLE_ENDED ;
1328+ const uint32_t channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL (channel_id );
1329+
1330+ /* The ADC must be disabled to change the single ended / differential mode setting. The
1331+ * disable / re-enable cycle can take some time, so avoid doing this if the channel is
1332+ * already set to the correct mode.
1333+ */
1334+ if (LL_ADC_GetChannelSingleDiff (adc , channel ) == mode ) {
1335+ return ;
1336+ }
1337+
1338+ adc_stm32_disable (adc );
1339+ LL_ADC_SetChannelSingleDiff (adc , channel , mode );
1340+ adc_stm32_enable (adc );
1341+ }
1342+ #endif
1343+
12901344static int adc_stm32_channel_setup (const struct device * dev ,
12911345 const struct adc_channel_cfg * channel_cfg )
12921346{
1293- #ifdef CONFIG_SOC_SERIES_STM32H5X
1347+ #if defined( CONFIG_SOC_SERIES_STM32H5X ) || DIFFERENTIAL_MODE_SUPPORTED
12941348 const struct adc_stm32_cfg * config = (const struct adc_stm32_cfg * )dev -> config ;
12951349 ADC_TypeDef * adc = config -> base ;
12961350#endif
12971351
1352+ #if !DIFFERENTIAL_MODE_SUPPORTED
12981353 if (channel_cfg -> differential ) {
1299- LOG_ERR ("Differential channels are not supported" );
1354+ LOG_ERR ("Differential channels not supported on this SOC series " );
13001355 return - EINVAL ;
13011356 }
1357+ #else
1358+ if (channel_cfg -> differential && !config -> differential_channels_used ) {
1359+ /* At least one channel must be set to differential mode in the devicetree
1360+ * to cause a differential calibration to be performed during init.
1361+ */
1362+ LOG_ERR ("Differential calibration not done, cannot use differential mode" );
1363+ return - EINVAL ;
1364+ }
1365+
1366+ set_channel_differential_mode (adc , channel_cfg -> channel_id , channel_cfg -> differential );
1367+ #endif
13021368
13031369 if (channel_cfg -> gain != ADC_GAIN_1 ) {
13041370 LOG_ERR ("Invalid channel gain" );
@@ -1918,6 +1984,7 @@ static const struct adc_stm32_cfg adc_stm32_cfg_##index = { \
19181984 .pclk_len = DT_INST_NUM_CLOCKS(index), \
19191985 .clk_prescaler = ADC_STM32_DT_PRESC(index), \
19201986 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
1987+ .differential_channels_used = (ANY_CHILD_NODE_IS_DIFFERENTIAL(index) > 0), \
19211988 .sequencer_type = DT_INST_STRING_UPPER_TOKEN(index, st_adc_sequencer), \
19221989 .oversampler_type = DT_INST_STRING_UPPER_TOKEN(index, st_adc_oversampler), \
19231990 .sampling_time_table = DT_INST_PROP(index, sampling_times), \
0 commit comments