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>
This commit is contained in:
parent
a0623a081c
commit
cc2a35b7b2
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue