]> git.earman.xyz Git - sensor-watch.git/commitdiff
WIP deep sleep mode
authorJoey Castillo <jose.castillo@gmail.com>
Tue, 3 Aug 2021 22:00:07 +0000 (18:00 -0400)
committerJoey Castillo <jose.castillo@gmail.com>
Tue, 3 Aug 2021 22:09:58 +0000 (18:09 -0400)
Sensor Watch Starter Project/app.c
watch-library/config/hpl_eic_config.h
watch-library/config/hpl_rtc_config.h
watch-library/hal/include/hpl_calendar.h
watch-library/hpl/rtc/hpl_rtc.c
watch-library/hw/atmel_start_pins.h
watch-library/hw/driver_init.c
watch-library/main.c
watch-library/watch/watch.c

index 4e44deb741af535a35c08976450a9e5fd6440f5a..c3eddcbc85639fbba5f69d033f0844be663a55ea 100644 (file)
@@ -23,6 +23,7 @@ typedef struct ApplicationState {
     LightColor color;
     uint8_t wake_count;
     bool debounce_wait;
+    bool enter_deep_sleep;
 } ApplicationState;
 
 ApplicationState application_state;
@@ -58,7 +59,10 @@ void app_init() {
  * @see watch_enter_deep_sleep()
  */
 void app_wake_from_deep_sleep() {
-    // TODO: deep sleep demo
+    // retrieve our application state from the backup registers
+    application_state.mode = (ApplicationMode)watch_get_backup_data(0);
+    application_state.color = (LightColor)watch_get_backup_data(1);
+    application_state.wake_count = (uint8_t)watch_get_backup_data(2) + 1;
 }
 
 /**
@@ -141,6 +145,24 @@ bool app_loop() {
     // Wait a moment to debounce button input
     delay_ms(250);
 
+    if (application_state.enter_deep_sleep) {
+        application_state.enter_deep_sleep = false;
+
+        // stash our application state in the backup registers
+        watch_store_backup_data((uint32_t)application_state.mode, 0);
+        watch_store_backup_data((uint32_t)application_state.color, 1);
+        watch_store_backup_data((uint32_t)application_state.wake_count, 2);
+
+        // turn off the LED
+        watch_set_led_off();
+
+        // wait a moment for the user's finger to be off the button
+        delay_ms(1000);
+
+        // nap time :)
+        watch_enter_deep_sleep();
+    }
+
     return true;
 }
 
@@ -161,5 +183,7 @@ void cb_mode_pressed() {
 }
 
 void cb_alarm_pressed() {
-    // TODO: deep sleep demo
-}
\ No newline at end of file
+    if (application_state.debounce_wait) return;
+    application_state.debounce_wait = true;
+    application_state.enter_deep_sleep = true;
+}
index 3b268a10efc41d8b68b2019818874113484f3954..5066be662c58d90d0b7e6d83bde4b27953d8218f 100644 (file)
 // <e> Interrupt 2 Settings
 // <id> eic_arch_enable_irq_setting2
 #ifndef CONF_EIC_ENABLE_IRQ_SETTING2
-#define CONF_EIC_ENABLE_IRQ_SETTING2 0
+#define CONF_EIC_ENABLE_IRQ_SETTING2 1
 #endif
 
 // <q> External Interrupt 2 Filter Enable
 // <i> Indicates whether the external interrupt 2 filter is enabled or not
 // <id> eic_arch_filten2
 #ifndef CONF_EIC_FILTEN2
-#define CONF_EIC_FILTEN2 0
+#define CONF_EIC_FILTEN2 1
 #endif
 
 // <q> External Interrupt 2 Event Output Enable
 // <i> This defines input sense trigger
 // <id> eic_arch_sense2
 #ifndef CONF_EIC_SENSE2
-#define CONF_EIC_SENSE2 EIC_NMICTRL_NMISENSE_NONE_Val
+#define CONF_EIC_SENSE2 EIC_NMICTRL_NMISENSE_RISE_Val
 #endif
 
 // <q> External Interrupt 2 Asynchronous Edge Detection Mode
 // <e> Interrupt 5 Settings
 // <id> eic_arch_enable_irq_setting5
 #ifndef CONF_EIC_ENABLE_IRQ_SETTING5
-#define CONF_EIC_ENABLE_IRQ_SETTING5 1
+#define CONF_EIC_ENABLE_IRQ_SETTING5 0
 #endif
 
 // <q> External Interrupt 5 Filter Enable
 // <i> This defines input sense trigger
 // <id> eic_arch_sense5
 #ifndef CONF_EIC_SENSE5
-#define CONF_EIC_SENSE5 EIC_NMICTRL_NMISENSE_RISE_Val
+#define CONF_EIC_SENSE5 EIC_NMICTRL_NMISENSE_NONE_Val
 #endif
 
 // <q> External Interrupt 5 Asynchronous Edge Detection Mode
 // <i> Indicates whether the external interrupt 6 filter is enabled or not
 // <id> eic_arch_filten6
 #ifndef CONF_EIC_FILTEN6
-#define CONF_EIC_FILTEN6 0
+#define CONF_EIC_FILTEN6 1
 #endif
 
 // <q> External Interrupt 6 Event Output Enable
 // <i> Indicates whether the external interrupt 7 filter is enabled or not
 // <id> eic_arch_filten7
 #ifndef CONF_EIC_FILTEN7
-#define CONF_EIC_FILTEN7 0
+#define CONF_EIC_FILTEN7 1
 #endif
 
 // <q> External Interrupt 7 Event Output Enable
 
 // </e>
 
-#define CONFIG_EIC_EXTINT_MAP {5, PIN_PB05}, {6, PIN_PA22}, {7, PIN_PA23},
+#define CONFIG_EIC_EXTINT_MAP {2, PIN_PA02}, {6, PIN_PA22}, {7, PIN_PA23},
 
 // <<< end of configuration section >>>
 
index 9085ca3758595827885e93126c4bd830266d93d4..582a1c237e0cd486be6148b8e5c944c0ce5ac5fe 100644 (file)
 // <e> RTC Tamper Input 2 settings
 // <id> tamper_input_2_settings
 #ifndef CONF_TAMPER_INPUT_2_SETTINGS
-#define CONF_TAMPER_INPUT_2_SETTINGS 0
+#define CONF_TAMPER_INPUT_2_SETTINGS 1
 #endif
 
 // <q> Tamper Level Settings
 // <i> Indicates Tamper input 2 level
 // <id> tamper_level_2
 #ifndef CONF_RTC_TAMP_LVL_2
-#define CONF_RTC_TAMP_LVL_2 0
+#define CONF_RTC_TAMP_LVL_2 1
 #endif
 
 // <o> RTC Tamper Input Action
 // <i> These bits define the RTC Tamper Input Action to be performed
 // <id> rtc_tamper_input_action_2
 #ifndef CONF_RTC_TAMPER_INACT_2
-#define CONF_RTC_TAMPER_INACT_2 0
+#define CONF_RTC_TAMPER_INACT_2 1
 #endif
 
 // <q> Debounce Enable for Tamper Input
index 16601d3a56ff9420ecc4f3546bc5e08e935c4e84..87b1a5a811d1c8c78be9b87183f0b7ddf4f89792 100644 (file)
@@ -77,12 +77,7 @@ enum calendar_alarm_mode { ONESHOT = 1, REPEAT };
 /**
  * \brief Prototype of callback on alarm match
  */
-typedef void (*calendar_drv_cb_alarm_t)(struct calendar_dev *const dev);
-
-/**
- * \brief Prototype of callback on tamper detect
- */
-typedef void (*tamper_drv_cb_t)(struct calendar_dev *const dev);
+typedef void (*calendar_drv_cb_t)(struct calendar_dev *const dev);
 
 /**
  * \brief Structure of Calendar instance
@@ -91,9 +86,11 @@ struct calendar_dev {
        /** Pointer to the hardware base */
        void *hw;
        /** Alarm match callback */
-       calendar_drv_cb_alarm_t callback;
+       calendar_drv_cb_t callback_alarm;
        /** Tamper callback */
-       tamper_drv_cb_t callback_tamper;
+       calendar_drv_cb_t callback_tamper;
+       /** Tamper callback */
+       calendar_drv_cb_t callback_tick;
        /** IRQ struct */
        struct _irq_descriptor irq;
 };
