Align the top of the second with the 1Hz periodic interrupt

This commit is contained in:
Alessandro Genova
2025-08-03 01:13:19 -04:00
parent e2d13e076e
commit 7acc9cc414
3 changed files with 68 additions and 32 deletions
+19 -4
View File
@@ -34,6 +34,7 @@ static const uint32_t RTC_OSC_DIV = 10;
static const uint32_t RTC_OSC_HZ = 1 << RTC_OSC_DIV; // 2^10 = 1024
static const uint32_t RTC_PRESCALER_DIV = 3;
static const uint32_t RTC_CNT_HZ = RTC_OSC_HZ >> RTC_PRESCALER_DIV; // 1024 / 2^3 = 128
static const uint32_t RTC_CNT_SUBSECOND_MASK = RTC_CNT_HZ - 1;
static const uint32_t RTC_CNT_DIV = RTC_OSC_DIV - RTC_PRESCALER_DIV; // 7
static const uint32_t RTC_CNT_TICKS_PER_MINUTE = RTC_CNT_HZ * 60;
static const uint32_t RTC_CNT_TICKS_PER_HOUR = RTC_CNT_TICKS_PER_MINUTE * 60;
@@ -88,17 +89,31 @@ rtc_date_time_t watch_rtc_get_date_time(void) {
}
void watch_rtc_set_unix_time(unix_timestamp_t unix_time) {
// time_backup + counter / RTC_CNT_HZ = unix_time
/* unix_time = time_backup + counter / RTC_CNT_HZ - 0.5
*
* Because of the way the hardware is designed, the periodic interrupts fire at the subsecond tick values
* according to the table below (for a 128Hz counter).
* since the 1Hz periodic interrupt is the most important, we shift the conversion from counter to timestamp by 64 ticks,
* so that the second changes at the top of the 1Hz interrupt. Hence the 0.5 factor in the equation above.
* 1Hz: 64
* 2Hz: 32, 96
* 4Hz: 16, 48, 80, 112
* 8Hz: 8, 24, 40, 56, 72, 88, 104, 120
* 16Hz: 4, 12, 20, ..., 124
* 32Hz: 2, 6, 10, ..., 126
* 64Hz: 1, 3, 5, ..., 127
* 128Hz: 0, 1, 2, ..., 127
*/
rtc_counter_t counter = rtc_get_counter();
unix_timestamp_t tb = unix_time - (counter >> RTC_CNT_DIV);
unix_timestamp_t tb = unix_time - (counter >> RTC_CNT_DIV) - ((counter & RTC_CNT_SUBSECOND_MASK) >> (RTC_CNT_DIV - 1)) + 1;
watch_store_backup_data(tb, TB_BKUP_REG);
}
unix_timestamp_t watch_rtc_get_unix_time(void) {
// time_backup + counter / RTC_CNT_HZ = unix_time
// unix_time = time_backup + counter / RTC_CNT_HZ - 0.5
rtc_counter_t counter = rtc_get_counter();
unix_timestamp_t tb = watch_get_backup_data(TB_BKUP_REG);
return tb + (counter >> RTC_CNT_DIV);
return tb + (counter >> RTC_CNT_DIV) + ((counter & RTC_CNT_SUBSECOND_MASK) >> (RTC_CNT_DIV - 1)) - 1;
}
rtc_counter_t watch_rtc_get_counter(void) {