summaryrefslogtreecommitdiffstats
path: root/watch-library/watch
diff options
context:
space:
mode:
Diffstat (limited to 'watch-library/watch')
-rw-r--r--watch-library/watch/watch.c12
-rw-r--r--watch-library/watch/watch_adc.c2
-rw-r--r--watch-library/watch/watch_adc.h5
-rw-r--r--watch-library/watch/watch_app.h3
-rw-r--r--watch-library/watch/watch_buzzer.c2
-rw-r--r--watch-library/watch/watch_buzzer.h5
-rw-r--r--watch-library/watch/watch_deepsleep.c38
-rw-r--r--watch-library/watch/watch_deepsleep.h10
-rw-r--r--watch-library/watch/watch_extint.c2
-rw-r--r--watch-library/watch/watch_extint.h4
-rw-r--r--watch-library/watch/watch_gpio.c2
-rw-r--r--watch-library/watch/watch_gpio.h5
-rw-r--r--watch-library/watch/watch_i2c.c4
-rw-r--r--watch-library/watch/watch_i2c.h5
-rw-r--r--watch-library/watch/watch_led.c2
-rw-r--r--watch-library/watch/watch_led.h5
-rw-r--r--watch-library/watch/watch_private.c4
-rw-r--r--watch-library/watch/watch_private.h8
-rw-r--r--watch-library/watch/watch_rtc.c167
-rw-r--r--watch-library/watch/watch_rtc.h114
-rw-r--r--watch-library/watch/watch_slcd.c2
-rw-r--r--watch-library/watch/watch_slcd.h5
-rw-r--r--watch-library/watch/watch_uart.c1
-rw-r--r--watch-library/watch/watch_uart.h5
24 files changed, 362 insertions, 50 deletions
diff --git a/watch-library/watch/watch.c b/watch-library/watch/watch.c
index 6196b1f3..de7160c5 100644
--- a/watch-library/watch/watch.c
+++ b/watch-library/watch/watch.c
@@ -24,18 +24,6 @@
#include "watch.h"
-#include "watch_rtc.c"
-#include "watch_slcd.c"
-#include "watch_extint.c"
-#include "watch_led.c"
-#include "watch_buzzer.c"
-#include "watch_adc.c"
-#include "watch_gpio.c"
-#include "watch_i2c.c"
-#include "watch_uart.c"
-#include "watch_deepsleep.c"
-#include "watch_private.c"
-
bool battery_is_low = false;
// receives interrupts from MCLK, OSC32KCTRL, OSCCTRL, PAC, PM, SUPC and TAL, whatever that is.
diff --git a/watch-library/watch/watch_adc.c b/watch-library/watch/watch_adc.c
index 490a49b1..90980a88 100644
--- a/watch-library/watch/watch_adc.c
+++ b/watch-library/watch/watch_adc.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_adc.h"
+
void _watch_sync_adc() {
while (ADC->SYNCBUSY.reg);
}
diff --git a/watch-library/watch/watch_adc.h b/watch-library/watch/watch_adc.h
index b49f1301..c9b6ad2a 100644
--- a/watch-library/watch/watch_adc.h
+++ b/watch-library/watch/watch_adc.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_ADC_H_INCLUDED
+#define _WATCH_ADC_H_INCLUDED
////< @file watch_adc.h
+#include "watch.h"
+
/** @addtogroup adc Analog Input
* @brief This section covers functions related to the SAM L22's analog-to-digital converter,
* as well as configuring and reading values from the five analog-capable pins on the
@@ -103,3 +107,4 @@ void watch_disable_analog_input(const uint8_t pin);
void watch_disable_adc();
/// @}
+#endif
diff --git a/watch-library/watch/watch_app.h b/watch-library/watch/watch_app.h
index fd7ea706..00a6a610 100644
--- a/watch-library/watch/watch_app.h
+++ b/watch-library/watch/watch_app.h
@@ -21,6 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_APP_H_INCLUDED
+#define _WATCH_APP_H_INCLUDED
////< @file watch_app.h
/** @addtogroup app Application Framework
@@ -103,3 +105,4 @@ void app_prepare_for_sleep();
void app_wake_from_sleep();
/// @}
+#endif
diff --git a/watch-library/watch/watch_buzzer.c b/watch-library/watch/watch_buzzer.c
index 9cb37393..007a44ca 100644
--- a/watch-library/watch/watch_buzzer.c
+++ b/watch-library/watch/watch_buzzer.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_buzzer.h"
+
inline void watch_enable_buzzer() {
if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) {
_watch_enable_tcc();
diff --git a/watch-library/watch/watch_buzzer.h b/watch-library/watch/watch_buzzer.h
index 995e059a..e15657be 100644
--- a/watch-library/watch/watch_buzzer.h
+++ b/watch-library/watch/watch_buzzer.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_BUZZER_H_INCLUDED
+#define _WATCH_BUZZER_H_INCLUDED
////< @file watch_buzzer.h
+#include "watch.h"
+
/** @addtogroup buzzer Buzzer
* @brief This section covers functions related to the piezo buzzer embedded in the F-91W's back plate.
*/
@@ -157,3 +161,4 @@ void watch_buzzer_play_note(BuzzerNote note, uint16_t duration_ms);
extern const uint16_t NotePeriods[108];
/// @}
+#endif
diff --git a/watch-library/watch/watch_deepsleep.c b/watch-library/watch/watch_deepsleep.c
index a69ba66c..b7da82ee 100644
--- a/watch-library/watch/watch_deepsleep.c
+++ b/watch-library/watch/watch_deepsleep.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_extint.h"
+
// this warning only appears when you `make BOARD=OSO-SWAT-A1-02`. it's annoying,
// but i'd rather have it warn us at build-time than fail silently at run-time.
// besides, no one but me really has any of these boards anyway.
@@ -29,24 +31,9 @@
#warning This board revision does not support external wake on BTN_ALARM, so watch_register_extwake_callback will not work with it. Use watch_register_interrupt_callback instead.
#endif
-static void extwake_callback(uint8_t reason);
-ext_irq_cb_t btn_alarm_callback;
-ext_irq_cb_t a2_callback;
-ext_irq_cb_t a4_callback;
-
- 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 (a4_callback != NULL) a4_callback();
- }
-}
-
void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) {
uint32_t pinmux;
- hri_rtc_tampctrl_reg_t config = hri_rtc_get_TAMPCTRL_reg(RTC, 0xFFFFFFFF);
+ hri_rtc_tampctrl_reg_t config = RTC->MODE2.TAMPCTRL.reg;
switch (pin) {
case A4:
@@ -84,16 +71,17 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le
gpio_set_pin_function(pin, pinmux);
// disable the RTC
- if (hri_rtcmode0_get_CTRLA_ENABLE_bit(RTC)) {
- hri_rtcmode0_clear_CTRLA_ENABLE_bit(RTC);
- hri_rtcmode0_wait_for_sync(RTC, RTC_MODE0_SYNCBUSY_ENABLE);
- }
+ RTC->MODE2.CTRLA.bit.ENABLE = 0;
+ while (RTC->MODE2.SYNCBUSY.bit.ENABLE);
+
// update the configuration
- hri_rtc_write_TAMPCTRL_reg(RTC, config);
+ RTC->MODE2.TAMPCTRL.reg = config;
// re-enable the RTC
- hri_rtcmode0_set_CTRLA_ENABLE_bit(RTC);
+ RTC->MODE2.CTRLA.bit.ENABLE = 1;
- _extwake_register_callback(&CALENDAR_0.device, extwake_callback);
+ NVIC_ClearPendingIRQ(RTC_IRQn);
+ NVIC_EnableIRQ(RTC_IRQn);
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_TAMPER;
}
void watch_disable_extwake_interrupt(uint8_t pin) {
@@ -176,7 +164,7 @@ void watch_enter_shallow_sleep(char *message) {
_watch_disable_all_peripherals_except_slcd();
// disable tick interrupt
- watch_register_tick_callback(NULL);
+ watch_rtc_disable_all_periodic_callbacks();
// disable brownout detector interrupt, which could inadvertently wake us up.
SUPC->INTENCLR.bit.BOD33DET = 1;
@@ -202,7 +190,7 @@ void watch_enter_deep_sleep() {
// so let's do it!
watch_register_extwake_callback(BTN_ALARM, NULL, true);
- watch_register_tick_callback(NULL);
+ watch_rtc_disable_all_periodic_callbacks();
_watch_disable_all_peripherals_except_slcd();
slcd_sync_deinit(&SEGMENT_LCD_0);
hri_mclk_clear_APBCMASK_SLCD_bit(SLCD);
diff --git a/watch-library/watch/watch_deepsleep.h b/watch-library/watch/watch_deepsleep.h
index 1e118929..3dc428d0 100644
--- a/watch-library/watch/watch_deepsleep.h
+++ b/watch-library/watch/watch_deepsleep.h
@@ -21,8 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_DEEPSLEEP_H_INCLUDED
+#define _WATCH_DEEPSLEEP_H_INCLUDED
////< @file watch_deepsleep.h
+#include "watch.h"
+
+// These are declared in watch_rtc.c.
+extern ext_irq_cb_t btn_alarm_callback;
+extern ext_irq_cb_t a2_callback;
+extern ext_irq_cb_t a4_callback;
+
/** @addtogroup deepsleep Deep Sleep Control
* @brief This section covers functions related to preparing for and entering BACKUP mode, the
* deepest sleep mode available on the SAM L22
@@ -110,3 +119,4 @@ void watch_enter_shallow_sleep(char *message);
*/
void watch_enter_deep_sleep();
/// @}
+#endif
diff --git a/watch-library/watch/watch_extint.c b/watch-library/watch/watch_extint.c
index f2bad949..dcaa0d80 100644
--- a/watch-library/watch/watch_extint.c
+++ b/watch-library/watch/watch_extint.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_extint.h"
+
void watch_enable_external_interrupts() {
// Configure EIC to use GCLK3 (the 32.768 kHz crystal)
hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
diff --git a/watch-library/watch/watch_extint.h b/watch-library/watch/watch_extint.h
index 9c810534..758fe8bc 100644
--- a/watch-library/watch/watch_extint.h
+++ b/watch-library/watch/watch_extint.h
@@ -21,8 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_EXTINT_H_INCLUDED
+#define _WATCH_EXTINT_H_INCLUDED
////< @file watch_extint.h
+#include "watch.h"
#include "hal_ext_irq.h"
/** @addtogroup buttons Buttons & External Interrupts
@@ -78,3 +81,4 @@ void watch_register_button_callback(const uint8_t pin, ext_irq_cb_t callback);
__attribute__((deprecated("Use watch_enable_external_interrupts instead")))
void watch_enable_buttons();
/// @}
+#endif
diff --git a/watch-library/watch/watch_gpio.c b/watch-library/watch/watch_gpio.c
index a9bc139d..b37d009f 100644
--- a/watch-library/watch/watch_gpio.c
+++ b/watch-library/watch/watch_gpio.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_gpio.h"
+
void watch_enable_digital_input(const uint8_t pin) {
gpio_set_pin_direction(pin, GPIO_DIRECTION_IN);
gpio_set_pin_function(pin, GPIO_PIN_FUNCTION_OFF);
diff --git a/watch-library/watch/watch_gpio.h b/watch-library/watch/watch_gpio.h
index 640686e0..fc43642c 100644
--- a/watch-library/watch/watch_gpio.h
+++ b/watch-library/watch/watch_gpio.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_GPIO_H_INCLUDED
+#define _WATCH_GPIO_H_INCLUDED
////< @file watch_gpio.h
+#include "watch.h"
+
/** @addtogroup gpio Digital Input and Output
* @brief This section covers functions related to general-purpose input and output signals.
*/
@@ -69,3 +73,4 @@ void watch_disable_digital_output(const uint8_t pin);
*/
void watch_set_pin_level(const uint8_t pin, const bool level);
/// @}
+#endif
diff --git a/watch-library/watch/watch_i2c.c b/watch-library/watch/watch_i2c.c
index 385d9d08..d2cf474b 100644
--- a/watch-library/watch/watch_i2c.c
+++ b/watch-library/watch/watch_i2c.c
@@ -22,7 +22,9 @@
* SOFTWARE.
*/
- struct io_descriptor *I2C_0_io;
+#include "watch_i2c.h"
+
+struct io_descriptor *I2C_0_io;
void watch_enable_i2c() {
I2C_0_init();
diff --git a/watch-library/watch/watch_i2c.h b/watch-library/watch/watch_i2c.h
index 7ac05c13..65df49b4 100644
--- a/watch-library/watch/watch_i2c.h
+++ b/watch-library/watch/watch_i2c.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_I2C_H_INCLUDED
+#define _WATCH_I2C_H_INCLUDED
////< @file watch_i2c.h
+#include "watch.h"
+
/** @addtogroup i2c I2C Controller Driver
* @brief This section covers functions related to the SAM L22's built-I2C driver, including
* configuring the I2C bus, putting values directly on the bus and reading data from
@@ -99,3 +103,4 @@ uint32_t watch_i2c_read24(int16_t addr, uint8_t reg);
*/
uint32_t watch_i2c_read32(int16_t addr, uint8_t reg);
/// @}
+#endif
diff --git a/watch-library/watch/watch_led.c b/watch-library/watch/watch_led.c
index 7b189452..1348c977 100644
--- a/watch-library/watch/watch_led.c
+++ b/watch-library/watch/watch_led.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_led.h"
+
void watch_enable_leds() {
if (!hri_tcc_get_CTRLA_reg(TCC0, TCC_CTRLA_ENABLE)) {
_watch_enable_tcc();
diff --git a/watch-library/watch/watch_led.h b/watch-library/watch/watch_led.h
index 0927e716..2b9dead0 100644
--- a/watch-library/watch/watch_led.h
+++ b/watch-library/watch/watch_led.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_LED_H_INCLUDED
+#define _WATCH_LED_H_INCLUDED
////< @file watch_led.h
+#include "watch.h"
+
/** @addtogroup led LED Control
* @brief This section covers functions related to the bi-color red/green LED mounted behind the LCD.
* @details The SAM L22 is an exceedingly power efficient chip, whereas the LED's are relatively power-
@@ -86,3 +90,4 @@ void watch_enable_led(bool unused);
__attribute__((deprecated("Use watch_disable_leds instead")))
void watch_disable_led(bool unused);
/// @}
+#endif
diff --git a/watch-library/watch/watch_private.c b/watch-library/watch/watch_private.c
index bdf6b78a..270208dc 100644
--- a/watch-library/watch/watch_private.c
+++ b/watch-library/watch/watch_private.c
@@ -22,6 +22,7 @@
* SOFTWARE.
*/
+#include "watch_private.h"
#include "tusb.h"
void _watch_init() {
@@ -56,8 +57,7 @@ void _watch_init() {
SUPC->BOD33.bit.ENABLE = 1;
// External wake depends on RTC; calendar is a required module.
- CALENDAR_0_init();
- calendar_enable(&CALENDAR_0);
+ _watch_rtc_init();
// set up state
btn_alarm_callback = NULL;
diff --git a/watch-library/watch/watch_private.h b/watch-library/watch/watch_private.h
index abee085a..8045e438 100644
--- a/watch-library/watch/watch_private.h
+++ b/watch-library/watch/watch_private.h
@@ -21,10 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_PRIVATE_H_INCLUDED
+#define _WATCH_PRIVATE_H_INCLUDED
+
+#include "watch.h"
/// Called by main.c while setting up the app. You should not call this from your app.
void _watch_init();
+/// Initializes the real-time clock peripheral.
+void _watch_rtc_init();
+
/// Called by buzzer and LED setup functions. You should not call this from your app.
void _watch_enable_tcc();
@@ -33,3 +40,4 @@ void _watch_disable_tcc();
/// Called by main.c if plugged in to USB. You should not call this from your app.
void _watch_enable_usb();
+#endif
diff --git a/watch-library/watch/watch_rtc.c b/watch-library/watch/watch_rtc.c
index 2d6d598f..a50da7c4 100644
--- a/watch-library/watch/watch_rtc.c
+++ b/watch-library/watch/watch_rtc.c
@@ -22,19 +22,174 @@
* SOFTWARE.
*/
- bool _watch_rtc_is_enabled() {
- return RTC->MODE0.CTRLA.bit.ENABLE;
+#include "watch_rtc.h"
+
+ext_irq_cb_t tick_callbacks[8];
+ext_irq_cb_t alarm_callback;
+ext_irq_cb_t btn_alarm_callback;
+ext_irq_cb_t a2_callback;
+ext_irq_cb_t a4_callback;
+
+bool _watch_rtc_is_enabled() {
+ return RTC->MODE2.CTRLA.bit.ENABLE;
+}
+
+void _sync_rtc() {
+ while (RTC->MODE2.SYNCBUSY.reg);
}
+void _watch_rtc_init() {
+ MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC;
+
+ if (_watch_rtc_is_enabled()) return; // don't reset the RTC if it's already set up.
+
+ RTC->MODE2.CTRLA.bit.ENABLE = 0;
+ _sync_rtc();
+
+ RTC->MODE2.CTRLA.bit.SWRST = 1;
+ _sync_rtc();
+
+ RTC->MODE2.CTRLA.bit.MODE = RTC_MODE2_CTRLA_MODE_CLOCK_Val;
+ RTC->MODE2.CTRLA.bit.PRESCALER = RTC_MODE2_CTRLA_PRESCALER_DIV1024_Val;
+ RTC->MODE2.CTRLA.bit.CLOCKSYNC = 1;
+ RTC->MODE2.CTRLA.bit.ENABLE = 1;
+ _sync_rtc();
+}
+
+void watch_rtc_set_date_time(watch_date_time date_time) {
+ RTC->MODE2.CLOCK.reg = date_time.reg;
+ _sync_rtc();
+}
+
+watch_date_time watch_rtc_get_date_time() {
+ watch_date_time retval;
+
+ _sync_rtc();
+ retval.reg = RTC->MODE2.CLOCK.reg;
+
+ return retval;
+}
+
+void watch_rtc_register_tick_callback(ext_irq_cb_t callback) {
+ watch_rtc_register_periodic_callback(callback, 1);
+}
+
+void watch_rtc_disable_tick_callback() {
+ watch_rtc_disable_periodic_callback(1);
+}
+
+void watch_rtc_register_periodic_callback(ext_irq_cb_t callback, uint8_t frequency) {
+ // we told them, it has to be a power of 2.
+ if (__builtin_popcount(frequency) != 1) return;
+
+ // this left-justifies the period in a 32-bit integer.
+ uint32_t tmp = frequency << 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_periodic_callback(uint8_t frequency) {
+ if (__builtin_popcount(frequency) != 1) return;
+ uint8_t per_n = __builtin_clz(frequency << 24);
+ RTC->MODE2.INTENCLR.reg = 1 << per_n;
+}
+
+void watch_rtc_disable_all_periodic_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) {
+ RTC->MODE2.Mode2Alarm[0].ALARM.reg = alarm_time.reg;
+ RTC->MODE2.Mode2Alarm[0].MASK.reg = mask;
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0;
+ alarm_callback = callback;
+ NVIC_ClearPendingIRQ(RTC_IRQn);
+ NVIC_EnableIRQ(RTC_IRQn);
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_ALARM0;
+}
+
+void watch_rtc_disable_alarm_callback() {
+ RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_ALARM0;
+}
+
+void RTC_Handler(void) {
+ uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg;
+ uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg;
+
+ if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER_Msk) {
+ // handle the tick callback first, it's what we do the most.
+ // 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;
+ }
+ }
+ } else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_TAMPER) {
+ // handle the extwake interrupts next.
+ uint8_t reason = RTC->MODE2.TAMPID.reg;
+ 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 (a4_callback != NULL) a4_callback();
+ }
+ RTC->MODE2.TAMPID.reg = reason;
+ 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;
+ }
+}
+
+///////////////////////
+// Deprecated functions
+
void watch_set_date_time(struct calendar_date_time date_time) {
- calendar_set_date(&CALENDAR_0, &date_time.date);
- calendar_set_time(&CALENDAR_0, &date_time.time);
+ RTC_MODE2_CLOCK_Type val;
+
+ val.bit.SECOND = date_time.time.sec;
+ val.bit.MINUTE = date_time.time.min;
+ val.bit.HOUR = date_time.time.hour;
+ val.bit.DAY = date_time.date.day;
+ val.bit.MONTH = date_time.date.month;
+ val.bit.YEAR = (uint8_t)(date_time.date.year - WATCH_RTC_REFERENCE_YEAR);
+
+ RTC->MODE2.CLOCK.reg = val.reg;
+
+ _sync_rtc();
}
void watch_get_date_time(struct calendar_date_time *date_time) {
- calendar_get_date_time(&CALENDAR_0, date_time);
+ _sync_rtc();
+ RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK;
+
+ date_time->time.sec = val.bit.SECOND;
+ date_time->time.min = val.bit.MINUTE;
+ date_time->time.hour = val.bit.HOUR;
+ date_time->date.day = val.bit.DAY;
+ date_time->date.month = val.bit.MONTH;
+ date_time->date.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
}
void watch_register_tick_callback(ext_irq_cb_t callback) {
- _prescaler_register_callback(&CALENDAR_0.device, callback);
+ tick_callbacks[7] = callback;
+ NVIC_ClearPendingIRQ(RTC_IRQn);
+ NVIC_EnableIRQ(RTC_IRQn);
+ RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
}
diff --git a/watch-library/watch/watch_rtc.h b/watch-library/watch/watch_rtc.h
index c685ac26..1776a712 100644
--- a/watch-library/watch/watch_rtc.h
+++ b/watch-library/watch/watch_rtc.h
@@ -21,8 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_RTC_H_INCLUDED
+#define _WATCH_RTC_H_INCLUDED
////< @file watch_rtc.h
+#include "watch.h"
#include "hpl_calendar.h"
/** @addtogroup rtc Real-Time Clock
@@ -35,24 +38,127 @@
* to wake from STANDBY mode.
*/
/// @{
+
+#define WATCH_RTC_REFERENCE_YEAR (2020)
+
+typedef union {
+ struct {
+ uint32_t second : 6; // 0-59
+ uint32_t minute : 6; // 0-59
+ uint32_t hour : 5; // 0-23
+ uint32_t day : 5; // 1-31
+ uint32_t month : 4; // 1-12
+ uint32_t year : 6; // 0-63 (representing 2020-2083)
+ } unit;
+ uint32_t reg; // the bit-packed value as expected by the RTC peripheral's CLOCK register.
+} watch_date_time;
+
+typedef enum watch_rtc_alarm_match {
+ ALARM_MATCH_DISABLED = 0,
+ ALARM_MATCH_SS,
+ ALARM_MATCH_MMSS,
+ ALARM_MATCH_HHMMSS,
+} watch_rtc_alarm_match;
+
/** @brief Called by main.c to check if the RTC is enabled.
- * You may call this function, but outside of app_init, it sbould always return true.
+ * You may call this function, but outside of app_init, it should always return true.
*/
bool _watch_rtc_is_enabled();
+/** @brief Sets the date and time.
+ * @param date_time The date and time you wish to set, with a year value from 0-63 representing 2020-2083.
+ * @note The SAM L22 stores the year as six bits representing a value from 0 to 63. It treats this as a year
+ * offset from a reference year, which must be a leap year. Since 2020 was a leap year, and it allows
+ * useful dates through 2083, it is assumed that watch apps will use 2020 as the reference year; thus
+ * 1 means 2021, 2 means 2022, etc. **You will be responsible for handling this offset in your code**,
+ * if the calendar year is needed for timestamp calculation logic or display purposes.
+ */
+void watch_rtc_set_date_time(watch_date_time date_time);
+
+/** @brief Returns the date and time.
+ * @return A watch_date_time with the current date and time, with a year value from 0-63 representing 2020-2083.
+ * @see watch_rtc_set_date_time for notes about how the year is stored.
+ */
+watch_date_time watch_rtc_get_date_time();
+
+/** @brief Registers an alarm callback that will be called when the RTC time matches the target time, as masked
+ * by the provided mask.
+ * @param callback The function you wish to have called when the alarm fires. If this value is NULL, the alarm
+ * interrupt will still be enabled, but no callback function will be called.
+ * @param alarm_time The time that you wish to match. The date is currently ignored.
+ * @param mask One of the values in watch_rtc_alarm_match indicating which values to check.
+ * @details The alarm interrupt is a versatile tool for scheduling events in the future, especially since it can
+ * wake the device from both shallow and deep sleep modes. The key to its versatility is the mask
+ * parameter. Suppose we set an alarm for midnight, 00:00:00.
+ * * if mask is ALARM_MATCH_SS, the alarm will fire every minute when the clock ticks to seconds == 0.
+ * * with ALARM_MATCH_MMSS, the alarm will once an hour, at the top of each hour.
+ * * with ALARM_MATCH_HHMMSS, the alarm will fire at midnight every day.
+ * In theory the SAM L22's alarm function can match on days, months and even years, but I have not had
+ * success with this yet; as such, I am omitting these options for now.
+ */
+void watch_rtc_register_alarm_callback(ext_irq_cb_t callback, watch_date_time alarm_time, watch_rtc_alarm_match mask);
+
+/** @brief Disables the alarm callback.
+ */
+void watch_rtc_disable_alarm_callback();
+
+/** @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.
+ * @note this is equivalent to calling watch_rtc_register_periodic_callback with a frequency of 1. It can be
+ * disabled with either watch_rtc_disable_tick_callback() or watch_rtc_disable_periodic_callback(1),
+ * and will also be disabled when watch_rtc_disable_all_periodic_callbacks is called.
+ */
+void watch_rtc_register_tick_callback(ext_irq_cb_t callback);
+
+/** @brief Disables the tick callback for the given period.
+ */
+void watch_rtc_disable_tick_callback();
+
+/** @brief Registers a callback that will be called at a configurable period.
+ * @param callback The function you wish to have called at the specified period. If you pass in NULL, the periodic
+ * interrupt will still be enabled, but no callback function will be called.
+ * @param frequency 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_tick_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_periodic_callback(ext_irq_cb_t callback, uint8_t frequency);
+
+/** @brief Disables the tick callback for the given period.
+ * @param frequency 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_periodic_callback(uint8_t frequency);
+
+/** @brief Disables all periodic callbacks, including the once-per-second tick callback.
+ */
+void watch_rtc_disable_all_periodic_callbacks();
+
/** @brief Sets the system date and time.
* @param date_time A struct representing the date and time you wish to set.
*/
+__attribute__((deprecated("Use watch_rtc_set_date_time function instead")))
void watch_set_date_time(struct calendar_date_time date_time);
/** @brief Returns the system date and time in the provided struct.
- * @param date_time A pointer to a calendar_date_time struct.
- It will be populated with the correct date and time on return.
+ * @param date_time A pointer to a calendar_date_time struct. It will have with the correct date and time on return.
*/
+__attribute__((deprecated("Use the watch_rtc_get_date_time function instead")))
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.
+ * @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_tick_callback function instead")))
void watch_register_tick_callback(ext_irq_cb_t callback);
+
/// @}
+#endif
diff --git a/watch-library/watch/watch_slcd.c b/watch-library/watch/watch_slcd.c
index 7210713a..ba9d12b2 100644
--- a/watch-library/watch/watch_slcd.c
+++ b/watch-library/watch/watch_slcd.c
@@ -22,6 +22,8 @@
* SOFTWARE.
*/
+#include "watch_slcd.h"
+
//////////////////////////////////////////////////////////////////////////////////////////
// Segmented Display
diff --git a/watch-library/watch/watch_slcd.h b/watch-library/watch/watch_slcd.h
index efef99ac..4f5a617c 100644
--- a/watch-library/watch/watch_slcd.h
+++ b/watch-library/watch/watch_slcd.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_SLCD_H_INCLUDED
+#define _WATCH_SLCD_H_INCLUDED
////< @file watch_slcd.h
+#include "watch.h"
+
/** @addtogroup slcd Segment LCD Display
* @brief This section covers functions related to the Segment LCD display driver, which is responsible
* for displaying strings of characters and indicators on the main watch display.
@@ -100,3 +104,4 @@ void watch_clear_indicator(WatchIndicatorSegment indicator);
void watch_clear_all_indicators();
/// @}
+#endif
diff --git a/watch-library/watch/watch_uart.c b/watch-library/watch/watch_uart.c
index 3d97803d..d35533d0 100644
--- a/watch-library/watch/watch_uart.c
+++ b/watch-library/watch/watch_uart.c
@@ -50,6 +50,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include "watch_uart.h"
#include "peripheral_clk_config.h"
void watch_enable_debug_uart(uint32_t baud) {
diff --git a/watch-library/watch/watch_uart.h b/watch-library/watch/watch_uart.h
index 3c4f7aef..3e98bd35 100644
--- a/watch-library/watch/watch_uart.h
+++ b/watch-library/watch/watch_uart.h
@@ -21,8 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifndef _WATCH_UART_H_INCLUDED
+#define _WATCH_UART_H_INCLUDED
////< @file watch_uart.h
+#include "watch.h"
+
/** @addtogroup debug Debug UART
* @brief This section covers functions related to the debug UART, available on
* pin D1 of the 9-pin connector.
@@ -51,3 +55,4 @@ void watch_debug_putc(char c);
__attribute__((deprecated("Use printf to log debug messages over USB.")))
void watch_debug_puts(char *s);
/// @}
+#endif