@@ -236,7 +233,7 @@ uint32_t _calendar_get_comp(struct calendar_dev *const dev);
  *
  * \return ERR_NONE on success, or an error code on failure.
  */
-int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_alarm_t callback);
+int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback);
 
 /**
  * \brief Set calendar IRQ
@@ -245,6 +242,16 @@ int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv
  */
 void _calendar_set_irq(struct calendar_dev *const dev);
 
+/**
+ * \brief Register callback for 1Hz tick from prescaler
+ *
+ * \param[in] dev The pointer to calendar device struct
+ * \param[in] callback The pointer to callback function
+ *
+ * \return ERR_NONE on success, or an error code on failure.
+ */
+int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback);
+
 /**
  * \brief Register callback for tamper detection
  *
@@ -253,7 +260,7 @@ void _calendar_set_irq(struct calendar_dev *const dev);
  *
  * \return ERR_NONE on success, or an error code on failure.
  */
-int32_t _tamper_register_callback(struct calendar_dev *const dev, tamper_drv_cb_t callback_tamper);
+int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback);
 
 /**
  * \brief Find tamper is detected on specified pin
index c28ddec64887445f57467823b991e868a0d43660..0d119da1d0d18527cc3cf070e9fdc2cbf0f483e1 100644 (file)
@@ -99,7 +99,9 @@ int32_t _calendar_deinit(struct calendar_dev *const dev)
        ASSERT(dev && dev->hw);
 
        NVIC_DisableIRQ(RTC_IRQn);
-       dev->callback = NULL;
+       dev->callback_alarm = NULL;
+       dev->callback_tick = NULL;
+       dev->callback_tamper = NULL;
 
        hri_rtcmode0_clear_CTRLA_ENABLE_bit(dev->hw);
        hri_rtcmode0_set_CTRLA_SWRST_bit(dev->hw);
@@ -302,27 +304,49 @@ int32_t _tamper_disable_debounce_majority(struct calendar_dev *const dev)
        return return_value;
 }
 
-int32_t _tamper_register_callback(struct calendar_dev *const dev, tamper_drv_cb_t callback_tamper)
+int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback)
 {
        ASSERT(dev && dev->hw);
 
        /* Check callback */
