3232#include "shared/timeutils/timeutils.h"
3333
3434// Default period for ticks is 1/1024 second
35- #define TICK_DIVISOR 1024
35+ #define TICKS_PER_SECOND 1024
36+ // Based on a 32768 kHz clock
37+ #define SUBTICKS_PER_TICK 32
3638
3739STATIC RTC_HandleTypeDef hrtc ;
3840
@@ -51,6 +53,8 @@ volatile uint32_t cached_hours_minutes = 0;
5153// If the RTC is set to a later time, the ticks the RTC returns will be offset by the new time.
5254// Remember that offset so it can be removed when returning a monotonic tick count.
5355static int64_t rtc_ticks_offset ;
56+ // Normalized to be 0-31 inclusive, so always positive.
57+ static uint8_t rtc_subticks_offset ;
5458
5559volatile bool alarmed_already [2 ];
5660
@@ -65,6 +69,7 @@ uint32_t stm32_peripherals_get_rtc_freq(void) {
6569
6670void stm32_peripherals_rtc_init (void ) {
6771 rtc_ticks_offset = 0 ;
72+ rtc_subticks_offset = 0 ;
6873
6974 // RTC oscillator selection is handled in peripherals/<family>/<line>/clocks.c
7075 __HAL_RCC_RTC_ENABLE ();
@@ -124,17 +129,27 @@ STATIC uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
124129 uint8_t seconds = (uint8_t )(time & (RTC_TR_ST | RTC_TR_SU ));
125130 seconds = (uint8_t )RTC_Bcd2ToByte (seconds );
126131 if (subticks != NULL ) {
127- * subticks = subseconds % 32 ;
132+ * subticks = subseconds % SUBTICKS_PER_TICK ;
128133 }
129134
130- uint64_t raw_ticks = ((uint64_t )TICK_DIVISOR ) * (seconds_to_date + seconds_to_minute + seconds ) + subseconds / 32 ;
135+ uint64_t raw_ticks = ((uint64_t )TICKS_PER_SECOND ) * (seconds_to_date + seconds_to_minute + seconds ) + subseconds / SUBTICKS_PER_TICK ;
131136 return raw_ticks ;
132137}
133138
134139// This function returns monotonically increasing ticks by adjusting away the RTC tick offset
135140// from the last time the date was set.
136141uint64_t stm32_peripherals_rtc_monotonic_ticks (uint8_t * subticks ) {
137- return stm32_peripherals_rtc_raw_ticks (subticks ) - rtc_ticks_offset ;
142+ uint8_t raw_subticks ;
143+ uint64_t monotonic_ticks = stm32_peripherals_rtc_raw_ticks (& raw_subticks ) - rtc_ticks_offset ;
144+ int8_t monotonic_subticks = raw_subticks - rtc_subticks_offset ;
145+ // Difference might be negative. Normalize to 0-31.
146+ // `while` not really necessary; should only loop 0 or 1 times.
147+ while (monotonic_subticks < 0 ) {
148+ monotonic_ticks -- ;
149+ monotonic_subticks += SUBTICKS_PER_TICK ;
150+ }
151+ * subticks = (uint8_t )monotonic_subticks ;
152+ return monotonic_ticks ;
138153}
139154
140155#if CIRCUITPY_RTC
@@ -160,8 +175,10 @@ void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
160175 RTC_DateTypeDef date = {0 };
161176 RTC_TimeTypeDef time = {0 };
162177
163- uint64_t current_monotonic_ticks = stm32_peripherals_rtc_monotonic_ticks (NULL );
178+ uint8_t current_monotonic_subticks ;
179+ uint64_t current_monotonic_ticks = stm32_peripherals_rtc_monotonic_ticks (& current_monotonic_subticks );
164180
181+ // SubSeconds will always be set to zero.
165182 time .Hours = tm -> tm_hour ;
166183 time .Minutes = tm -> tm_min ;
167184 time .Seconds = tm -> tm_sec ;
@@ -177,8 +194,16 @@ void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
177194 // todo - throw an exception
178195 }
179196
180- rtc_ticks_offset = stm32_peripherals_rtc_raw_ticks (NULL ) - current_monotonic_ticks ;
181- ;
197+ uint8_t raw_subticks ;
198+ rtc_ticks_offset = stm32_peripherals_rtc_raw_ticks (& raw_subticks ) - current_monotonic_ticks ;
199+ int8_t rtc_subticks_offset_signed = raw_subticks - current_monotonic_subticks ;
200+ // Difference might be negative. Normalize subticks to 0-31.
201+ // `while` not really necessary; should only loop 0 or 1 times.
202+ while (rtc_subticks_offset_signed < 0 ) {
203+ rtc_ticks_offset -- ;
204+ rtc_subticks_offset_signed += SUBTICKS_PER_TICK ;
205+ }
206+ rtc_subticks_offset = (uint8_t )rtc_subticks_offset_signed ;
182207}
183208#endif
184209
@@ -195,7 +220,7 @@ void stm32_peripherals_rtc_set_wakeup_mode_seconds(uint32_t seconds) {
195220}
196221
197222void stm32_peripherals_rtc_set_wakeup_mode_tick (void ) {
198- HAL_RTCEx_SetWakeUpTimer_IT (& hrtc , (rtc_clock_frequency / 16 ) / TICK_DIVISOR , RTC_WAKEUPCLOCK_RTCCLK_DIV2 );
223+ HAL_RTCEx_SetWakeUpTimer_IT (& hrtc , (rtc_clock_frequency / 16 ) / TICKS_PER_SECOND , RTC_WAKEUPCLOCK_RTCCLK_DIV2 );
199224}
200225
201226void stm32_peripherals_rtc_enable_wakeup_timer (void ) {
@@ -223,9 +248,9 @@ void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks) {
223248 uint64_t raw_ticks = stm32_peripherals_rtc_raw_ticks (NULL ) + ticks ;
224249
225250 RTC_AlarmTypeDef alarm ;
226- if (ticks > TICK_DIVISOR ) {
251+ if (ticks > TICKS_PER_SECOND ) {
227252 timeutils_struct_time_t tm ;
228- timeutils_seconds_since_2000_to_struct_time (raw_ticks / TICK_DIVISOR , & tm );
253+ timeutils_seconds_since_2000_to_struct_time (raw_ticks / TICKS_PER_SECOND , & tm );
229254 alarm .AlarmTime .Hours = tm .tm_hour ;
230255 alarm .AlarmTime .Minutes = tm .tm_min ;
231256 alarm .AlarmTime .Seconds = tm .tm_sec ;
@@ -239,7 +264,7 @@ void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks) {
239264 }
240265
241266 alarm .AlarmTime .SubSeconds = rtc_clock_frequency - 1 -
242- ((raw_ticks % TICK_DIVISOR ) * 32 );
267+ ((raw_ticks % TICKS_PER_SECOND ) * SUBTICKS_PER_TICK );
243268 if (alarm .AlarmTime .SubSeconds > rtc_clock_frequency ) {
244269 alarm .AlarmTime .SubSeconds = alarm .AlarmTime .SubSeconds +
245270 rtc_clock_frequency ;
0 commit comments