From bdcef28075c3aafee16a62bb9fb8c9ea3c1cd6b9 Mon Sep 17 00:00:00 2001 From: Giancarlo Stasi Date: Tue, 20 Apr 2021 18:08:42 +0200 Subject: [PATCH 1/2] drivers/adc: stm32: workaround for L462xE errata 2.5.2 and stuck reads According to the ST Errata sheet ES0389 - Rev 5, section 2.5.2, the workaround to the issue of "Wrong ADC result if conversion done late after calibration or previous conversion" is to perform two consecutive ADC conversions. We found also that the same objective is achieved enabling and disabling it at every read. Moreover, this approach solves another issue found on several STM32L462VE samples, where the reads were stuck, giving always the same wrong value, that was 0 or the last calibration value. Additional clearing of ADRDY flag has been added to avoid finding it already set before next enabling. Signed-off-by: Giancarlo Stasi --- drivers/adc/adc_stm32.c | 82 ++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 656c4650f438c..b1cc02d059ef3 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -502,15 +502,61 @@ static void adc_stm32_isr(const struct device *dev) LOG_DBG("ISR triggered."); } +static int adc_stm32_enable_and_wait_stabilisation(ADC_TypeDef *adc) +{ +#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ + defined(CONFIG_SOC_SERIES_STM32L5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBX) || \ + defined(CONFIG_SOC_SERIES_STM32G0X) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) || \ + defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32WLX) + /* + * Enabling ADC modules in L4, WB, G0 and G4 series may fail if they are + * still not stabilized, this will wait for a short time to ensure ADC + * modules are properly enabled. + */ + uint32_t countTimeout = 0; + + do { + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } + countTimeout++; + if (countTimeout == 10) { + return -ETIMEDOUT; + } + } while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0); + LL_ADC_ClearFlag_ADRDY(adc); +#else + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } +#endif + return 0; +} + static int adc_stm32_read(const struct device *dev, const struct adc_sequence *sequence) { struct adc_stm32_data *data = dev->data; - int error; + const struct adc_stm32_cfg *config = dev->config; + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + int error = 0; - adc_context_lock(&data->ctx, false, NULL); - error = start_read(dev, sequence); - adc_context_release(&data->ctx, error); + if (LL_ADC_IsEnabled(adc) == 0) { + error = adc_stm32_enable_and_wait_stabilisation(adc); + } + + if (error == 0) { + adc_context_lock(&data->ctx, false, NULL); + error = start_read(dev, sequence); + adc_context_release(&data->ctx, error); + } + + if (LL_ADC_IsEnabled(adc)) { + LL_ADC_Disable(adc); + } return error; } @@ -796,32 +842,10 @@ static int adc_stm32_init(const struct device *dev) } #endif - LL_ADC_Enable(adc); - -#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32L5X) || \ - defined(CONFIG_SOC_SERIES_STM32WBX) || \ - defined(CONFIG_SOC_SERIES_STM32G0X) || \ - defined(CONFIG_SOC_SERIES_STM32G4X) || \ - defined(CONFIG_SOC_SERIES_STM32H7X) || \ - defined(CONFIG_SOC_SERIES_STM32WLX) - /* - * Enabling ADC modules in L4, WB, G0 and G4 series may fail if they are - * still not stabilized, this will wait for a short time to ensure ADC - * modules are properly enabled. - */ - uint32_t countTimeout = 0; - - while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { - if (LL_ADC_IsEnabled(adc) == 0UL) { - LL_ADC_Enable(adc); - countTimeout++; - if (countTimeout == 10) { - return -ETIMEDOUT; - } - } + err = adc_stm32_enable_and_wait_stabilisation(adc); + if (err < 0) { + return err; } -#endif config->irq_cfg_func(); From e346a72e7c132ced59bcc3652f57863a2887f064 Mon Sep 17 00:00:00 2001 From: Giancarlo Stasi Date: Fri, 16 Jul 2021 22:02:27 +0200 Subject: [PATCH 2/2] drivers/adc: stm32: workaround for both L462xE and G081xB errata Apply workaround for both L462xE errata 2.5.2 and G081xB errata 2.6.2, avoiding to have double enabling for a single read on G0 series. Make workaround for L462xE valid also for the async api. Signed-off-by: Giancarlo Stasi --- drivers/adc/adc_stm32.c | 102 ++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index b1cc02d059ef3..7e1cddcd8b1fe 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -319,6 +319,40 @@ static void adc_stm32_calib(const struct device *dev) } #endif +static int adc_stm32_enable_and_wait_stabilisation(ADC_TypeDef *adc) +{ +#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ + defined(CONFIG_SOC_SERIES_STM32L5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBX) || \ + defined(CONFIG_SOC_SERIES_STM32G0X) || \ + defined(CONFIG_SOC_SERIES_STM32G4X) || \ + defined(CONFIG_SOC_SERIES_STM32H7X) || \ + defined(CONFIG_SOC_SERIES_STM32WLX) + /* + * Enabling ADC modules in L4, WB, G0 and G4 series may fail if they are + * still not stabilized, this will wait for a short time to ensure ADC + * modules are properly enabled. + */ + uint32_t countTimeout = 0; + + do { + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } + countTimeout++; + if (countTimeout == 10) { + return -ETIMEDOUT; + } + } while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0); + LL_ADC_ClearFlag_ADRDY(adc); +#else + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + } +#endif + return 0; +} + static int start_read(const struct device *dev, const struct adc_sequence *sequence) { @@ -425,6 +459,12 @@ static int start_read(const struct device *dev, } #elif !defined(CONFIG_SOC_SERIES_STM32F1X) && \ !defined(STM32F3X_ADC_V2_5) + if (LL_ADC_IsEnabled(adc) == 0) { + err = adc_stm32_enable_and_wait_stabilisation(adc); + if (err) { + return err; + } + } LL_ADC_SetResolution(adc, resolution); #endif @@ -464,7 +504,13 @@ static int start_read(const struct device *dev, adc_context_start_read(&data->ctx, sequence); - return adc_context_wait_for_completion(&data->ctx); + err = adc_context_wait_for_completion(&data->ctx); + + if (LL_ADC_IsEnabled(adc)) { + LL_ADC_Disable(adc); + } + + return err; } static void adc_context_start_sampling(struct adc_context *ctx) @@ -502,61 +548,15 @@ static void adc_stm32_isr(const struct device *dev) LOG_DBG("ISR triggered."); } -static int adc_stm32_enable_and_wait_stabilisation(ADC_TypeDef *adc) -{ -#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32L5X) || \ - defined(CONFIG_SOC_SERIES_STM32WBX) || \ - defined(CONFIG_SOC_SERIES_STM32G0X) || \ - defined(CONFIG_SOC_SERIES_STM32G4X) || \ - defined(CONFIG_SOC_SERIES_STM32H7X) || \ - defined(CONFIG_SOC_SERIES_STM32WLX) - /* - * Enabling ADC modules in L4, WB, G0 and G4 series may fail if they are - * still not stabilized, this will wait for a short time to ensure ADC - * modules are properly enabled. - */ - uint32_t countTimeout = 0; - - do { - if (LL_ADC_IsEnabled(adc) == 0UL) { - LL_ADC_Enable(adc); - } - countTimeout++; - if (countTimeout == 10) { - return -ETIMEDOUT; - } - } while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0); - LL_ADC_ClearFlag_ADRDY(adc); -#else - if (LL_ADC_IsEnabled(adc) == 0UL) { - LL_ADC_Enable(adc); - } -#endif - return 0; -} - static int adc_stm32_read(const struct device *dev, const struct adc_sequence *sequence) { struct adc_stm32_data *data = dev->data; - const struct adc_stm32_cfg *config = dev->config; - ADC_TypeDef *adc = (ADC_TypeDef *)config->base; - int error = 0; - - if (LL_ADC_IsEnabled(adc) == 0) { - error = adc_stm32_enable_and_wait_stabilisation(adc); - } - - if (error == 0) { - adc_context_lock(&data->ctx, false, NULL); - error = start_read(dev, sequence); - adc_context_release(&data->ctx, error); - } + int error; - if (LL_ADC_IsEnabled(adc)) { - LL_ADC_Disable(adc); - } + adc_context_lock(&data->ctx, false, NULL); + error = start_read(dev, sequence); + adc_context_release(&data->ctx, error); return error; }