Skip to content

Commit 0b2f857

Browse files
committed
STM: monotonic time even when RTC is changed
1 parent c75a768 commit 0b2f857

File tree

3 files changed

+61
-43
lines changed

3 files changed

+61
-43
lines changed

ports/stm/peripherals/rtc.c

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ volatile uint32_t cached_date = 0;
4747
volatile uint32_t seconds_to_minute = 0;
4848
volatile uint32_t cached_hours_minutes = 0;
4949

50+
// The RTC starts at 2000-01-01 when it comes up.
51+
// If the RTC is set to a later time, the ticks the RTC returns will be offset by the new time.
52+
// Remember that offset so it can be removed when returning a monotonic tick count.
53+
static int64_t rtc_ticks_offset;
54+
5055
volatile bool alarmed_already[2];
5156

5257
bool peripherals_wkup_on = false;
@@ -59,6 +64,8 @@ uint32_t stm32_peripherals_get_rtc_freq(void) {
5964
}
6065

6166
void stm32_peripherals_rtc_init(void) {
67+
rtc_ticks_offset = 0;
68+
6269
// RTC oscillator selection is handled in peripherals/<family>/<line>/clocks.c
6370
__HAL_RCC_RTC_ENABLE();
6471
hrtc.Instance = RTC;
@@ -74,49 +81,9 @@ void stm32_peripherals_rtc_init(void) {
7481
HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
7582
}
7683

77-
#if CIRCUITPY_RTC
78-
void stm32_peripherals_rtc_get_time(timeutils_struct_time_t *tm) {
79-
RTC_DateTypeDef date = {0};
80-
RTC_TimeTypeDef time = {0};
81-
82-
int code;
83-
if ((code = HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN)) == HAL_OK &&
84-
(code = HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN)) == HAL_OK) {
85-
tm->tm_hour = time.Hours;
86-
tm->tm_min = time.Minutes;
87-
tm->tm_sec = time.Seconds;
88-
tm->tm_wday = date.WeekDay - 1;
89-
tm->tm_mday = date.Date;
90-
tm->tm_mon = date.Month;
91-
tm->tm_year = date.Year + 2000;
92-
tm->tm_yday = -1;
93-
}
94-
}
95-
96-
void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
97-
RTC_DateTypeDef date = {0};
98-
RTC_TimeTypeDef time = {0};
99-
100-
time.Hours = tm->tm_hour;
101-
time.Minutes = tm->tm_min;
102-
time.Seconds = tm->tm_sec;
103-
date.WeekDay = tm->tm_wday + 1;
104-
date.Date = tm->tm_mday;
105-
date.Month = tm->tm_mon;
106-
date.Year = tm->tm_year - 2000;
107-
time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
108-
time.StoreOperation = RTC_STOREOPERATION_RESET;
109-
110-
if (HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK ||
111-
HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK) {
112-
// todo - throw an exception
113-
}
114-
}
115-
#endif
116-
11784
// This function is called often for timing so we cache the seconds elapsed computation based on the
11885
// register value. The STM HAL always does shifts and conversion if we use it directly.
119-
uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
86+
STATIC uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
12087
// Disable IRQs to ensure we read all of the RTC registers as close in time as possible. Read
12188
// SSR twice to make sure we didn't read across a tick.
12289
__disable_irq();
@@ -164,6 +131,57 @@ uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
164131
return raw_ticks;
165132
}
166133

134+
// This function returns monotonically increasing ticks by adjusting away the RTC tick offset
135+
// from the last time the date was set.
136+
uint64_t stm32_peripherals_rtc_monotonic_ticks(uint8_t *subticks) {
137+
return stm32_peripherals_rtc_raw_ticks(subticks) - rtc_ticks_offset;
138+
}
139+
140+
#if CIRCUITPY_RTC
141+
void stm32_peripherals_rtc_get_time(timeutils_struct_time_t *tm) {
142+
RTC_DateTypeDef date = {0};
143+
RTC_TimeTypeDef time = {0};
144+
145+
int code;
146+
if ((code = HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN)) == HAL_OK &&
147+
(code = HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN)) == HAL_OK) {
148+
tm->tm_hour = time.Hours;
149+
tm->tm_min = time.Minutes;
150+
tm->tm_sec = time.Seconds;
151+
tm->tm_wday = date.WeekDay - 1;
152+
tm->tm_mday = date.Date;
153+
tm->tm_mon = date.Month;
154+
tm->tm_year = date.Year + 2000;
155+
tm->tm_yday = -1;
156+
}
157+
}
158+
159+
void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
160+
RTC_DateTypeDef date = {0};
161+
RTC_TimeTypeDef time = {0};
162+
163+
uint64_t current_monotonic_ticks = stm32_peripherals_rtc_monotonic_ticks(NULL);
164+
165+
time.Hours = tm->tm_hour;
166+
time.Minutes = tm->tm_min;
167+
time.Seconds = tm->tm_sec;
168+
date.WeekDay = tm->tm_wday + 1;
169+
date.Date = tm->tm_mday;
170+
date.Month = tm->tm_mon;
171+
date.Year = tm->tm_year - 2000;
172+
time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
173+
time.StoreOperation = RTC_STOREOPERATION_RESET;
174+
175+
if (HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BIN) != HAL_OK ||
176+
HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BIN) != HAL_OK) {
177+
// todo - throw an exception
178+
}
179+
180+
rtc_ticks_offset = stm32_peripherals_rtc_raw_ticks(NULL) - current_monotonic_ticks;
181+
;
182+
}
183+
#endif
184+
167185
void stm32_peripherals_rtc_assign_wkup_callback(void (*callback)(void)) {
168186
wkup_callback = callback;
169187
}

ports/stm/peripherals/rtc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
uint32_t stm32_peripherals_get_rtc_freq(void);
3838
void stm32_peripherals_rtc_init(void);
39-
uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks);
39+
uint64_t stm32_peripherals_rtc_monotonic_ticks(uint8_t *subticks);
4040

4141
void stm32_peripherals_rtc_assign_wkup_callback(void (*callback)(void));
4242
void stm32_peripherals_rtc_set_wakeup_mode_seconds(uint32_t seconds);

ports/stm/supervisor/port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ __attribute__((used)) void HardFault_Handler(void) {
385385
}
386386

387387
uint64_t port_get_raw_ticks(uint8_t *subticks) {
388-
return stm32_peripherals_rtc_raw_ticks(subticks);
388+
return stm32_peripherals_rtc_monotonic_ticks(subticks);
389389
}
390390

391391
// Enable 1/1024 second tick.

0 commit comments

Comments
 (0)