Skip to content

Commit a0e5e96

Browse files
committed
Fix STM RTC read so it's atomic.
Fixes #3376
1 parent 699f19f commit a0e5e96

File tree

1 file changed

+17
-1
lines changed

1 file changed

+17
-1
lines changed

ports/stm/supervisor/port.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ safe_mode_t port_init(void) {
190190
_hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
191191

192192
HAL_RTC_Init(&_hrtc);
193+
HAL_RTCEx_EnableBypassShadow(&_hrtc);
193194
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
194195

195196
// Turn off SysTick
@@ -328,9 +329,23 @@ volatile uint32_t cached_date = 0;
328329
volatile uint32_t seconds_to_minute = 0;
329330
volatile uint32_t cached_hours_minutes = 0;
330331
uint64_t port_get_raw_ticks(uint8_t* subticks) {
331-
uint32_t subseconds = rtc_clock_frequency - (uint32_t)(RTC->SSR);
332+
// Disable IRQs to ensure we read all of the RTC registers as close in time as possible. Read
333+
// SSR twice to make sure we didn't read across a tick.
334+
__disable_irq();
335+
uint32_t first_ssr = (uint32_t)(RTC->SSR);
332336
uint32_t time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
333337
uint32_t date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
338+
uint32_t ssr = (uint32_t)(RTC->SSR);
339+
while (ssr != first_ssr) {
340+
first_ssr = ssr;
341+
time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
342+
date = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK);
343+
ssr = (uint32_t)(RTC->SSR);
344+
}
345+
__enable_irq();
346+
347+
uint32_t subseconds = rtc_clock_frequency - 1 - ssr;
348+
334349
if (date != cached_date) {
335350
uint32_t year = (uint8_t)((date & (RTC_DR_YT | RTC_DR_YU)) >> 16U);
336351
uint8_t month = (uint8_t)((date & (RTC_DR_MT | RTC_DR_MU)) >> 8U);
@@ -349,6 +364,7 @@ uint64_t port_get_raw_ticks(uint8_t* subticks) {
349364
hours = (uint8_t)RTC_Bcd2ToByte(hours);
350365
minutes = (uint8_t)RTC_Bcd2ToByte(minutes);
351366
seconds_to_minute = 60 * (60 * hours + minutes);
367+
cached_hours_minutes = hours_minutes;
352368
}
353369
uint8_t seconds = (uint8_t)(time & (RTC_TR_ST | RTC_TR_SU));
354370
seconds = (uint8_t)RTC_Bcd2ToByte(seconds);

0 commit comments

Comments
 (0)