diff --git a/src/fw/drivers/rtc.h b/src/fw/drivers/rtc.h index 7e7b6e052..ff31b8ad1 100644 --- a/src/fw/drivers/rtc.h +++ b/src/fw/drivers/rtc.h @@ -100,6 +100,22 @@ RtcTicks rtc_alarm_get_elapsed_ticks(void); //! us from going into stop mode before we're ready to wake up from it. bool rtc_alarm_is_initialized(void); +// RTC Wake-up +/////////////////////////////////////////////////////////////////////////////// + +//! RTC second tick callback. +typedef void (*RtcSecondTickCallback)(void *ctx); + +//! Configures the RTC to fire the given callback on every second tick. +//! +//! @note Callback happens in ISR context. +//! +//! @param callback Callback to call every time RTC increases 1 second. +//! @param ctx Context to pass to the callback when called. +void rtc_second_tick_subscribe(RtcSecondTickCallback callback, void *ctx); + +//! Unsubscribes from the RTC second tick. +void rtc_second_tick_unsubscribe(void); // Utility Functions /////////////////////////////////////////////////////////////////////////////// diff --git a/src/fw/drivers/rtc/sf32lb.c b/src/fw/drivers/rtc/sf32lb.c index dab9c1905..05159b0e3 100644 --- a/src/fw/drivers/rtc/sf32lb.c +++ b/src/fw/drivers/rtc/sf32lb.c @@ -81,6 +81,17 @@ static RTC_HandleTypeDef RTC_Handler = { static bool s_initialized = false; +static RtcSecondTickCallback s_second_tick_callback = NULL; +static void *s_second_tick_callback_ctx = NULL; + +void RTC_IRQHandler(void) { + HAL_RTC_IRQHandler(&RTC_Handler); +} + +void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { + s_second_tick_callback(s_second_tick_callback_ctx); +} + #ifndef SF32LB52_USE_LXT static uint32_t prv_rtc_get_lpcycle() { uint32_t value; @@ -204,6 +215,9 @@ void rtc_init(void) { prv_rtc_reconfig(); #endif + HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_RTC, AON_PIN_MODE_HIGH); + HAL_NVIC_SetPriority(RTC_IRQn, 5, 0); + s_initialized = true; } @@ -477,3 +491,27 @@ void rtc_calibrate_frequency(uint32_t frequency) { PBL_ASSERTN(success); #endif } + +void rtc_second_tick_subscribe(RtcSecondTickCallback callback, void *ctx) { + PBL_ASSERTN(s_second_tick_callback == NULL); + + s_second_tick_callback = callback; + s_second_tick_callback_ctx = ctx; + + RTC_AlarmTypeDef alarm = { + // Mask all fields, and subsecond mask to 8-bit (covers DIV_B=256) + .AlarmMask = RTC_ALRMDR_MSKWD | RTC_ALRMDR_MSKM | RTC_ALRMDR_MSKD | + RTC_ALRMDR_MSKH | RTC_ALRMDR_MSKMN | RTC_ALRMDR_MSKS | + (8U << RTC_ALRMDR_MSKSS_Pos), + .AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL, + }; + HAL_RTC_SetAlarm(&RTC_Handler, &alarm, RTC_FORMAT_BIN); +} + +void rtc_second_tick_unsubscribe(void) { + PBL_ASSERTN(s_second_tick_callback != NULL); + + HAL_RTC_DeactivateAlarm(&RTC_Handler); + + s_second_tick_callback = NULL; +} \ No newline at end of file diff --git a/src/fw/services/common/tick_timer.c b/src/fw/services/common/tick_timer.c index 95835f6ef..be157fa8c 100644 --- a/src/fw/services/common/tick_timer.c +++ b/src/fw/services/common/tick_timer.c @@ -10,6 +10,11 @@ #include "system/logging.h" #include "system/passert.h" +// FIXME: Move to Kconfig +#ifdef MICRO_FAMILY_SF32LB52 +#define USE_RTC_SECOND_TICK +#endif + static uint16_t s_num_subscribers; static void timer_tick_event_publisher(void* data) { @@ -18,18 +23,28 @@ static void timer_tick_event_publisher(void* data) { .clock_tick.tick_time = rtc_get_time(), }; +#ifdef USE_RTC_SECOND_TICK + event_put_isr(&e); +#else event_put(&e); +#endif } +#ifndef USE_RTC_SECOND_TICK static RegularTimerInfo s_tick_timer_info = { .cb = &timer_tick_event_publisher }; +#endif void tick_timer_add_subscriber(PebbleTask task) { ++s_num_subscribers; if (s_num_subscribers == 1) { PBL_LOG_DBG("starting tick timer"); +#ifdef USE_RTC_SECOND_TICK + rtc_second_tick_subscribe(timer_tick_event_publisher, NULL); +#else regular_timer_add_seconds_callback(&s_tick_timer_info); +#endif } } @@ -38,6 +53,10 @@ void tick_timer_remove_subscriber(PebbleTask task) { --s_num_subscribers; if (s_num_subscribers == 0) { PBL_LOG_DBG("stopping tick timer"); +#ifdef USE_RTC_SECOND_TICK + rtc_second_tick_unsubscribe(); +#else regular_timer_remove_callback(&s_tick_timer_info); +#endif } }