work on RTC tamper interrupt and external wake
This commit is contained in:
parent
27edc50be1
commit
e45fdf15af
@ -62,6 +62,7 @@ void app_wake_from_deep_sleep() {
|
|||||||
application_state.mode = (ApplicationMode)watch_get_backup_data(0);
|
application_state.mode = (ApplicationMode)watch_get_backup_data(0);
|
||||||
application_state.color = (LightColor)watch_get_backup_data(1);
|
application_state.color = (LightColor)watch_get_backup_data(1);
|
||||||
application_state.wake_count = (uint8_t)watch_get_backup_data(2) + 1;
|
application_state.wake_count = (uint8_t)watch_get_backup_data(2) + 1;
|
||||||
|
application_state.debounce_wait = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,5 +185,8 @@ void cb_mode_pressed() {
|
|||||||
void cb_alarm_pressed() {
|
void cb_alarm_pressed() {
|
||||||
if (application_state.debounce_wait) return;
|
if (application_state.debounce_wait) return;
|
||||||
application_state.debounce_wait = true;
|
application_state.debounce_wait = true;
|
||||||
application_state.enter_deep_sleep = true;
|
// boo: http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_L22_Family_Errata_DS80000782B.pdf
|
||||||
|
// Reference 15010. doesn't say it applies to PA02 but it seems it does?
|
||||||
|
// anyway can't deep sleep now :(
|
||||||
|
// application_state.enter_deep_sleep = true;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
// <e> RTC Tamper Input 0 settings
|
// <e> RTC Tamper Input 0 settings
|
||||||
// <id> tamper_input_0_settings
|
// <id> tamper_input_0_settings
|
||||||
#ifndef CONF_TAMPER_INPUT_0_SETTINGS
|
#ifndef CONF_TAMPER_INPUT_0_SETTINGS
|
||||||
#define CONF_TAMPER_INPUT_0_SETTINGS 0
|
#define CONF_TAMPER_INPUT_0_SETTINGS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// <q> Tamper Level Settings
|
// <q> Tamper Level Settings
|
||||||
@ -66,7 +66,7 @@
|
|||||||
// <i> These bits define the RTC Tamper Input Action to be performed
|
// <i> These bits define the RTC Tamper Input Action to be performed
|
||||||
// <id> rtc_tamper_input_action_0
|
// <id> rtc_tamper_input_action_0
|
||||||
#ifndef CONF_RTC_TAMPER_INACT_0
|
#ifndef CONF_RTC_TAMPER_INACT_0
|
||||||
#define CONF_RTC_TAMPER_INACT_0 0
|
#define CONF_RTC_TAMPER_INACT_0 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// <q> Debounce Enable for Tamper Input
|
// <q> Debounce Enable for Tamper Input
|
||||||
@ -81,7 +81,7 @@
|
|||||||
// <e> RTC Tamper Input 1 settings
|
// <e> RTC Tamper Input 1 settings
|
||||||
// <id> tamper_input_1_settings
|
// <id> tamper_input_1_settings
|
||||||
#ifndef CONF_TAMPER_INPUT_1_SETTINGS
|
#ifndef CONF_TAMPER_INPUT_1_SETTINGS
|
||||||
#define CONF_TAMPER_INPUT_1_SETTINGS 0
|
#define CONF_TAMPER_INPUT_1_SETTINGS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// <q> Tamper Level Settings
|
// <q> Tamper Level Settings
|
||||||
@ -99,7 +99,7 @@
|
|||||||
// <i> These bits define the RTC Tamper Input Action to be performed
|
// <i> These bits define the RTC Tamper Input Action to be performed
|
||||||
// <id> rtc_tamper_input_action_1
|
// <id> rtc_tamper_input_action_1
|
||||||
#ifndef CONF_RTC_TAMPER_INACT_1
|
#ifndef CONF_RTC_TAMPER_INACT_1
|
||||||
#define CONF_RTC_TAMPER_INACT_1 0
|
#define CONF_RTC_TAMPER_INACT_1 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// <q> Debounce Enable for Tamper Input
|
// <q> Debounce Enable for Tamper Input
|
||||||
|
@ -77,7 +77,8 @@ enum calendar_alarm_mode { ONESHOT = 1, REPEAT };
|
|||||||
/**
|
/**
|
||||||
* \brief Prototype of callback on alarm match
|
* \brief Prototype of callback on alarm match
|
||||||
*/
|
*/
|
||||||
typedef void (*calendar_drv_cb_t)(struct calendar_dev *const dev);
|
typedef void (*calendar_drv_cb_t)();
|
||||||
|
typedef void (*calendar_drv_extwake_cb_t)(uint8_t reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Structure of Calendar instance
|
* \brief Structure of Calendar instance
|
||||||
@ -88,8 +89,8 @@ struct calendar_dev {
|
|||||||
/** Alarm match callback */
|
/** Alarm match callback */
|
||||||
calendar_drv_cb_t callback_alarm;
|
calendar_drv_cb_t callback_alarm;
|
||||||
/** Tamper callback */
|
/** Tamper callback */
|
||||||
calendar_drv_cb_t callback_tamper;
|
calendar_drv_extwake_cb_t callback_tamper;
|
||||||
/** Tamper callback */
|
/** Tick callback */
|
||||||
calendar_drv_cb_t callback_tick;
|
calendar_drv_cb_t callback_tick;
|
||||||
/** IRQ struct */
|
/** IRQ struct */
|
||||||
struct _irq_descriptor irq;
|
struct _irq_descriptor irq;
|
||||||
@ -260,7 +261,7 @@ int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_dr
|
|||||||
*
|
*
|
||||||
* \return ERR_NONE on success, or an error code on failure.
|
* \return ERR_NONE on success, or an error code on failure.
|
||||||
*/
|
*/
|
||||||
int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback);
|
int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_extwake_cb_t callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Find tamper is detected on specified pin
|
* \brief Find tamper is detected on specified pin
|
||||||
|
@ -327,8 +327,7 @@ int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_dr
|
|||||||
return ERR_NONE;
|
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_extwake_cb_t callback)
|
||||||
int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_cb_t callback)
|
|
||||||
{
|
{
|
||||||
ASSERT(dev && dev->hw);
|
ASSERT(dev && dev->hw);
|
||||||
|
|
||||||
@ -389,16 +388,20 @@ static void _rtc_interrupt_handler(struct calendar_dev *dev)
|
|||||||
uint16_t interrupt_enabled = hri_rtcmode0_read_INTEN_reg(dev->hw);
|
uint16_t interrupt_enabled = hri_rtcmode0_read_INTEN_reg(dev->hw);
|
||||||
|
|
||||||
if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
|
if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
|
||||||
dev->callback_alarm(dev);
|
dev->callback_alarm();
|
||||||
|
|
||||||
/* Clear interrupt flag */
|
/* Clear interrupt flag */
|
||||||
hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw);
|
hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw);
|
||||||
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
|
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
|
||||||
dev->callback_tick(dev);
|
dev->callback_tick();
|
||||||
|
|
||||||
/* Clear interrupt flag */
|
/* Clear interrupt flag */
|
||||||
hri_rtcmode0_clear_interrupt_PER7_bit(dev->hw);
|
hri_rtcmode0_clear_interrupt_PER7_bit(dev->hw);
|
||||||
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
|
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
|
||||||
|
uint8_t reason = hri_rtc_get_TAMPID_reg(dev->hw, 0x1F);
|
||||||
|
dev->callback_tamper(reason);
|
||||||
|
hri_rtc_write_TAMPID_reg(dev->hw, reason);
|
||||||
|
|
||||||
/* Clear interrupt flag */
|
/* Clear interrupt flag */
|
||||||
hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);
|
hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// User callbacks and other definitions
|
||||||
|
|
||||||
|
ext_irq_cb_t btn_alarm_callback;
|
||||||
|
ext_irq_cb_t a2_callback;
|
||||||
|
ext_irq_cb_t d1_callback;
|
||||||
|
|
||||||
|
static void extwake_callback(uint8_t reason);
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Initialization
|
// Initialization
|
||||||
|
|
||||||
@ -15,7 +25,14 @@ void _watch_init() {
|
|||||||
|
|
||||||
// Not sure if this belongs in every app -- is there a power impact?
|
// Not sure if this belongs in every app -- is there a power impact?
|
||||||
delay_driver_init();
|
delay_driver_init();
|
||||||
|
|
||||||
|
// set up state
|
||||||
|
btn_alarm_callback = NULL;
|
||||||
|
a2_callback = NULL;
|
||||||
|
d1_callback = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Segmented Display
|
// Segmented Display
|
||||||
|
|
||||||
@ -215,9 +232,17 @@ void watch_enable_buttons() {
|
|||||||
EXTERNAL_IRQ_0_init();
|
EXTERNAL_IRQ_0_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_register_button_callback(const uint32_t pin, ext_irq_cb_t callback) {
|
void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback) {
|
||||||
|
if (pin == 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);
|
||||||
|
btn_alarm_callback = callback;
|
||||||
|
_extwake_register_callback(&CALENDAR_0.device, extwake_callback);
|
||||||
|
} else {
|
||||||
ext_irq_register(pin, callback);
|
ext_irq_register(pin, callback);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// LED
|
// LED
|
||||||
@ -310,15 +335,8 @@ void watch_get_date_time(struct calendar_date_time *date_time) {
|
|||||||
calendar_get_date_time(&CALENDAR_0, date_time);
|
calendar_get_date_time(&CALENDAR_0, date_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ext_irq_cb_t tick_user_callback;
|
|
||||||
|
|
||||||
static void tick_callback(struct calendar_dev *const dev) {
|
|
||||||
tick_user_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
||||||
tick_user_callback = callback;
|
_prescaler_register_callback(&CALENDAR_0.device, callback);
|
||||||
_prescaler_register_callback(&CALENDAR_0.device, &tick_callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -448,6 +466,32 @@ uint32_t watch_i2c_read32(int16_t addr, uint8_t reg) {
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Deep Sleep
|
// Deep Sleep
|
||||||
|
|
||||||
|
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 (d1_callback != NULL) d1_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback) {
|
||||||
|
uint32_t pinmux;
|
||||||
|
if (pin == D1) {
|
||||||
|
d1_callback = callback;
|
||||||
|
pinmux = PINMUX_PB00G_RTC_IN0;
|
||||||
|
} else if (pin == A2) {
|
||||||
|
a2_callback = callback;
|
||||||
|
pinmux = PINMUX_PB02G_RTC_IN1;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gpio_set_pin_direction(pin, GPIO_DIRECTION_IN);
|
||||||
|
gpio_set_pin_function(pin, pinmux);
|
||||||
|
_extwake_register_callback(&CALENDAR_0.device, extwake_callback);
|
||||||
|
}
|
||||||
|
|
||||||
void watch_store_backup_data(uint32_t data, uint8_t reg) {
|
void watch_store_backup_data(uint32_t data, uint8_t reg) {
|
||||||
if (reg < 8) {
|
if (reg < 8) {
|
||||||
RTC->MODE0.BKUP[reg].reg = data;
|
RTC->MODE0.BKUP[reg].reg = data;
|
||||||
@ -462,14 +506,14 @@ uint32_t watch_get_backup_data(uint8_t reg) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
void watch_enter_deep_sleep() {
|
||||||
// enable and configure the external wake interrupt
|
// enable and configure the external wake interrupt, if not already set up.
|
||||||
_extwake_register_callback(&CALENDAR_0.device, &extwake_callback);
|
if (btn_alarm_callback == NULL && a2_callback == NULL && d1_callback == NULL) {
|
||||||
_tamper_enable_debounce_asynchronous(&CALENDAR_0.device);
|
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);
|
||||||
|
_extwake_register_callback(&CALENDAR_0.device, extwake_callback);
|
||||||
|
}
|
||||||
|
|
||||||
// disable SLCD
|
// disable SLCD
|
||||||
slcd_sync_deinit(&SEGMENT_LCD_0);
|
slcd_sync_deinit(&SEGMENT_LCD_0);
|
||||||
@ -477,12 +521,6 @@ void watch_enter_deep_sleep() {
|
|||||||
|
|
||||||
// TODO: disable other peripherals
|
// 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
|
// go into backup sleep mode
|
||||||
sleep(5);
|
sleep(5);
|
||||||
}
|
}
|
||||||
|
@ -256,16 +256,18 @@ void watch_enable_analog(const uint8_t pin);
|
|||||||
* @brief This section covers functions related to the three buttons: Light, Mode and Alarm.
|
* @brief This section covers functions related to the three buttons: Light, Mode and Alarm.
|
||||||
*/
|
*/
|
||||||
/// @{
|
/// @{
|
||||||
/** @brief Enables the external interrupt controller.
|
/** @brief Enables the external interrupt controller for use with the buttons.
|
||||||
|
* @note The BTN_ALARM button runs off of an interrupt in the the RTC controller, not the EIC. If your
|
||||||
|
* application ONLY makes use of the alarm button, you do not need to call this method; you can
|
||||||
|
* save ~5µA by leaving the EIC disabled and only registering a callback for BTN_ALARM.
|
||||||
*/
|
*/
|
||||||
void watch_enable_buttons();
|
void watch_enable_buttons();
|
||||||
|
|
||||||
/** @brief Configures an external interrupt
|
/** @brief Configures an external interrupt
|
||||||
* @param pin One of pins BTN_LIGHT, BTN_MODE or BTN_ALARM.
|
* @param pin One of pins BTN_LIGHT, BTN_MODE or BTN_ALARM.
|
||||||
* @param callback The function you wish to have called when the button is pressed.
|
* @param callback The function you wish to have called when the button is pressed.
|
||||||
* @todo Make the alarm interrupt use the RTC tamper interrupt instead of the EIC.
|
|
||||||
*/
|
*/
|
||||||
void watch_register_button_callback(const uint32_t pin, ext_irq_cb_t callback);
|
void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
@ -391,7 +393,18 @@ uint32_t watch_i2c_read32(int16_t addr, uint8_t reg);
|
|||||||
* deepest sleep mode available on the SAM L22
|
* deepest sleep mode available on the SAM L22
|
||||||
*/
|
*/
|
||||||
/// @{
|
/// @{
|
||||||
/** @brief Stores 32 bits of data in the RTC's backup register, which retains its data in deep sleep.
|
/** @brief Registers a callback on one of the RTC's external wake pins, which can wake the device
|
||||||
|
* from deep sleep mode.
|
||||||
|
* @param pin Either pin A2 or pin D1, the two external wake pins on the nine-pin connector.
|
||||||
|
* @param callback The callback to be called if this pin triggers outside of deep sleep mode.
|
||||||
|
* @note When in normal or STANDBY mode, this will function much like a standard external interrupt
|
||||||
|
* situation: these pins will wake from standby, and your callback will be called. However,
|
||||||
|
* if the device enters deep sleep and one of these pins wakes the device, your callback
|
||||||
|
* WILL NOT be called.
|
||||||
|
*/
|
||||||
|
void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback);
|
||||||
|
|
||||||
|
/** @brief Stores data in one of the RTC's backup registers, which retain their data in deep sleep.
|
||||||
* @param data An unsigned 32 bit integer with the data you wish to store.
|
* @param data An unsigned 32 bit integer with the data you wish to store.
|
||||||
* @param reg A register from 0-7.
|
* @param reg A register from 0-7.
|
||||||
*/
|
*/
|
||||||
@ -413,7 +426,13 @@ uint32_t watch_get_backup_data(uint8_t reg);
|
|||||||
* in ACTIVE, IDLE or STANDBY modes, but it *will not be called* when waking from BACKUP.
|
* in ACTIVE, IDLE or STANDBY modes, but it *will not be called* when waking from BACKUP.
|
||||||
* Waking from backup is effectively like waking from reset, except that your @ref
|
* Waking from backup is effectively like waking from reset, except that your @ref
|
||||||
* app_wake_from_deep_sleep function will be called.
|
* app_wake_from_deep_sleep function will be called.
|
||||||
* @warning still kind of glitchy!
|
* @warning In initial testing, it seems like the ALARM_BTN pin (PA02 RTC/IN2) cannot wake the device
|
||||||
|
from deep sleep mode. There is an errata note (Reference: 15010, linked) that says that
|
||||||
|
due to a silicon bug, PB01 cannot be used as RTC/IN2. It seems though that this bug may
|
||||||
|
also affect PA02. As a result — and I'm very bummed about this — you cannot use deep sleep
|
||||||
|
mode unless you set up an external wake interrupt using a device on the nine-pin connector
|
||||||
|
(i.e. an accelerometer with an interrupt pin). Otherwise your only option for waking will
|
||||||
|
be to unscrew the watch case and press the reset button on the back of the board.
|
||||||
*/
|
*/
|
||||||
void watch_enter_deep_sleep();
|
void watch_enter_deep_sleep();
|
||||||
/// @}
|
/// @}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user