mirror of
https://github.com/firewalkwithm3/Sensor-Watch.git
synced 2024-11-22 19:20:30 +08:00
rtc: support periodic ticks at intervals from 1 to 128 Hz
This commit is contained in:
parent
39a17c99b9
commit
9da9dfb7b2
|
@ -164,7 +164,7 @@ void watch_enter_shallow_sleep(char *message) {
|
||||||
_watch_disable_all_peripherals_except_slcd();
|
_watch_disable_all_peripherals_except_slcd();
|
||||||
|
|
||||||
// disable tick interrupt
|
// disable tick interrupt
|
||||||
watch_disable_tick_callback();
|
watch_rtc_disable_all_tick_callbacks();
|
||||||
|
|
||||||
// disable brownout detector interrupt, which could inadvertently wake us up.
|
// disable brownout detector interrupt, which could inadvertently wake us up.
|
||||||
SUPC->INTENCLR.bit.BOD33DET = 1;
|
SUPC->INTENCLR.bit.BOD33DET = 1;
|
||||||
|
@ -190,7 +190,7 @@ void watch_enter_deep_sleep() {
|
||||||
// so let's do it!
|
// so let's do it!
|
||||||
watch_register_extwake_callback(BTN_ALARM, NULL, true);
|
watch_register_extwake_callback(BTN_ALARM, NULL, true);
|
||||||
|
|
||||||
watch_disable_tick_callback();
|
watch_rtc_disable_all_tick_callbacks();
|
||||||
_watch_disable_all_peripherals_except_slcd();
|
_watch_disable_all_peripherals_except_slcd();
|
||||||
slcd_sync_deinit(&SEGMENT_LCD_0);
|
slcd_sync_deinit(&SEGMENT_LCD_0);
|
||||||
hri_mclk_clear_APBCMASK_SLCD_bit(SLCD);
|
hri_mclk_clear_APBCMASK_SLCD_bit(SLCD);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#include "watch_rtc.h"
|
#include "watch_rtc.h"
|
||||||
|
|
||||||
ext_irq_cb_t tick_callback;
|
ext_irq_cb_t tick_callbacks[8];
|
||||||
ext_irq_cb_t alarm_callback;
|
ext_irq_cb_t alarm_callback;
|
||||||
ext_irq_cb_t btn_alarm_callback;
|
ext_irq_cb_t btn_alarm_callback;
|
||||||
ext_irq_cb_t a2_callback;
|
ext_irq_cb_t a2_callback;
|
||||||
|
@ -70,15 +70,40 @@ watch_date_time watch_rtc_get_date_time() {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback) {
|
||||||
tick_callback = callback;
|
watch_rtc_register_tick_callback(callback, 1);
|
||||||
NVIC_ClearPendingIRQ(RTC_IRQn);
|
|
||||||
NVIC_EnableIRQ(RTC_IRQn);
|
|
||||||
RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_disable_tick_callback() {
|
void watch_rtc_disable_1Hz_callback() {
|
||||||
RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_PER7;
|
watch_rtc_disable_tick_callback(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period) {
|
||||||
|
// we told them, it has to be a power of 2.
|
||||||
|
if (__builtin_popcount(period) != 1) return;
|
||||||
|
|
||||||
|
// this left-justifies the period in a 32-bit integer.
|
||||||
|
uint32_t tmp = period << 24;
|
||||||
|
// now we can count the leading zeroes to get the value we need.
|
||||||
|
// 0x01 (1 Hz) will have 7 leading zeros for PER7. 0xF0 (128 Hz) will have no leading zeroes for PER0.
|
||||||
|
uint8_t per_n = __builtin_clz(tmp);
|
||||||
|
|
||||||
|
// this also maps nicely to an index for our list of tick callbacks.
|
||||||
|
tick_callbacks[per_n] = callback;
|
||||||
|
|
||||||
|
NVIC_ClearPendingIRQ(RTC_IRQn);
|
||||||
|
NVIC_EnableIRQ(RTC_IRQn);
|
||||||
|
RTC->MODE2.INTENSET.reg = 1 << per_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_rtc_disable_tick_callback(uint8_t period) {
|
||||||
|
if (__builtin_popcount(period) != 1) return;
|
||||||
|
uint8_t per_n = __builtin_clz(period << 24);
|
||||||
|
RTC->MODE2.INTENCLR.reg = 1 << per_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_rtc_disable_all_tick_callbacks() {
|
||||||
|
RTC->MODE2.INTENCLR.reg = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) {
|
void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask) {
|
||||||
|
@ -99,17 +124,20 @@ void RTC_Handler(void) {
|
||||||
uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg;
|
uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg;
|
||||||
uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg;
|
uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg;
|
||||||
|
|
||||||
if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
|
if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER_Msk) {
|
||||||
if (alarm_callback != NULL) {
|
// handle the tick callback first, it's what we do the most.
|
||||||
alarm_callback();
|
// start from PER7, the 1 Hz tick.
|
||||||
|
for(int8_t i = 7; i >= 0; i--) {
|
||||||
|
if ((interrupt_status & interrupt_enabled) & (1 << i)) {
|
||||||
|
if (tick_callbacks[i] != NULL) {
|
||||||
|
tick_callbacks[i]();
|
||||||
|
}
|
||||||
|
RTC->MODE2.INTFLAG.reg = 1 << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
|
|
||||||
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
|
|
||||||
if (tick_callback != NULL) {
|
|
||||||
tick_callback();
|
|
||||||
}
|
|
||||||
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_PER7;
|
|
||||||
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
|
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
|
||||||
|
// handle the extwake interrupts next.
|
||||||
uint8_t reason = RTC->MODE2.TAMPID.reg;
|
uint8_t reason = RTC->MODE2.TAMPID.reg;
|
||||||
if (reason & RTC_TAMPID_TAMPID2) {
|
if (reason & RTC_TAMPID_TAMPID2) {
|
||||||
if (btn_alarm_callback != NULL) btn_alarm_callback();
|
if (btn_alarm_callback != NULL) btn_alarm_callback();
|
||||||
|
@ -120,6 +148,12 @@ void RTC_Handler(void) {
|
||||||
}
|
}
|
||||||
RTC->MODE2.TAMPID.reg = reason;
|
RTC->MODE2.TAMPID.reg = reason;
|
||||||
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_TAMPER;
|
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_TAMPER;
|
||||||
|
} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
|
||||||
|
// finally handle the alarm.
|
||||||
|
if (alarm_callback != NULL) {
|
||||||
|
alarm_callback();
|
||||||
|
}
|
||||||
|
RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,3 +186,10 @@ void watch_get_date_time(struct calendar_date_time *date_time) {
|
||||||
date_time->date.month = val.bit.MONTH;
|
date_time->date.month = val.bit.MONTH;
|
||||||
date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
|
date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void watch_register_tick_callback(ext_irq_cb_t callback) {
|
||||||
|
tick_callbacks[7] = callback;
|
||||||
|
NVIC_ClearPendingIRQ(RTC_IRQn);
|
||||||
|
NVIC_EnableIRQ(RTC_IRQn);
|
||||||
|
RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
|
||||||
|
}
|
||||||
|
|
|
@ -106,11 +106,37 @@ void watch_rtc_disable_alarm_callback();
|
||||||
* @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick
|
* @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick
|
||||||
* interrupt will still be enabled, but no callback function will be called.
|
* interrupt will still be enabled, but no callback function will be called.
|
||||||
*/
|
*/
|
||||||
void watch_register_tick_callback(ext_irq_cb_t callback);
|
void watch_rtc_register_1Hz_callback(ext_irq_cb_t callback);
|
||||||
|
|
||||||
/** @brief Disables the tick callback.
|
/** @brief Disables the tick callback for the given period.
|
||||||
*/
|
*/
|
||||||
void watch_disable_tick_callback();
|
void watch_rtc_disable_1Hz_callback();
|
||||||
|
|
||||||
|
/** @brief Registers a "tick" callback that will be called at a configurable period.
|
||||||
|
* @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick
|
||||||
|
* interrupt will still be enabled, but no callback function will be called.
|
||||||
|
* @param period The frequency of the tick in Hz. **Must be a power of 2**, from 1 to 128 inclusive.
|
||||||
|
* @note A 1 Hz tick (@see watch_rtc_register_1Hz_callback) is suitable for most applications, in that it gives you a
|
||||||
|
* chance to update the display once a second — an ideal update rate for a watch! If however you are displaying
|
||||||
|
* a value (such as an accelerometer output) that updates more frequently than once per second, you may want to
|
||||||
|
* tick at 16 or 32 Hz to update the screen more quickly. Just remember that the more frequent the tick, the more
|
||||||
|
* power your app will consume. Ideally you should enable the fast tick only when the user requires it (i.e. in
|
||||||
|
* response to an input event), and move back to the slow tick after some time.
|
||||||
|
*
|
||||||
|
* Also note that the RTC peripheral does not have sub-second resolution, so even if you set a 2 or 4 Hz interval,
|
||||||
|
* the system will not have any way of telling you where you are within a given second; watch_rtc_get_date_time
|
||||||
|
* will return the exact same timestamp until the second ticks over.
|
||||||
|
*/
|
||||||
|
void watch_rtc_register_tick_callback(ext_irq_cb_t callback, uint8_t period);
|
||||||
|
|
||||||
|
/** @brief Disables the tick callback for the given period.
|
||||||
|
* @param period The frequency of the tick you wish to disable, in Hz. **Must be a power of 2**, from 1 to 128.
|
||||||
|
*/
|
||||||
|
void watch_rtc_disable_tick_callback(uint8_t period);
|
||||||
|
|
||||||
|
/** @brief Disables all tick callbacks.
|
||||||
|
*/
|
||||||
|
void watch_rtc_disable_all_tick_callbacks();
|
||||||
|
|
||||||
/** @brief Sets the system date and time.
|
/** @brief Sets the system date and time.
|
||||||
* @param date_time A struct representing the date and time you wish to set.
|
* @param date_time A struct representing the date and time you wish to set.
|
||||||
|
@ -124,5 +150,12 @@ void watch_set_date_time(struct calendar_date_time date_time);
|
||||||
__attribute__((deprecated("Use the watch_rtc_get_date_time function instead")))
|
__attribute__((deprecated("Use the watch_rtc_get_date_time function instead")))
|
||||||
void watch_get_date_time(struct calendar_date_time *date_time);
|
void watch_get_date_time(struct calendar_date_time *date_time);
|
||||||
|
|
||||||
|
/** @brief Registers a "tick" callback that will be called once per second.
|
||||||
|
* @param callback The function you wish to have called when the clock ticks. If you pass in NULL, the tick
|
||||||
|
* interrupt will still be enabled, but no callback function will be called.
|
||||||
|
*/
|
||||||
|
__attribute__((deprecated("Use the watch_rtc_register_1Hz_callback function instead")))
|
||||||
|
void watch_register_tick_callback(ext_irq_cb_t callback);
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue