diff options
Diffstat (limited to 'watch-library/watch/watch_deepsleep.c')
-rw-r--r-- | watch-library/watch/watch_deepsleep.c | 116 |
1 files changed, 74 insertions, 42 deletions
diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c index e5494e79..8120617b 100644 --- a/watch-library/watch/watch_deepsleep.c +++ b/watch-library/watch/watch_deepsleep.c @@ -22,24 +22,18 @@ * SOFTWARE. */ -static void extwake_callback(uint8_t reason); -ext_irq_cb_t btn_alarm_callback; -ext_irq_cb_t a2_callback; -ext_irq_cb_t a4_callback; - - static void extwake_callback(uint8_t reason) { - if (reason & RTC_TAMPID_TAMPID2) { - if (btn_alarm_callback != NULL) btn_alarm_callback(); - } else if (reason & RTC_TAMPID_TAMPID1) { - if (a2_callback != NULL) a2_callback(); - } else if (reason & RTC_TAMPID_TAMPID0) { - if (a4_callback != NULL) a4_callback(); - } -} +#include "watch_extint.h" + +// this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying, +// but i'd rather have it warn us at build-time than fail silently at run-time. +// besides, no one but me really has any of these boards anyway. +#if BTN_ALARM != GPIO(GPIO_PORTA, 2) +#warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead. +#endif void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) { uint32_t pinmux; - hri_rtc_tampctrl_reg_t config = hri_rtc_get_TAMPCTRL_reg(RTC, 0xFFFFFFFF); + hri_rtc_tampctrl_reg_t config = RTC->MODE2.TAMPCTRL.reg; switch (pin) { case A4: @@ -77,16 +71,45 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le gpio_set_pin_function(pin, pinmux); // disable the RTC + RTC->MODE2.CTRLA.bit.ENABLE = 0; + while (RTC->MODE2.SYNCBUSY.bit.ENABLE); + + // update the configuration + RTC->MODE2.TAMPCTRL.reg = config; + // re-enable the RTC + RTC->MODE2.CTRLA.bit.ENABLE = 1; + + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_EnableIRQ(RTC_IRQn); + RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_TAMPER; +} + +void watch_disable_extwake_interrupt(uint8_t pin) { + hri_rtc_tampctrl_reg_t config = hri_rtc_get_TAMPCTRL_reg(RTC, 0xFFFFFFFF); + + switch (pin) { + case A4: + a4_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN0ACT_Pos); + break; + case A2: + a2_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN1ACT_Pos); + break; + case BTN_ALARM: + btn_alarm_callback = NULL; + config &= ~(3 << RTC_TAMPCTRL_IN2ACT_Pos); + break; + default: + return; + } + if (hri_rtcmode0_get_CTRLA_ENABLE_bit(RTC)) { hri_rtcmode0_clear_CTRLA_ENABLE_bit(RTC); hri_rtcmode0_wait_for_sync(RTC, RTC_MODE0_SYNCBUSY_ENABLE); } - // update the configuration hri_rtc_write_TAMPCTRL_reg(RTC, config); - // re-enable the RTC hri_rtcmode0_set_CTRLA_ENABLE_bit(RTC); - - _extwake_register_callback(&CALENDAR_0.device, extwake_callback); } void watch_store_backup_data(uint32_t data, uint8_t reg) { @@ -128,23 +151,12 @@ void _watch_disable_all_peripherals_except_slcd() { MCLK->APBCMASK.reg &= ~MCLK_APBCMASK_SERCOM3; } -void watch_enter_deep_sleep(char *message) { - // configure the ALARM interrupt (the callback doesn't matter) - watch_register_extwake_callback(BTN_ALARM, NULL, true); - - if (message != NULL) { - watch_display_string(" ", 0); - watch_display_string(message, 0); - } else { - slcd_sync_deinit(&SEGMENT_LCD_0); - hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); - } - +void watch_enter_sleep_mode() { // disable all other peripherals _watch_disable_all_peripherals_except_slcd(); // disable tick interrupt - watch_register_tick_callback(NULL); + watch_rtc_disable_all_periodic_callbacks(); // disable brownout detector interrupt, which could inadvertently wake us up. SUPC->INTENCLR.bit.BOD33DET = 1; @@ -152,21 +164,29 @@ void watch_enter_deep_sleep(char *message) { // disable all pins _watch_disable_all_pins_except_rtc(); - // turn off RAM completely. - PM->STDBYCFG.bit.BBIASHS = 3; - - // enter standby (4); we basically hang out here until an interrupt forces us to reset. + // enter standby (4); we basically hang out here until an interrupt wakes us. sleep(4); - NVIC_SystemReset(); + // and we awake! re-enable the brownout detector + SUPC->INTENSET.bit.BOD33DET = 1; + + // call app_setup so the app can re-enable everything we disabled. + app_setup(); + + // and call app_wake_from_standby (since main won't have a chance to do it) + app_wake_from_standby(); } -void watch_enter_backup_mode() { - // this will not work on the current silicon revision, but I said in the documentation that we do it. - // so let's do it! - watch_register_extwake_callback(BTN_ALARM, NULL, true); +void watch_enter_deep_sleep_mode() { + // identical to sleep mode except we disable the LCD first. + slcd_sync_deinit(&SEGMENT_LCD_0); + hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); + + watch_enter_sleep_mode(); +} - watch_register_tick_callback(NULL); +void watch_enter_backup_mode() { + watch_rtc_disable_all_periodic_callbacks(); _watch_disable_all_peripherals_except_slcd(); slcd_sync_deinit(&SEGMENT_LCD_0); hri_mclk_clear_APBCMASK_SLCD_bit(SLCD); @@ -175,3 +195,15 @@ void watch_enter_backup_mode() { // go into backup sleep mode (5). when we exit, the reset controller will take over. sleep(5); } + +// deprecated +void watch_enter_shallow_sleep(bool display_on) { + if (display_on) watch_enter_sleep_mode(); + else watch_enter_deep_sleep_mode(); +} + +// deprecated +void watch_enter_deep_sleep() { + watch_register_extwake_callback(BTN_ALARM, NULL, true); + watch_enter_backup_mode(); +} |