Skip to content

Commit 83caa04

Browse files
committed
STM32 RTC : write RTC time while LPTICKER is enabled
This fix avoid a long waiting loop in rtc_write function, which was not acceptable in TICKLESS context. Implementation comments added. Global variable name has been updated for easier maintenance: - LPTICKER_counter is the U32 continuous tick counter - LPTICKER_RTC_time is the RTC time used to get the time difference between rtc_read_lp() calls
1 parent 1af1a4a commit 83caa04

File tree

1 file changed

+26
-21
lines changed

1 file changed

+26
-21
lines changed

targets/TARGET_STM/rtc_api.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
#include "mbed_critical.h"
3737

3838
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
39-
volatile uint32_t LP_continuous_time = 0;
40-
volatile uint32_t LP_last_RTC_time = 0;
39+
volatile uint32_t LPTICKER_counter = 0;
40+
volatile uint32_t LPTICKER_RTC_time = 0;
4141
#endif
4242

4343
static int RTC_inited = 0;
@@ -261,14 +261,14 @@ void rtc_write(time_t t)
261261
#endif /* TARGET_STM32F1 */
262262

263263
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
264-
/* Need to update LP_continuous_time value before new RTC time */
264+
/* Before setting the new time, we need to update the LPTICKER_counter value */
265+
/* rtc_read_lp function is then called */
265266
rtc_read_lp();
266267

267-
/* LP_last_RTC_time value is updated with the new RTC time */
268-
LP_last_RTC_time = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60;
269-
270-
/* Save current SSR */
271-
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
268+
/* In rtc_read_lp, LPTICKER_RTC_time value has been updated with the current time */
269+
/* We need now to overwrite the value with the new RTC time */
270+
/* Note that when a new RTC time is set by HW, the RTC SubSeconds counter is reset to PREDIV_S_VALUE */
271+
LPTICKER_RTC_time = (timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60) * PREDIV_S_VALUE;
272272
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
273273

274274
// Change the RTC current date/time
@@ -279,11 +279,6 @@ void rtc_write(time_t t)
279279
error("HAL_RTC_SetTime error\n");
280280
}
281281

282-
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
283-
while (Read_SubSeconds != (RTC->SSR)) {
284-
}
285-
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
286-
287282
core_util_critical_section_exit();
288283
}
289284

@@ -333,11 +328,18 @@ static void RTC_IRQHandler(void)
333328

334329
uint32_t rtc_read_lp(void)
335330
{
331+
/* RTC_time_tick is the addition of the RTC time register (in second) and the RTC sub-second register
332+
* This time value is breaking each 24h (= 86400s = 0x15180)
333+
* In order to get a U32 continuous time information, we use an internal counter : LPTICKER_counter
334+
* This counter is the addition of each spent time since last function call
335+
* Current RTC time is saved into LPTICKER_RTC_time
336+
* NB: rtc_read_lp() output is not the time in us, but the LPTICKER_counter (frequency LSE/4 = 8kHz => 122us)
337+
*/
338+
core_util_critical_section_enter();
336339
struct tm timeinfo;
337340

338341
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
339342
/* We don't have to read date as we bypass shadow registers */
340-
uint32_t Read_SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);
341343
uint32_t Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
342344
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
343345

@@ -350,17 +352,18 @@ uint32_t rtc_read_lp(void)
350352
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
351353
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
352354

353-
uint32_t RTC_time_s = timeinfo.tm_sec + timeinfo.tm_min * 60 + timeinfo.tm_hour * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
355+
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
354356

355-
if (LP_last_RTC_time <= RTC_time_s) {
356-
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
357+
if (LPTICKER_RTC_time <= RTC_time_tick) {
358+
LPTICKER_counter += (RTC_time_tick - LPTICKER_RTC_time);
357359
} else {
358-
/* Add 24h */
359-
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
360+
/* When RTC time is 0h00.01 and was 11H59.59, difference is "current time + 24h - previous time" */
361+
LPTICKER_counter += (RTC_time_tick + 24 * 60 * 60 * PREDIV_S_VALUE - LPTICKER_RTC_time);
360362
}
361-
LP_last_RTC_time = RTC_time_s;
363+
LPTICKER_RTC_time = RTC_time_tick;
362364

363-
return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds;
365+
core_util_critical_section_exit();
366+
return LPTICKER_counter;
364367
}
365368

366369
void rtc_set_wake_up_timer(timestamp_t timestamp)
@@ -380,6 +383,7 @@ void rtc_set_wake_up_timer(timestamp_t timestamp)
380383
WakeUpCounter = 0xFFFF;
381384
}
382385

386+
core_util_critical_section_enter();
383387
RtcHandle.Instance = RTC;
384388
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV4) != HAL_OK) {
385389
error("rtc_set_wake_up_timer init error\n");
@@ -388,6 +392,7 @@ void rtc_set_wake_up_timer(timestamp_t timestamp)
388392
NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler);
389393
irq_handler = (void (*)(void))lp_ticker_irq_handler;
390394
NVIC_EnableIRQ(RTC_WKUP_IRQn);
395+
core_util_critical_section_exit();
391396
}
392397

393398
void rtc_fire_interrupt(void)

0 commit comments

Comments
 (0)