WIP deep sleep mode

This commit is contained in:
Joey Castillo 2021-08-03 18:00:07 -04:00
parent 8a06636833
commit fc31739eb6
9 changed files with 126 additions and 51 deletions

View 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
if (application_state.debounce_wait) return;
application_state.debounce_wait = true;
application_state.enter_deep_sleep = true;
}

View File

@ -138,14 +138,14 @@
// <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
@ -165,7 +165,7 @@
// <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
@ -264,7 +264,7 @@
// <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
@ -291,7 +291,7 @@
// <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
@ -313,7 +313,7 @@
// <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
@ -355,7 +355,7 @@
// <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
@ -723,7 +723,7 @@
// </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 >>>

View File

@ -114,14 +114,14 @@
// <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
@ -132,7 +132,7 @@
// <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

View 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

View 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);
}
/* disable RTC_IRQn */
NVIC_DisableIRQ(RTC_IRQn);
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);
/* 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);
}
}
/**

View 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)

View 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);

View File

@ -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.

View 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);
}