From cb38f77918b7c7dde2904b7f13ad38aaf69d7350 Mon Sep 17 00:00:00 2001 From: Yuuki NAGAO Date: Sat, 8 Jul 2023 11:14:00 +0900 Subject: [PATCH] stm32/adc: Add workaround for ADC errata with G4 MCUs. For STM32G4, there is a errata on ADC that may get wrong ADC result. According to the errata sheet, this can be avoid by performing two consecutive ADC conversions and keep second result. Signed-off-by: Yuuki NAGAO --- ports/stm32/adc.c | 15 ++++++++++++--- ports/stm32/machine_adc.c | 21 +++++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 93eaa93f0..ec4a18cde 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -458,9 +458,18 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) } STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { - HAL_ADC_Start(adcHandle); - adc_wait_for_eoc_or_timeout(adcHandle, EOC_TIMEOUT); - uint32_t value = adcHandle->Instance->DR; + uint32_t value; + #if defined(STM32G4) + // For STM32G4 there is errata 2.7.7, "Wrong ADC result if conversion done late after + // calibration or previous conversion". According to the errata, this can be avoided + // by performing two consecutive ADC conversions and keeping the second result. + for (uint8_t i = 0; i < 2; i++) + #endif + { + HAL_ADC_Start(adcHandle); + adc_wait_for_eoc_or_timeout(adcHandle, EOC_TIMEOUT); + value = adcHandle->Instance->DR; + } HAL_ADC_Stop(adcHandle); return value; } diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 041b06723..fee3d698d 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -371,13 +371,22 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp } STATIC uint32_t adc_read_channel(ADC_TypeDef *adc) { - #if ADC_V2 - adc->CR |= ADC_CR_ADSTART; - #else - adc->CR2 |= ADC_CR2_SWSTART; + uint32_t value; + #if defined(STM32G4) + // For STM32G4 there is errata 2.7.7, "Wrong ADC result if conversion done late after + // calibration or previous conversion". According to the errata, this can be avoided + // by performing two consecutive ADC conversions and keeping the second result. + for (uint8_t i = 0; i < 2; i++) #endif - adc_wait_eoc(adc, ADC_EOC_TIMEOUT_MS); - uint32_t value = adc->DR; + { + #if ADC_V2 + adc->CR |= ADC_CR_ADSTART; + #else + adc->CR2 |= ADC_CR2_SWSTART; + #endif + adc_wait_eoc(adc, ADC_EOC_TIMEOUT_MS); + value = adc->DR; + } return value; } -- GitLab