From 42fdad78d5c157f6c8e1c8191e088c56bed15860 Mon Sep 17 00:00:00 2001 From: Alessandro Genova Date: Tue, 12 Aug 2025 22:28:17 -0400 Subject: [PATCH] Add more theoretical checks to ensure we don't miss out on any comp timers Even without this "fix" the watch seems to be extremely stable and haven't seen any missed timers over several days test. So this might not actually be needed, but it should make things even safer. --- watch-library/hardware/watch/watch_rtc.c | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/watch-library/hardware/watch/watch_rtc.c b/watch-library/hardware/watch/watch_rtc.c index b3c61efb..1b0b5f49 100644 --- a/watch-library/hardware/watch/watch_rtc.c +++ b/watch-library/hardware/watch/watch_rtc.c @@ -39,6 +39,8 @@ 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; +static const uint32_t RTC_COMP_GRACE_PERIOD = 4; + static const int TB_BKUP_REG = 7; #define WATCH_RTC_N_COMP_CB 8 @@ -200,14 +202,10 @@ void watch_rtc_disable_all_periodic_callbacks(void) { void watch_rtc_schedule_next_comp(void) { rtc_counter_t curr_counter = watch_rtc_get_counter(); - // If there is already a pending comp interrupt for this very tick, let it fire - // And this function will be called again as soon as the interrupt fires. - if (curr_counter == scheduled_comp_counter) { - return; - } - // Because of the hardware, the soonest we can schedule is the next tick - curr_counter += 1; + // We want to ensure we never miss any registered callbacks, + // so if a callback counter has just passed but didn't fire, give it a chance to fire. + rtc_counter_t lax_curr_counter = curr_counter - RTC_COMP_GRACE_PERIOD; bool schedule_any = false; rtc_counter_t comp_counter; @@ -215,7 +213,7 @@ void watch_rtc_schedule_next_comp(void) { for (uint8_t index = 0; index < WATCH_RTC_N_COMP_CB; ++index) { if (comp_callbacks[index].enabled) { - rtc_counter_t diff = comp_callbacks[index].counter - curr_counter; + rtc_counter_t diff = comp_callbacks[index].counter - lax_curr_counter; if (diff <= min_diff) { min_diff = diff; comp_counter = comp_callbacks[index].counter; @@ -225,13 +223,17 @@ void watch_rtc_schedule_next_comp(void) { } if (schedule_any) { - // If we are changing the comp counter at the front of the line + // If we are changing the comp counter at the front of the line, don't schedule a comp interrupt for a counter that is too close to now if (comp_counter != scheduled_comp_counter) { + rtc_counter_t earliest_comp_counter = curr_counter + RTC_COMP_GRACE_PERIOD; + if ((earliest_comp_counter - lax_curr_counter) > (comp_counter - lax_curr_counter)) { + comp_counter = earliest_comp_counter; + } scheduled_comp_counter = comp_counter; rtc_enable_compare_interrupt(comp_counter); } } else { - scheduled_comp_counter = curr_counter - 2; + scheduled_comp_counter = lax_curr_counter - RTC_COMP_GRACE_PERIOD; rtc_disable_compare_interrupt(); } } @@ -278,7 +280,7 @@ void watch_rtc_disable_comp_callback_no_schedule(uint8_t index) { void watch_rtc_callback(uint16_t interrupt_cause) { // First read all relevant registers, to ensure no changes occurr during the callbacks - rtc_counter_t comp_counter = RTC->MODE0.COMP[0].reg; + rtc_counter_t curr_counter = watch_rtc_get_counter(); uint16_t interrupt_enabled = (uint16_t)RTC->MODE0.INTENSET.reg; if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_PER_Msk) { @@ -308,7 +310,9 @@ void watch_rtc_callback(uint16_t interrupt_cause) { if ((interrupt_cause & interrupt_enabled) & RTC_MODE0_INTFLAG_CMP0) { for (uint8_t index = 0; index < WATCH_RTC_N_COMP_CB; ++index) { - if (comp_callbacks[index].enabled && comp_counter == comp_callbacks[index].counter) { + if (comp_callbacks[index].enabled && + (curr_counter - comp_callbacks[index].counter) < (RTC_COMP_GRACE_PERIOD * 4) + ) { comp_callbacks[index].enabled = false; comp_callbacks[index].callback(); }