diff options
| author | Damien George | 2020-11-12 14:35:43 +1100 |
|---|---|---|
| committer | Damien George | 2020-11-13 11:23:52 +1100 |
| commit | cc2a35b7b241e7eda031db424bf9b3afb8b6204b (patch) | |
| tree | f20dff9634a7bde8a5a1c3a532613b425d59d14a | |
| parent | a0623a081c0dde50aa8d87b464232f2d7866f951 (diff) | |
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 <damien@micropython.org>
| -rw-r--r-- | ports/stm32/boards/stm32f0xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32f4xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32f7xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32h7xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32l0xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32l4xx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | ports/stm32/boards/stm32wbxx_hal_conf_base.h | 1 | ||||
| -rw-r--r-- | 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 faceda2f4..5c6f31d1d 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 cdae0c562..8d8bb8f4e 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 05ab10fea..83a144f8f 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 9f43da403..231f1ac7f 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 b100daaa9..6b5ece766 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 cfffcffbb..215e798b9 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 83d07ad5b..91309e286 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 18ecf7750..bd898d455 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; } } |
