Sfoglia il codice sorgente

nrf5/rtc: implement wakeup timer [FIRM-61]

Signed-off-by: Joshua Wise <joshua@joshuawise.com>
Joshua Wise 2 mesi fa
parent
commit
ab8a04fe1b
1 ha cambiato i file con 41 aggiunte e 5 eliminazioni
  1. 41 5
      src/fw/drivers/nrf5/rtc.c

+ 41 - 5
src/fw/drivers/nrf5/rtc.c

@@ -28,6 +28,10 @@
 #include <stdio.h>
 #include <string.h>
 
+#define OS_RTC_INST NRF_RTC1
+static void prv_rtc_irq_handler(void);
+IRQ_MAP_NRFX(RTC1, prv_rtc_irq_handler);
+
 //! The type of a raw reading from the RTC (masked to 0xFFFFFF).
 typedef uint32_t RtcIntervalTicks;
 
@@ -47,7 +51,7 @@ static RtcIntervalTicks prv_elapsed_ticks(RtcIntervalTicks before, RtcIntervalTi
 }
 
 static RtcIntervalTicks prv_get_rtc_interval_ticks(void) {
-  return nrf_rtc_counter_get(NRF_RTC1);
+  return nrf_rtc_counter_get(OS_RTC_INST);
 }
 
 /***
@@ -313,8 +317,8 @@ void rtc_init(void) {
     PBL_LOG(LOG_LEVEL_INFO, "RTC appears to have been reset :( hope you have your phone connected");
   }
 
-  nrf_rtc_prescaler_set(NRF_RTC1, NRF_RTC_FREQ_TO_PRESCALER(RTC_TICKS_HZ));
-  nrf_rtc_task_trigger(NRF_RTC1, NRF_RTC_TASK_START);
+  nrf_rtc_prescaler_set(OS_RTC_INST, NRF_RTC_FREQ_TO_PRESCALER(RTC_TICKS_HZ));
+  nrf_rtc_task_trigger(OS_RTC_INST, NRF_RTC_TASK_START);
   
   prv_restore_rtc_time_state();
   s_did_init_rtc = true;
@@ -331,17 +335,49 @@ void rtc_init_timers(void) {
   regular_timer_add_minutes_callback(&rtc_sync_timer);
 }
 
+/*** Logic to control RTC wakeup timer. ***/
+
+static RtcTicks s_alarm_set_time = 0;
+static RtcTicks s_alarm_expiry_time = 0;
+static bool s_tick_alarm_initialized = false;
 
 void rtc_alarm_init(void) {
+  nrf_rtc_event_disable(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  nrf_rtc_int_disable(OS_RTC_INST, NRF_RTC_INT_COMPARE0_MASK);
+  s_tick_alarm_initialized = true;
 }
 
 void rtc_alarm_set(RtcTicks num_ticks) {
+  PBL_ASSERTN(s_tick_alarm_initialized);
+  
+  nrf_rtc_event_disable(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  nrf_rtc_event_clear(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  
+  s_alarm_set_time = rtc_get_ticks();
+  s_alarm_expiry_time = s_alarm_set_time + num_ticks;
+  
+  /* We're bounded by the regular_timer_add_minutes_callback for the
+   * rtc_alarm_set, so we're not going to wrap around more than once -- one
+   * minute is always less than 4.5 hours.
+   */
+  nrf_rtc_cc_set(OS_RTC_INST, 0, s_alarm_expiry_time & RTC_COUNTER_COUNTER_Msk);
+  
+  nrf_rtc_event_enable(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  nrf_rtc_int_enable(OS_RTC_INST, NRF_RTC_INT_COMPARE0_MASK);
 }
 
 RtcTicks rtc_alarm_get_elapsed_ticks(void) {
-  return 0;
+  return rtc_get_ticks() - s_alarm_set_time;
 }
 
 bool rtc_alarm_is_initialized(void) {
-  return 0;
+  return s_tick_alarm_initialized;
+}
+
+//! Handler for the RTC alarm interrupt. We don't actually have to do anything in this handler,
+//! just the interrupt firing is enough to bring us out of stop mode.
+static void prv_rtc_irq_handler(void) {
+  nrf_rtc_event_disable(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  nrf_rtc_event_clear(OS_RTC_INST, NRF_RTC_EVENT_COMPARE_0);
+  nrf_rtc_int_disable(OS_RTC_INST, NRF_RTC_INT_COMPARE0_MASK);
 }