diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index d4fbe455a9a..92ea97b5d55 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -344,6 +344,20 @@ static void adc_stm32_calib(const struct device *dev) } #endif +/* + * Disable ADC peripheral, and wait until it is disabled + */ +static inline void adc_stm32_disable(ADC_TypeDef *adc) +{ + if (LL_ADC_IsEnabled(adc) != 1UL) { + return; + } + + LL_ADC_Disable(adc); + while (LL_ADC_IsEnabled(adc) == 1UL) { + } +} + #if defined(CONFIG_SOC_SERIES_STM32G0X) || \ defined(CONFIG_SOC_SERIES_STM32G4X) || \ defined(CONFIG_SOC_SERIES_STM32H7X) || \ @@ -369,6 +383,48 @@ static void adc_stm32_calib(const struct device *dev) }; #endif /* ! ADC_VER_V5_V90 */ +/* + * Function to configure the oversampling scope. It is basically a wrapper over + * LL_ADC_SetOverSamplingScope() which in addition stops the ADC if needed. + */ +static void adc_stm32_oversampling_scope(ADC_TypeDef *adc, uint32_t ovs_scope) +{ +#if defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32WLX) + /* + * setting OVS bits is conditioned to ADC state: ADC must be disabled + * or enabled without conversion on going : disable it, it will stop + */ + if (LL_ADC_GetOverSamplingScope(adc) == ovs_scope) { + return; + } + adc_stm32_disable(adc); +#endif + LL_ADC_SetOverSamplingScope(adc, ovs_scope); +} + +/* + * Function to configure the oversampling ratio and shift. It is basically a + * wrapper over LL_ADC_SetOverSamplingRatioShift() which in addition stops the + * ADC if needed. + */ +static void adc_stm32_oversampling_ratioshift(ADC_TypeDef *adc, uint32_t ratio, uint32_t shift) +{ +#if defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32WLX) + /* + * setting OVS bits is conditioned to ADC state: ADC must be disabled + * or enabled without conversion on going : disable it, it will stop + */ + if ((LL_ADC_GetOverSamplingRatio(adc) == ratio) + && (LL_ADC_GetOverSamplingShift(adc) == shift)) { + return; + } + adc_stm32_disable(adc); +#endif + LL_ADC_ConfigOverSamplingRatioShift(adc, ratio, shift); +} + /* * Function to configure the oversampling ratio and shit using stm32 LL * ratio is directly the sequence->oversampling (a 2^n value) @@ -376,7 +432,7 @@ static void adc_stm32_calib(const struct device *dev) */ static void adc_stm32_oversampling(ADC_TypeDef *adc, uint8_t ratio, uint32_t shift) { - LL_ADC_SetOverSamplingScope(adc, LL_ADC_OVS_GRP_REGULAR_CONTINUED); + adc_stm32_oversampling_scope(adc, LL_ADC_OVS_GRP_REGULAR_CONTINUED); #if defined(CONFIG_SOC_SERIES_STM32H7X) /* * Set bits manually to circumvent bug in LL Libraries @@ -396,13 +452,13 @@ static void adc_stm32_oversampling(ADC_TypeDef *adc, uint8_t ratio, uint32_t shi #elif defined(CONFIG_SOC_SERIES_STM32U5X) if (adc == ADC1) { /* the LL function expects a value from 1 to 1024 */ - LL_ADC_ConfigOverSamplingRatioShift(adc, (1 << ratio), shift); + adc_stm32_oversampling_ratioshift(adc, (1 << ratio), shift); } else { /* the LL function expects a value LL_ADC_OVS_RATIO_x */ - LL_ADC_ConfigOverSamplingRatioShift(adc, stm32_adc_ratio_table[ratio], shift); + adc_stm32_oversampling_ratioshift(adc, stm32_adc_ratio_table[ratio], shift); } #else /* CONFIG_SOC_SERIES_STM32H7X */ - LL_ADC_ConfigOverSamplingRatioShift(adc, stm32_adc_ratio_table[ratio], shift); + adc_stm32_oversampling_ratioshift(adc, stm32_adc_ratio_table[ratio], shift); #endif /* CONFIG_SOC_SERIES_STM32H7X */ } #endif /* CONFIG_SOC_SERIES_STM32xxx */ @@ -450,20 +506,6 @@ static int adc_stm32_enable(ADC_TypeDef *adc) return 0; } -/* - * Disable ADC peripheral, and wait until it is disabled - */ -static inline void adc_stm32_disable(ADC_TypeDef *adc) -{ - if (LL_ADC_IsEnabled(adc) != 1UL) { - return; - } - - LL_ADC_Disable(adc); - while (LL_ADC_IsEnabled(adc) == 1UL) { - } -} - static int start_read(const struct device *dev, const struct adc_sequence *sequence) { @@ -560,26 +602,19 @@ static int start_read(const struct device *dev, #if defined(CONFIG_SOC_SERIES_STM32G0X) || \ defined(CONFIG_SOC_SERIES_STM32WLX) - /* - * Writing ADC_CFGR1 register while ADEN bit is set - * resets RES[1:0] bitfield. We need to disable and enable adc. - */ - adc_stm32_disable(adc); - LL_ADC_SetResolution(adc, resolution); + if (LL_ADC_GetResolution(adc) != resolution) { + /* + * Writing ADC_CFGR1 register while ADEN bit is set + * resets RES[1:0] bitfield. We need to disable and enable adc. + */ + adc_stm32_disable(adc); + LL_ADC_SetResolution(adc, resolution); + } #elif !defined(CONFIG_SOC_SERIES_STM32F1X) && \ !defined(STM32F3X_ADC_V2_5) LL_ADC_SetResolution(adc, resolution); #endif -#if defined(CONFIG_SOC_SERIES_STM32L0X) || \ - defined(CONFIG_SOC_SERIES_STM32WLX) - /* - * setting OVS bits is conditioned to ADC state: ADC must be disabled - * or enabled without conversion on going : disable it, it will stop - */ - adc_stm32_disable(adc); -#endif - #if defined(CONFIG_SOC_SERIES_STM32G0X) || \ defined(CONFIG_SOC_SERIES_STM32G4X) || \ defined(CONFIG_SOC_SERIES_STM32H7X) || \ @@ -592,7 +627,7 @@ static int start_read(const struct device *dev, switch (sequence->oversampling) { case 0: - LL_ADC_SetOverSamplingScope(adc, LL_ADC_OVS_DISABLE); + adc_stm32_oversampling_scope(adc, LL_ADC_OVS_DISABLE); break; case 1: adc_stm32_oversampling(adc, 1, LL_ADC_OVS_SHIFT_RIGHT_1);