-       if (callback_tamper != NULL) {
+       if (callback != NULL) {
                /* register the callback */
-               dev->callback_tamper = callback_tamper;
+               dev->callback_tick = callback;
 
                /* enable RTC_IRQn */
                NVIC_ClearPendingIRQ(RTC_IRQn);
                NVIC_EnableIRQ(RTC_IRQn);
 
-               /* enable tamper interrupt */
+               /* enable periodic interrupt */
                hri_rtcmode0_set_INTEN_PER7_bit(dev->hw);
        } else {
-               /* disable tamper interrupt */
+               /* disable periodic interrupt */
                hri_rtcmode0_clear_INTEN_PER7_bit(dev->hw);
+       }
+
+       return ERR_NONE;
+}
+
+// TODO: refactor this so it doesn't take a callback (it will never get called anyway)
+int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback)
+{
+       ASSERT(dev && dev->hw);
 
-               /* disable RTC_IRQn */
-               NVIC_DisableIRQ(RTC_IRQn);
+       /* Check callback */
+       if (callback != NULL) {
+               /* register the callback */
+               dev->callback_tamper = callback;
+
+               /* enable RTC_IRQn */
+               NVIC_ClearPendingIRQ(RTC_IRQn);
+               NVIC_EnableIRQ(RTC_IRQn);
+
+               hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);
+               /* enable tamper interrupt */
+               hri_rtcmode0_set_INTEN_TAMPER_bit(dev->hw);
+       } else {
+               /* disable tamper interrupt */
+               hri_rtcmode0_clear_INTEN_TAMPER_bit(dev->hw);
        }
 
        return ERR_NONE;
@@ -330,14 +354,14 @@ int32_t _tamper_register_callback(struct calendar_dev *const dev, tamper_drv_cb_
 /**
  * \brief Registers callback for the specified callback type
  */
-int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_alarm_t callback)
+int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback)
 {
        ASSERT(dev && dev->hw);
 
        /* Check callback */
        if (callback != NULL) {
                /* register the callback */
-               dev->callback = callback;
+               dev->callback_alarm = callback;
 
                /* enable RTC_IRQn */
                NVIC_ClearPendingIRQ(RTC_IRQn);
@@ -348,9 +372,6 @@ int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv
        } else {
                /* disable cmp */
                hri_rtcmode0_clear_INTEN_CMP0_bit(dev->hw);
-
-               /* disable RTC_IRQn */
-               NVIC_DisableIRQ(RTC_IRQn);
        }
 
        return ERR_NONE;
@@ -368,15 +389,18 @@ static void _rtc_interrupt_handler(struct calendar_dev *dev)
        uint16_t interrupt_enabled = hri_rtcmode0_read_INTEN_reg(dev->hw);
 
        if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
-               dev->callback(dev);
+               dev->callback_alarm(dev);
 
                /* Clear interrupt flag */
                hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw);
        } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
-               dev->callback_tamper(dev);
+               dev->callback_tick(dev);
 
                /* Clear interrupt flag */
                hri_rtcmode0_clear_interrupt_PER7_bit(dev->hw);
