diff options
| -rw-r--r-- | Sensor Watch Starter Project/app.c | 6 | ||||
| -rw-r--r-- | watch-library/config/hpl_rtc_config.h | 8 | ||||
| -rw-r--r-- | watch-library/hal/include/hpl_calendar.h | 9 | ||||
| -rw-r--r-- | watch-library/hpl/rtc/hpl_rtc.c | 11 | ||||
| -rw-r--r-- | watch-library/watch/watch.c | 84 | ||||
| -rw-r--r-- | watch-library/watch/watch.h | 29 | 
6 files changed, 106 insertions, 41 deletions
diff --git a/Sensor Watch Starter Project/app.c b/Sensor Watch Starter Project/app.c index a180f0ea..87326422 100644 --- a/Sensor Watch Starter Project/app.c +++ b/Sensor Watch Starter Project/app.c @@ -62,6 +62,7 @@ void app_wake_from_deep_sleep() {      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; +    application_state.debounce_wait = true;  }  /** @@ -184,5 +185,8 @@ void cb_mode_pressed() {  void cb_alarm_pressed() {      if (application_state.debounce_wait) return;      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;  } diff --git a/watch-library/config/hpl_rtc_config.h b/watch-library/config/hpl_rtc_config.h index 582a1c23..2c478111 100644 --- a/watch-library/config/hpl_rtc_config.h +++ b/watch-library/config/hpl_rtc_config.h @@ -48,7 +48,7 @@  // <e> RTC Tamper Input 0 settings  // <id> 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  // <q> Tamper Level Settings @@ -66,7 +66,7 @@  // <i> These bits define the RTC Tamper Input Action to be performed  // <id> rtc_tamper_input_action_0  #ifndef CONF_RTC_TAMPER_INACT_0 -#define CONF_RTC_TAMPER_INACT_0 0 +#define CONF_RTC_TAMPER_INACT_0 1  #endif  // <q> Debounce Enable for Tamper Input @@ -81,7 +81,7 @@  // <e> RTC Tamper Input 1 settings  // <id> 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  // <q> Tamper Level Settings @@ -99,7 +99,7 @@  // <i> These bits define the RTC Tamper Input Action to be performed  // <id> rtc_tamper_input_action_1  #ifndef CONF_RTC_TAMPER_INACT_1 -#define CONF_RTC_TAMPER_INACT_1 0 +#define CONF_RTC_TAMPER_INACT_1 1  #endif  // <q> Debounce Enable for Tamper Input diff --git a/watch-library/hal/include/hpl_calendar.h b/watch-library/hal/include/hpl_calendar.h index 87b1a5a8..f94249b9 100644 --- a/watch-library/hal/include/hpl_calendar.h +++ b/watch-library/hal/include/hpl_calendar.h @@ -77,7 +77,8 @@ enum calendar_alarm_mode { ONESHOT = 1, REPEAT };  /**   * \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 @@ -88,8 +89,8 @@ struct calendar_dev {  	/** Alarm match callback */  	calendar_drv_cb_t callback_alarm;  	/** Tamper callback */ -	calendar_drv_cb_t callback_tamper; -	/** Tamper callback */ +	calendar_drv_extwake_cb_t callback_tamper; +	/** Tick callback */  	calendar_drv_cb_t callback_tick;  	/** IRQ struct */  	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.   */ -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 diff --git a/watch-library/hpl/rtc/hpl_rtc.c b/watch-library/hpl/rtc/hpl_rtc.c index 0d119da1..437449ce 100644 --- a/watch-library/hpl/rtc/hpl_rtc.c +++ b/watch-library/hpl/rtc/hpl_rtc.c @@ -327,8 +327,7 @@ int32_t _prescaler_register_callback(struct calendar_dev *const dev, calendar_dr  	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) +int32_t _extwake_register_callback(struct calendar_dev *const dev, calendar_drv_extwake_cb_t callback)  {  	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);  	if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) { -		dev->callback_alarm(dev); +		dev->callback_alarm();  		/* Clear interrupt flag */  		hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw);  	} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) { -		dev->callback_tick(dev); +		dev->callback_tick();  		/* Clear interrupt flag */  		hri_rtcmode0_clear_interrupt_PER7_bit(dev->hw);  	} 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 */  		hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);  	} diff --git a/watch-library/watch/watch.c b/watch-library/watch/watch.c index 4c891d65..170c4747 100644 --- a/watch-library/watch/watch.c +++ b/watch-library/watch/watch.c @@ -2,6 +2,16 @@  #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  void _watch_init() { @@ -15,7 +25,14 @@ void _watch_init() {      // Not sure if this belongs in every app -- is there a power impact?      delay_driver_init(); + +    // set up state +    btn_alarm_callback = NULL; +    a2_callback = NULL; +    d1_callback = NULL;  } + +  //////////////////////////////////////////////////////////////////////////////////////////  // Segmented Display @@ -215,8 +232,16 @@ void watch_enable_buttons() {      EXTERNAL_IRQ_0_init();  } -void watch_register_button_callback(const uint32_t pin, ext_irq_cb_t callback) { -    ext_irq_register(pin, 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); +    }  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -310,15 +335,8 @@ void watch_get_date_time(struct calendar_date_time *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) { -    tick_user_callback = callback; -    _prescaler_register_callback(&CALENDAR_0.device, &tick_callback); +    _prescaler_register_callback(&CALENDAR_0.device, callback);  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -448,6 +466,32 @@ uint32_t watch_i2c_read32(int16_t addr, uint8_t reg) {  //////////////////////////////////////////////////////////////////////////////////////////  // 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) {      if (reg < 8) {          RTC->MODE0.BKUP[reg].reg = data; @@ -462,14 +506,14 @@ uint32_t watch_get_backup_data(uint8_t reg) {      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() { -    // enable and configure the external wake interrupt -    _extwake_register_callback(&CALENDAR_0.device, &extwake_callback); -    _tamper_enable_debounce_asynchronous(&CALENDAR_0.device); +    // enable and configure the external wake interrupt, if not already set up. +    if (btn_alarm_callback == NULL && a2_callback == NULL && d1_callback == NULL) { +        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      slcd_sync_deinit(&SEGMENT_LCD_0); @@ -477,12 +521,6 @@ void watch_enter_deep_sleep() {      // 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);  } diff --git a/watch-library/watch/watch.h b/watch-library/watch/watch.h index 8cb949f6..29881292 100644 --- a/watch-library/watch/watch.h +++ b/watch-library/watch/watch.h @@ -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 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();  /** @brief Configures an external interrupt    * @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. -  * @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    */  /// @{ -/** @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 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.    *       Waking from backup is effectively like waking from reset, except that your @ref    *       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();  /// @}  | 
