From cc2a35b7b241e7eda031db424bf9b3afb8b6204b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 12 Nov 2020 14:35:43 +1100 Subject: [PATCH] stm32/rtc: Validate the RTC prescaler on boot and change if incorrect. Devices with RTC backup-batteries have been shown (very rarely) to have incorrect RTC prescaler values. Such incorrect values mean the RTC counts fast or slow, and will be wrong forever if the power/backup-battery is always present. This commit detects such a state at start up (hard reset) and corrects it by reconfiguring the RTC prescaler values. Signed-off-by: Damien George --- ports/stm32/boards/stm32f0xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32f4xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32f7xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32h7xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32l0xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32l4xx_hal_conf_base.h | 1 + ports/stm32/boards/stm32wbxx_hal_conf_base.h | 1 + ports/stm32/rtc.c | 40 ++++++++++++++++++-- 8 files changed, 44 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/stm32f0xx_hal_conf_base.h b/ports/stm32/boards/stm32f0xx_hal_conf_base.h index faceda2f4f..5c6f31d1dd 100644 --- a/ports/stm32/boards/stm32f0xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f0xx_hal_conf_base.h @@ -48,6 +48,7 @@ #include "stm32f0xx_hal_usart.h" #include "stm32f0xx_hal_wwdg.h" #include "stm32f0xx_ll_adc.h" +#include "stm32f0xx_ll_rtc.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h index cdae0c5629..8d8bb8f4ee 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_rtc.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32f7xx_hal_conf_base.h b/ports/stm32/boards/stm32f7xx_hal_conf_base.h index 05ab10fea0..83a144f8fe 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_rtc.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h index 9f43da4030..231f1ac7f4 100644 --- a/ports/stm32/boards/stm32h7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h @@ -54,6 +54,7 @@ #include "stm32h7xx_hal_usart.h" #include "stm32h7xx_hal_wwdg.h" #include "stm32h7xx_ll_adc.h" +#include "stm32h7xx_ll_rtc.h" // Enable various HAL modules #define HAL_ADC_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32l0xx_hal_conf_base.h b/ports/stm32/boards/stm32l0xx_hal_conf_base.h index b100daaa98..6b5ece766a 100644 --- a/ports/stm32/boards/stm32l0xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32l0xx_hal_conf_base.h @@ -47,6 +47,7 @@ #include "stm32l0xx_hal_usart.h" #include "stm32l0xx_hal_wwdg.h" #include "stm32l0xx_ll_adc.h" +#include "stm32l0xx_ll_rtc.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h index cfffcffbbe..215e798b92 100644 --- a/ports/stm32/boards/stm32l4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h @@ -51,6 +51,7 @@ #include "stm32l4xx_hal_usart.h" #include "stm32l4xx_hal_wwdg.h" #include "stm32l4xx_ll_adc.h" +#include "stm32l4xx_ll_rtc.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/boards/stm32wbxx_hal_conf_base.h b/ports/stm32/boards/stm32wbxx_hal_conf_base.h index 83d07ad5b1..91309e286f 100644 --- a/ports/stm32/boards/stm32wbxx_hal_conf_base.h +++ b/ports/stm32/boards/stm32wbxx_hal_conf_base.h @@ -42,6 +42,7 @@ #include "stm32wbxx_hal_uart.h" #include "stm32wbxx_hal_usart.h" #include "stm32wbxx_ll_adc.h" +#include "stm32wbxx_ll_rtc.h" // Enable various HAL modules #define HAL_MODULE_ENABLED diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 18ecf77505..bd898d4558 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -114,20 +114,22 @@ void rtc_init_start(bool force_init) { rtc_need_init_finalise = false; if (!force_init) { + bool rtc_running = false; uint32_t bdcr = RCC->BDCR; if ((bdcr & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL | RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) == (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_0 | RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { // LSE is enabled & ready --> no need to (re-)init RTC + rtc_running = true; // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag __HAL_RCC_CLEAR_RESET_FLAGS(); // provide some status information - rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; - return; + rtc_info |= 0x40000; } else if ((bdcr & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL)) == (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_1)) { // LSI configured as the RTC clock source --> no need to (re-)init RTC + rtc_running = true; // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag @@ -135,7 +137,39 @@ void rtc_init_start(bool force_init) { // Turn the LSI on (it may need this even if the RTC is running) RCC->CSR |= RCC_CSR_LSION; // provide some status information - rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; + rtc_info |= 0x80000; + } + + if (rtc_running) { + // Provide information about the registers that indicated the RTC is running. + rtc_info |= (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; + + // Check that the sync and async prescaler values are correct. If the RTC + // gets into a state where they are wrong then it will run slow or fast and + // never be corrected. In such a situation, attempt to reconfigure the values + // without changing the data/time. + if (LL_RTC_GetSynchPrescaler(RTC) != RTC_SYNCH_PREDIV + || LL_RTC_GetAsynchPrescaler(RTC) != RTC_ASYNCH_PREDIV) { + // Values are wrong, attempt to enter RTC init mode and change them. + LL_RTC_DisableWriteProtection(RTC); + LL_RTC_EnableInitMode(RTC); + uint32_t ticks_ms = HAL_GetTick(); + while (HAL_GetTick() - ticks_ms < RTC_TIMEOUT_VALUE) { + if (LL_RTC_IsActiveFlag_INIT(RTC)) { + // Reconfigure the RTC prescaler register PRER. + LL_RTC_SetSynchPrescaler(RTC, RTC_SYNCH_PREDIV); + LL_RTC_SetAsynchPrescaler(RTC, RTC_ASYNCH_PREDIV); + LL_RTC_DisableInitMode(RTC); + break; + } + } + LL_RTC_EnableWriteProtection(RTC); + + // Provide information that the prescaler was changed. + rtc_info |= 0x100000; + } + + // The RTC is up and running, so return without any further configuration. return; } }