+       } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
+               /* Clear interrupt flag */
+               hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);
        }
 }
 /**
index 36fe6bf4b945eadd7beb215118063075e042e6c7..28dc9919ce13cb23e3132ff8aef5c921913d9924 100644 (file)
@@ -49,7 +49,7 @@
 #define A2 GPIO(GPIO_PORTB, 2)
 #define D0 GPIO(GPIO_PORTB, 3)
 #define A0 GPIO(GPIO_PORTB, 4)
-#define BTN_ALARM GPIO(GPIO_PORTB, 5)
+#define BTN_ALARM GPIO(GPIO_PORTA, 2)
 #define COM0 GPIO(GPIO_PORTB, 6)
 #define COM1 GPIO(GPIO_PORTB, 7)
 #define COM2 GPIO(GPIO_PORTB, 8)
index 4f1f8eee65dfc3a20010f416bf09ecd0ab5dd3d1..02907feb782ebd5e67dd72ee8c6e29e8380c9138 100644 (file)
@@ -50,7 +50,7 @@ void EXTERNAL_IRQ_0_init(void) {
                               // <GPIO_PULL_DOWN"> Pull-down
                               GPIO_PULL_DOWN);
 
-       gpio_set_pin_function(BTN_ALARM, PINMUX_PB05A_EIC_EXTINT5);
+       gpio_set_pin_function(BTN_ALARM, PINMUX_PA02A_EIC_EXTINT2);
 
        // Set pin direction to input
        gpio_set_pin_direction(BTN_LIGHT, GPIO_DIRECTION_IN);
index 67e47896cc6e574a8d5844504dd47e4fcc7281ec..42d0b56a7ac341608a5b109aad44b61ba335e8ce 100755 (executable)
@@ -43,7 +43,6 @@
 
 //-----------------------------------------------------------------------------
 HAL_GPIO_PIN(UART_TX,   B, 0)
-HAL_GPIO_PIN(UART_RX,   B, 2)
 
 //-----------------------------------------------------------------------------
 static void uart_init(uint32_t baud) {
@@ -51,8 +50,6 @@ static void uart_init(uint32_t baud) {
 
     HAL_GPIO_UART_TX_out();
     HAL_GPIO_UART_TX_pmuxen(HAL_GPIO_PMUX_C);
-    HAL_GPIO_UART_RX_in();
-    HAL_GPIO_UART_RX_pmuxen(HAL_GPIO_PMUX_C);
 
     MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM3;
 
@@ -92,10 +89,15 @@ int main(void) {
     // User code. Give the app a chance to initialize its data structures and state.
     app_init();
 
-    // At this point, if the RTC peripheral is enabled, we are waking from BACKUP.
+    // If the RTC is already enabled, we're either waking from BACKUP mode or a reset.
+    // Ideally we should check if the TAMPER or CMP0 (alarm) flags are set.
     if (watch_rtc_is_enabled()) {
         // User code. Give the application a chance to restore state from backup registers.
         app_wake_from_deep_sleep();
+
+        // disable the tamper interrupt and clear the tamper bit
+        hri_rtcmode0_clear_INTEN_TAMPER_bit(RTC);
+        hri_rtcmode0_clear_interrupt_TAMPER_bit(RTC);
     }
 
     // Watch library code. Set initial parameters for the device and enable the RTC.
index 82b7467c256c00903048eb3b27021ffd1a5d96e7..922aeb0acbe751c83816213ed7a439d72818be8c 100644 (file)
@@ -271,8 +271,7 @@ static void tick_callback(struct calendar_dev *const dev) {
 
 void watch_enable_tick_callback(ext_irq_cb_t callback) {
     tick_user_callback = callback;
-    // TODO: rename this method to reflect that it now sets the PER7 interrupt.
-    _tamper_register_callback(&CALENDAR_0.device, &tick_callback);
+    _prescaler_register_callback(&CALENDAR_0.device, &tick_callback);
 }
 
 static bool ADC_0_ENABLED = false;
@@ -359,8 +358,27 @@ uint32_t watch_get_backup_data(uint8_t reg) {
     return 0;
 }
 
-void watch_enter_deep_sleep(){
-    // Not yet implemented.
-    // TODO: enable tamper interrupt on ALARM pin.
-    // sleep(5);
+static void extwake_callback(struct calendar_dev *const dev) {
+    // this will never get called since we are basically waking from reset
+}
+
+void watch_enter_deep_sleep() {
+    // enable and configure the external wake interrupt
+    _extwake_register_callback(&CALENDAR_0.device, &extwake_callback);
+    _tamper_enable_debounce_asynchronous(&CALENDAR_0.device);
+
+    // disable SLCD
+    slcd_sync_deinit(&SEGMENT_LCD_0);
+    hri_mclk_clear_APBCMASK_SLCD_bit(SLCD);
+
+    // TODO: disable other peripherals
+
+    // disable EIC interrupt on ALARM pin (if any) and enable RTC interrupt.
+    ext_irq_disable(BTN_ALARM);
+    gpio_set_pin_direction(BTN_ALARM, GPIO_DIRECTION_IN);
+    gpio_set_pin_pull_mode(BTN_ALARM, GPIO_PULL_DOWN);
+    gpio_set_pin_function(BTN_ALARM, PINMUX_PA02G_RTC_IN2);
+
+    // go into backup sleep mode
+    sleep(5);
 }