From 80883a82c0dd40178933eb8a46b2877cb72725b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 Dec 2020 12:23:09 +1100 Subject: [PATCH] stm32/adc: Deselect VBAT after reading to prevent battery drain. Signed-off-by: Damien George --- ports/stm32/adc.c | 8 ++--- ports/stm32/adc.h | 31 ++++++++++++++++++++ ports/stm32/boards/stm32f4xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32f7xx_hal_conf_base.h | 1 + ports/stm32/machine_adc.c | 8 ++++- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 3793ef5ff28a2..5fa22d7c78d3a 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -380,16 +380,14 @@ STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32 adc_config_channel(adcHandle, channel); uint32_t raw_value = adc_read_channel(adcHandle); - #if defined(STM32F4) || defined(STM32F7) // ST docs say that (at least on STM32F42x and STM32F43x), VBATE must // be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT // conversions to work. VBATE is enabled by the above call to read // the channel, and here we disable VBATE so a subsequent call for // TEMPSENSOR or VREFINT works correctly. - if (channel == ADC_CHANNEL_VBAT) { - ADC->CCR &= ~ADC_CCR_VBATE; - } - #endif + // It's also good to disable the VBAT switch to prevent battery drain, + // so disable it for all MCUs. + adc_deselect_vbat(adcHandle->Instance, channel); return raw_value; } diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h index 4ae6022bc3362..6f2e61e099449 100644 --- a/ports/stm32/adc.h +++ b/ports/stm32/adc.h @@ -29,4 +29,35 @@ extern const mp_obj_type_t pyb_adc_type; extern const mp_obj_type_t pyb_adc_all_type; +#if defined(ADC_CHANNEL_VBAT) + +static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) { + (void)adc; + + if (channel == ADC_CHANNEL_VBAT) { + ADC_Common_TypeDef *adc_common; + + #if defined(STM32F0) || defined(STM32WB) + adc_common = ADC1_COMMON; + #elif defined(STM32F4) || defined(STM32L4) + adc_common = ADC_COMMON_REGISTER(0); + #elif defined(STM32F7) + adc_common = ADC123_COMMON; + #elif defined(STM32H7) + adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; + #endif + + adc_common->CCR &= ~LL_ADC_PATH_INTERNAL_VBAT; + } +} + +#else + +static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) { + (void)adc; + (void)channel; +} + +#endif + #endif // MICROPY_INCLUDED_STM32_ADC_H diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h index 8d8bb8f4eeccc..91f064835e03d 100644 --- a/ports/stm32/boards/stm32f4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f4xx_hal_conf_base.h @@ -53,6 +53,7 @@ #include "stm32f4xx_hal_uart.h" #include "stm32f4xx_hal_usart.h" #include "stm32f4xx_hal_wwdg.h" +#include "stm32f4xx_ll_adc.h" #include "stm32f4xx_ll_rtc.h" // Enable various HAL modules diff --git a/ports/stm32/boards/stm32f7xx_hal_conf_base.h b/ports/stm32/boards/stm32f7xx_hal_conf_base.h index 83a144f8fe7f0..1a3fca3ac86a8 100644 --- a/ports/stm32/boards/stm32f7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f7xx_hal_conf_base.h @@ -53,6 +53,7 @@ #include "stm32f7xx_hal_uart.h" #include "stm32f7xx_hal_usart.h" #include "stm32f7xx_hal_wwdg.h" +#include "stm32f7xx_ll_adc.h" #include "stm32f7xx_ll_rtc.h" // Enable various HAL modules diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 9c20f0f954989..d9e5a64da5533 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "adc.h" #if defined(STM32F0) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) #define ADC_V2 (1) @@ -335,10 +336,15 @@ STATIC uint32_t adc_config_and_read_u16(ADC_TypeDef *adc, uint32_t channel, uint return 0xffff; } + // Select, configure and read the channel. adc_config_channel(adc, channel, sample_time); uint32_t raw = adc_read_channel(adc); + + // If VBAT was sampled then deselect it to prevent battery drain. + adc_deselect_vbat(adc, channel); + + // Scale raw reading to 16 bit value using a Taylor expansion (for bits <= 16). uint32_t bits = adc_get_bits(adc); - // Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16) #if defined(STM32H7) if (bits < 8) { // For 6 and 7 bits