stm32/rtc: Add auto-LSE-bypass detection with fallback to LSE then LSI.
If MICROPY_HW_RTC_USE_BYPASS is enabled the RTC startup goes as follows: - RTC is started with LSE in bypass mode to begin with - if that fails to start (after a given timeout) then LSE is reconfigured in non-bypass - if that fails to start then RTC is switched to LSI
This commit is contained in:
parent
d5f0c87bb9
commit
46e5d6b889
|
@ -210,6 +210,12 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// If disabled then try normal (non-bypass) LSE first, with fallback to LSI.
|
||||||
|
// If enabled first try LSE in bypass mode. If that fails to start, try non-bypass mode, with fallback to LSI.
|
||||||
|
#ifndef MICROPY_HW_RTC_USE_BYPASS
|
||||||
|
#define MICROPY_HW_RTC_USE_BYPASS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
|
#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
|
||||||
// Provide block device macros if internal flash storage is enabled
|
// Provide block device macros if internal flash storage is enabled
|
||||||
#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl
|
#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl
|
||||||
|
|
|
@ -61,11 +61,11 @@ static mp_uint_t rtc_info;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc);
|
STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc);
|
||||||
STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse);
|
STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool rtc_use_byp);
|
||||||
STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc);
|
STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc);
|
||||||
STATIC void RTC_CalendarConfig(void);
|
STATIC void RTC_CalendarConfig(void);
|
||||||
|
|
||||||
#if defined(MICROPY_HW_RTC_USE_LSE) && MICROPY_HW_RTC_USE_LSE
|
#if MICROPY_HW_RTC_USE_LSE || MICROPY_HW_RTC_USE_BYPASS
|
||||||
STATIC bool rtc_use_lse = true;
|
STATIC bool rtc_use_lse = true;
|
||||||
#else
|
#else
|
||||||
STATIC bool rtc_use_lse = false;
|
STATIC bool rtc_use_lse = false;
|
||||||
|
@ -159,7 +159,7 @@ void rtc_init_start(bool force_init) {
|
||||||
rtc_info &= ~0x01000000;
|
rtc_info &= ~0x01000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse);
|
PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse, MICROPY_HW_RTC_USE_BYPASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_init_finalise() {
|
void rtc_init_finalise() {
|
||||||
|
@ -167,26 +167,34 @@ void rtc_init_finalise() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_info = 0x20000000;
|
rtc_info = 0;
|
||||||
if (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
|
while (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
|
||||||
if (rtc_use_lse) {
|
if (rtc_use_lse) {
|
||||||
// fall back to LSI...
|
#if MICROPY_HW_RTC_USE_BYPASS
|
||||||
rtc_use_lse = false;
|
if (RCC->BDCR & RCC_BDCR_LSEBYP) {
|
||||||
|
// LSEBYP failed, fallback to LSE non-bypass
|
||||||
|
rtc_info |= 0x02000000;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// LSE failed, fallback to LSI
|
||||||
|
rtc_use_lse = false;
|
||||||
|
rtc_info |= 0x01000000;
|
||||||
|
}
|
||||||
rtc_startup_tick = HAL_GetTick();
|
rtc_startup_tick = HAL_GetTick();
|
||||||
PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse);
|
PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse, false);
|
||||||
HAL_PWR_EnableBkUpAccess();
|
HAL_PWR_EnableBkUpAccess();
|
||||||
RTCHandle.State = HAL_RTC_STATE_RESET;
|
RTCHandle.State = HAL_RTC_STATE_RESET;
|
||||||
if (PYB_RTC_Init(&RTCHandle) != HAL_OK) {
|
|
||||||
rtc_info = 0x0100ffff; // indicate error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// init error
|
// init error
|
||||||
rtc_info = 0xffff; // indicate error
|
rtc_info |= 0xffff; // indicate error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RTC started successfully
|
||||||
|
rtc_info = 0x20000000;
|
||||||
|
|
||||||
// record if LSE or LSI is used
|
// record if LSE or LSI is used
|
||||||
rtc_info |= (rtc_use_lse << 28);
|
rtc_info |= (rtc_use_lse << 28);
|
||||||
|
|
||||||
|
@ -257,6 +265,16 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_HW_RTC_USE_BYPASS
|
||||||
|
// If LSEBYP is enabled and new state is non-bypass then disable LSEBYP
|
||||||
|
if (RCC_OscInitStruct->LSEState == RCC_LSE_ON && (RCC->BDCR & RCC_BDCR_LSEBYP)) {
|
||||||
|
CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSEON);
|
||||||
|
while (RCC->BDCR & RCC_BDCR_LSERDY) {
|
||||||
|
}
|
||||||
|
CLEAR_BIT(RCC->BDCR, RCC_BDCR_LSEBYP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set the new LSE configuration
|
// Set the new LSE configuration
|
||||||
__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
|
__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
|
||||||
}
|
}
|
||||||
|
@ -327,7 +345,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) {
|
STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse, bool rtc_use_byp) {
|
||||||
/* To change the source clock of the RTC feature (LSE, LSI), You have to:
|
/* To change the source clock of the RTC feature (LSE, LSI), You have to:
|
||||||
- Enable the power clock using __PWR_CLK_ENABLE()
|
- Enable the power clock using __PWR_CLK_ENABLE()
|
||||||
- Enable write access using HAL_PWR_EnableBkUpAccess() function before to
|
- Enable write access using HAL_PWR_EnableBkUpAccess() function before to
|
||||||
|
@ -342,12 +360,14 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) {
|
||||||
RCC_OscInitTypeDef RCC_OscInitStruct;
|
RCC_OscInitTypeDef RCC_OscInitStruct;
|
||||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
|
||||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
|
||||||
if (rtc_use_lse) {
|
#if MICROPY_HW_RTC_USE_BYPASS
|
||||||
#if MICROPY_HW_RTC_USE_BYPASS
|
if (rtc_use_byp) {
|
||||||
RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS;
|
RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS;
|
||||||
#else
|
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (rtc_use_lse) {
|
||||||
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
|
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
|
||||||
#endif
|
|
||||||
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
|
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
|
||||||
} else {
|
} else {
|
||||||
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
|
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
|
||||||
|
@ -361,14 +381,21 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) {
|
||||||
|
|
||||||
#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic
|
#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic
|
||||||
#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms
|
#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms
|
||||||
|
#define PYB_BYP_TIMEOUT_VALUE 150
|
||||||
|
|
||||||
STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) {
|
STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) {
|
||||||
// we already had a kick so now wait for the corresponding ready state...
|
// we already had a kick so now wait for the corresponding ready state...
|
||||||
if (rtc_use_lse) {
|
if (rtc_use_lse) {
|
||||||
// we now have to wait for LSE ready or timeout
|
// we now have to wait for LSE ready or timeout
|
||||||
|
uint32_t timeout = PYB_LSE_TIMEOUT_VALUE;
|
||||||
|
#if MICROPY_HW_RTC_USE_BYPASS
|
||||||
|
if (RCC->BDCR & RCC_BDCR_LSEBYP) {
|
||||||
|
timeout = PYB_BYP_TIMEOUT_VALUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
uint32_t tickstart = rtc_startup_tick;
|
uint32_t tickstart = rtc_startup_tick;
|
||||||
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
|
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
|
||||||
if ((HAL_GetTick() - tickstart ) > PYB_LSE_TIMEOUT_VALUE) {
|
if ((HAL_GetTick() - tickstart ) > timeout) {
|
||||||
return HAL_TIMEOUT;
|
return HAL_TIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue