LightColor color;
uint8_t wake_count;
bool debounce_wait;
+ bool enter_deep_sleep;
} ApplicationState;
ApplicationState application_state;
* @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;
}
/**
// 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;
}
}
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;
+}
// <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 >>>
// <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
/**
* \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
/** 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;
};
*
* \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
*/
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
*
*
* \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
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);
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;
/**
* \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);
} else {
/* disable cmp */
hri_rtcmode0_clear_INTEN_CMP0_bit(dev->hw);
-
- /* disable RTC_IRQn */
- NVIC_DisableIRQ(RTC_IRQn);
}
return ERR_NONE;
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);
}
}
/**
#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)
// <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);
//-----------------------------------------------------------------------------
HAL_GPIO_PIN(UART_TX, B, 0)
-HAL_GPIO_PIN(UART_RX, B, 2)
//-----------------------------------------------------------------------------
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;
// 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.
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;
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);
}