]> git.earman.xyz Git - sensor-watch.git/commitdiff
Fix corner case that could cause the top of minute alarm to stop firing
authorAlessandro Genova <ales.genova@gmail.com>
Fri, 8 Aug 2025 03:34:13 +0000 (23:34 -0400)
committerAlessandro Genova <ales.genova@gmail.com>
Sat, 3 Jan 2026 01:02:36 +0000 (20:02 -0500)
watch-library/hardware/watch/watch_rtc.c
watch-library/simulator/watch/watch_rtc.c

index f81f10ffcb7acc7cd141d35f400cd60db69b3269..1fee9917f7483d680bc8babaf76e529d3966573a 100644 (file)
@@ -49,6 +49,8 @@ typedef struct {
     volatile bool enabled;
 } comp_cb_t;
 
+volatile uint32_t scheduled_comp_counter;
+
 watch_cb_t tick_callbacks[8];
 comp_cb_t comp_callbacks[WATCH_RTC_N_COMP_CB];
 watch_cb_t alarm_callback;
@@ -76,6 +78,8 @@ void _watch_rtc_init(void) {
         comp_callbacks[index].enabled = false;
     }
 
+    scheduled_comp_counter = 0;
+
     NVIC_ClearPendingIRQ(RTC_IRQn);
     NVIC_EnableIRQ(RTC_IRQn);
 }
@@ -195,10 +199,15 @@ void watch_rtc_disable_all_periodic_callbacks(void) {
 }
 
 static void _watch_rtc_schedule_next_comp(void) {
-    rtc_disable_compare_interrupt();
+    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;
+    }
 
-    // The soonest we can schedule is the next tick
-    rtc_counter_t curr_counter = watch_rtc_get_counter() + 1;
+    // Because of the hardware, the soonest we can schedule is the next tick
+    curr_counter +=1;
 
     bool schedule_any = false;
     rtc_counter_t comp_counter;
@@ -216,7 +225,14 @@ static void _watch_rtc_schedule_next_comp(void) {
     }
 
     if (schedule_any) {
-        rtc_enable_compare_interrupt(comp_counter);
+        // If we are changing the comp counter at the front of the line
+        if (comp_counter != scheduled_comp_counter) {
+            scheduled_comp_counter = comp_counter;
+            rtc_enable_compare_interrupt(comp_counter);
+        }
+    } else {
+        scheduled_comp_counter = curr_counter - 2;
+        rtc_disable_compare_interrupt();
     }
 }
 
@@ -225,8 +241,6 @@ void watch_rtc_register_comp_callback(watch_cb_t callback, rtc_counter_t counter
         return;
     }
 
-    rtc_disable_compare_interrupt();
-
     comp_callbacks[index].counter = counter;
     comp_callbacks[index].callback = callback;
     comp_callbacks[index].enabled = true;
@@ -239,8 +253,6 @@ void watch_rtc_disable_comp_callback(uint8_t index) {
         return;
     }
 
-    rtc_disable_compare_interrupt();
-
     comp_callbacks[index].enabled = false;
 
     _watch_rtc_schedule_next_comp();
index b58b6bfa7436f5b0f4a3567360fb4135882a4621..d9cfb9f2a948fc55c3e3c766263ae2152d21f9bd 100644 (file)
@@ -286,10 +286,15 @@ void watch_rtc_disable_comp_callback(uint8_t index) {
 }
 
 static void _watch_rtc_schedule_next_comp(void) {
-    scheduled_comp_counter = 0;
+    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;
+    }
 
     // The soonest we can schedule is the next tick
-    rtc_counter_t curr_counter = watch_rtc_get_counter() + 1;
+    curr_counter +=1;
 
     bool schedule_any = false;
     rtc_counter_t comp_counter;
@@ -309,6 +314,8 @@ static void _watch_rtc_schedule_next_comp(void) {
 
     if (schedule_any) {
         scheduled_comp_counter = comp_counter;
+    } else {
+        scheduled_comp_counter = curr_counter - 2;
     }
 }