Merge pull request #8286 from jeromecoutant/PR_RTCWRITE

STM32 RTC : write RTC time while LPTICKER is enabled
pull/8192/merge
Martin Kojtal 2018-10-09 10:33:37 -05:00 committed by GitHub
commit 18d613111f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 26 additions and 21 deletions

View File

@ -36,8 +36,8 @@
#include "mbed_critical.h" #include "mbed_critical.h"
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM #if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
volatile uint32_t LP_continuous_time = 0; volatile uint32_t LPTICKER_counter = 0;
volatile uint32_t LP_last_RTC_time = 0; volatile uint32_t LPTICKER_RTC_time = 0;
#endif #endif
static int RTC_inited = 0; static int RTC_inited = 0;
@ -261,14 +261,14 @@ void rtc_write(time_t t)
#endif /* TARGET_STM32F1 */ #endif /* TARGET_STM32F1 */
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM #if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
/* Need to update LP_continuous_time value before new RTC time */ /* Before setting the new time, we need to update the LPTICKER_counter value */
/* rtc_read_lp function is then called */
rtc_read_lp(); rtc_read_lp();
/* LP_last_RTC_time value is updated with the new RTC time */ /* In rtc_read_lp, LPTICKER_RTC_time value has been updated with the current time */
LP_last_RTC_time = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60; /* We need now to overwrite the value with the new RTC time */
/* Note that when a new RTC time is set by HW, the RTC SubSeconds counter is reset to PREDIV_S_VALUE */
/* Save current SSR */ LPTICKER_RTC_time = (timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60) * PREDIV_S_VALUE;
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */ #endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
// Change the RTC current date/time // Change the RTC current date/time
@ -279,11 +279,6 @@ void rtc_write(time_t t)
error("HAL_RTC_SetTime error\n"); error("HAL_RTC_SetTime error\n");
} }
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
while (Read_SubSeconds != (RTC->SSR)) {
}
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
core_util_critical_section_exit(); core_util_critical_section_exit();
} }
@ -333,11 +328,18 @@ static void RTC_IRQHandler(void)
uint32_t rtc_read_lp(void) uint32_t rtc_read_lp(void)
{ {
/* RTC_time_tick is the addition of the RTC time register (in second) and the RTC sub-second register
* This time value is breaking each 24h (= 86400s = 0x15180)
* In order to get a U32 continuous time information, we use an internal counter : LPTICKER_counter
* This counter is the addition of each spent time since last function call
* Current RTC time is saved into LPTICKER_RTC_time
* NB: rtc_read_lp() output is not the time in us, but the LPTICKER_counter (frequency LSE/4 = 8kHz => 122us)
*/
core_util_critical_section_enter();
struct tm timeinfo; struct tm timeinfo;
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */ /* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
/* We don't have to read date as we bypass shadow registers */ /* We don't have to read date as we bypass shadow registers */
uint32_t Read_SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);
uint32_t Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK); uint32_t Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR); uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
@ -350,17 +352,18 @@ uint32_t rtc_read_lp(void)
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8)); timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0)); timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
uint32_t RTC_time_s = timeinfo.tm_sec + timeinfo.tm_min * 60 + timeinfo.tm_hour * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80 uint32_t RTC_time_tick = (timeinfo.tm_sec + timeinfo.tm_min * 60 + timeinfo.tm_hour * 60 * 60) * PREDIV_S_VALUE + PREDIV_S_VALUE - Read_SubSeconds; // Max 0x0001-517F * 8191 + 8191 = 0x2A2E-AE80
if (LP_last_RTC_time <= RTC_time_s) { if (LPTICKER_RTC_time <= RTC_time_tick) {
LP_continuous_time += (RTC_time_s - LP_last_RTC_time); LPTICKER_counter += (RTC_time_tick - LPTICKER_RTC_time);
} else { } else {
/* Add 24h */ /* When RTC time is 0h00.01 and was 11H59.59, difference is "current time + 24h - previous time" */
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time); LPTICKER_counter += (RTC_time_tick + 24 * 60 * 60 * PREDIV_S_VALUE - LPTICKER_RTC_time);
} }
LP_last_RTC_time = RTC_time_s; LPTICKER_RTC_time = RTC_time_tick;
return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds; core_util_critical_section_exit();
return LPTICKER_counter;
} }
void rtc_set_wake_up_timer(timestamp_t timestamp) void rtc_set_wake_up_timer(timestamp_t timestamp)
@ -380,6 +383,7 @@ void rtc_set_wake_up_timer(timestamp_t timestamp)
WakeUpCounter = 0xFFFF; WakeUpCounter = 0xFFFF;
} }
core_util_critical_section_enter();
RtcHandle.Instance = RTC; RtcHandle.Instance = RTC;
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle); HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV4) != HAL_OK) { if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV4) != HAL_OK) {
@ -389,6 +393,7 @@ void rtc_set_wake_up_timer(timestamp_t timestamp)
NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler); NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler);
irq_handler = (void (*)(void))lp_ticker_irq_handler; irq_handler = (void (*)(void))lp_ticker_irq_handler;
NVIC_EnableIRQ(RTC_WKUP_IRQn); NVIC_EnableIRQ(RTC_WKUP_IRQn);
core_util_critical_section_exit();
} }
void rtc_fire_interrupt(void) void rtc_fire_interrupt(void)