32
32
#include "shared/timeutils/timeutils.h"
33
33
34
34
// 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
36
38
37
39
STATIC RTC_HandleTypeDef hrtc ;
38
40
@@ -51,6 +53,8 @@ volatile uint32_t cached_hours_minutes = 0;
51
53
// If the RTC is set to a later time, the ticks the RTC returns will be offset by the new time.
52
54
// Remember that offset so it can be removed when returning a monotonic tick count.
53
55
static int64_t rtc_ticks_offset ;
56
+ // Normalized to be 0-31 inclusive, so always positive.
57
+ static uint8_t rtc_subticks_offset ;
54
58
55
59
volatile bool alarmed_already [2 ];
56
60
@@ -65,6 +69,7 @@ uint32_t stm32_peripherals_get_rtc_freq(void) {
65
69
66
70
void stm32_peripherals_rtc_init (void ) {
67
71
rtc_ticks_offset = 0 ;
72
+ rtc_subticks_offset = 0 ;
68
73
69
74
// RTC oscillator selection is handled in peripherals/<family>/<line>/clocks.c
70
75
__HAL_RCC_RTC_ENABLE ();
@@ -124,17 +129,27 @@ STATIC uint64_t stm32_peripherals_rtc_raw_ticks(uint8_t *subticks) {
124
129
uint8_t seconds = (uint8_t )(time & (RTC_TR_ST | RTC_TR_SU ));
125
130
seconds = (uint8_t )RTC_Bcd2ToByte (seconds );
126
131
if (subticks != NULL ) {
127
- * subticks = subseconds % 32 ;
132
+ * subticks = subseconds % SUBTICKS_PER_TICK ;
128
133
}
129
134
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 ;
131
136
return raw_ticks ;
132
137
}
133
138
134
139
// This function returns monotonically increasing ticks by adjusting away the RTC tick offset
135
140
// from the last time the date was set.
136
141
uint64_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 ;
138
153
}
139
154
140
155
#if CIRCUITPY_RTC
@@ -160,8 +175,10 @@ void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
160
175
RTC_DateTypeDef date = {0 };
161
176
RTC_TimeTypeDef time = {0 };
162
177
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 );
164
180
181
+ // SubSeconds will always be set to zero.
165
182
time .Hours = tm -> tm_hour ;
166
183
time .Minutes = tm -> tm_min ;
167
184
time .Seconds = tm -> tm_sec ;
@@ -177,8 +194,16 @@ void stm32_peripherals_rtc_set_time(timeutils_struct_time_t *tm) {
177
194
// todo - throw an exception
178
195
}
179
196
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 ;
182
207
}
183
208
#endif
184
209
@@ -195,7 +220,7 @@ void stm32_peripherals_rtc_set_wakeup_mode_seconds(uint32_t seconds) {
195
220
}
196
221
197
222
void 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 );
199
224
}
200
225
201
226
void stm32_peripherals_rtc_enable_wakeup_timer (void ) {
@@ -223,9 +248,9 @@ void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks) {
223
248
uint64_t raw_ticks = stm32_peripherals_rtc_raw_ticks (NULL ) + ticks ;
224
249
225
250
RTC_AlarmTypeDef alarm ;
226
- if (ticks > TICK_DIVISOR ) {
251
+ if (ticks > TICKS_PER_SECOND ) {
227
252
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 );
229
254
alarm .AlarmTime .Hours = tm .tm_hour ;
230
255
alarm .AlarmTime .Minutes = tm .tm_min ;
231
256
alarm .AlarmTime .Seconds = tm .tm_sec ;
@@ -239,7 +264,7 @@ void stm32_peripherals_rtc_set_alarm(uint8_t alarm_idx, uint32_t ticks) {
239
264
}
240
265
241
266
alarm .AlarmTime .SubSeconds = rtc_clock_frequency - 1 -
242
- ((raw_ticks % TICK_DIVISOR ) * 32 );
267
+ ((raw_ticks % TICKS_PER_SECOND ) * SUBTICKS_PER_TICK );
243
268
if (alarm .AlarmTime .SubSeconds > rtc_clock_frequency ) {
244
269
alarm .AlarmTime .SubSeconds = alarm .AlarmTime .SubSeconds +
245
270
rtc_clock_frequency ;
0 commit comments