diff --git a/Makefile b/Makefile index 1532bd29..db2a0417 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ INCLUDES += \ # Add your source files here. SRCS += \ ./watch-library/hardware/watch/watch_gpio.c \ + ./watch-library/hardware/watch/watch_rtc.c \ ./watch-library/hardware/watch/watch_tcc.c \ ./app.c \ diff --git a/app.c b/app.c index f5cbc54f..0ba7a444 100644 --- a/app.c +++ b/app.c @@ -1,19 +1,25 @@ #include "app.h" #include "watch.h" +#include "watch_private.h" #include "delay.h" void app_init(void) { + _watch_rtc_init(); } void app_setup(void) { watch_enable_leds(); + watch_rtc_register_periodic_callback(NULL, 1); } bool app_loop(void) { - watch_set_led_yellow(); - delay_ms(500); - watch_set_led_off(); - delay_ms(500); + watch_date_time date_time = watch_rtc_get_date_time(); - return false; + if (date_time.unit.second % 2 == 0) { + watch_set_led_red(); + } else { + watch_set_led_green(); + } + + return true; } \ No newline at end of file diff --git a/watch-library/hardware/watch/watch_rtc.c b/watch-library/hardware/watch/watch_rtc.c index 93cb9f1c..8d3a897a 100644 --- a/watch-library/hardware/watch/watch_rtc.c +++ b/watch-library/hardware/watch/watch_rtc.c @@ -22,56 +22,41 @@ * SOFTWARE. */ -#include "watch_rtc.h" +#include -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; +#include "watch_rtc.h" +#include "watch_private.h" + +watch_cb_t tick_callbacks[8]; +watch_cb_t alarm_callback; +watch_cb_t btn_alarm_callback; +watch_cb_t a2_callback; +watch_cb_t a4_callback; + +void watch_rtc_callback(uint16_t interrupt_status); bool _watch_rtc_is_enabled(void) { - return RTC->MODE2.CTRLA.bit.ENABLE; -} - -static void _sync_rtc(void) { - while (RTC->MODE2.SYNCBUSY.reg); + return rtc_is_enabled(); } void _watch_rtc_init(void) { - 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(); + rtc_init(); +#ifdef STATIC_FREQCORR + watch_rtc_freqcorr_write(STATIC_FREQCORR, 0); +#endif + rtc_enable(); + rtc_configure_callback(watch_rtc_callback); } -void watch_rtc_set_date_time(watch_date_time date_time) { - _sync_rtc(); // Double sync as without it at high Hz faces setting time is unrealiable (specifically, set_time_hackwatch) - RTC->MODE2.CLOCK.reg = date_time.reg; - _sync_rtc(); +void watch_rtc_set_date_time(rtc_date_time date_time) { + rtc_set_date_time(date_time); } -watch_date_time watch_rtc_get_date_time(void) { - watch_date_time retval; - - _sync_rtc(); - retval.reg = RTC->MODE2.CLOCK.reg; - - return retval; +rtc_date_time watch_rtc_get_date_time(void) { + return rtc_get_date_time(); } -void watch_rtc_register_tick_callback(ext_irq_cb_t callback) { +void watch_rtc_register_tick_callback(watch_cb_t callback) { watch_rtc_register_periodic_callback(callback, 1); } @@ -79,7 +64,7 @@ void watch_rtc_disable_tick_callback(void) { watch_rtc_disable_periodic_callback(1); } -void watch_rtc_register_periodic_callback(ext_irq_cb_t callback, uint8_t frequency) { +void watch_rtc_register_periodic_callback(watch_cb_t callback, uint8_t frequency) { // we told them, it has to be a power of 2. if (__builtin_popcount(frequency) != 1) return; @@ -111,7 +96,7 @@ void watch_rtc_disable_all_periodic_callbacks(void) { watch_rtc_disable_matching_periodic_callbacks(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(watch_cb_t callback, rtc_date_time alarm_time, 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; @@ -125,8 +110,7 @@ void watch_rtc_disable_alarm_callback(void) { RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_ALARM0; } -void RTC_Handler(void) { - uint16_t interrupt_status = RTC->MODE2.INTFLAG.reg; +void watch_rtc_callback(uint16_t interrupt_status) { uint16_t interrupt_enabled = RTC->MODE2.INTENSET.reg; if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER_Msk) { @@ -162,8 +146,7 @@ void RTC_Handler(void) { } } -void watch_rtc_enable(bool en) -{ +void watch_rtc_enable(bool en) { // Writing it twice - as it's quite dangerous operation. // If write fails - we might hang with RTC off, which means no recovery possible while (RTC->MODE2.SYNCBUSY.reg); @@ -173,8 +156,7 @@ void watch_rtc_enable(bool en) while (RTC->MODE2.SYNCBUSY.reg); } -void watch_rtc_freqcorr_write(int16_t value, int16_t sign) -{ +void watch_rtc_freqcorr_write(int16_t value, int16_t sign) { RTC_FREQCORR_Type data; data.bit.VALUE = value; diff --git a/watch-library/shared/watch/watch.h b/watch-library/shared/watch/watch.h index 10d9c474..ecff1927 100644 --- a/watch-library/shared/watch/watch.h +++ b/watch-library/shared/watch/watch.h @@ -57,7 +57,11 @@ deepest sleep mode available on the SAM L22. */ -// #include "watch_rtc.h" +/** @brief Typedef for a general-purpose callback function. + */ +typedef void (*watch_cb_t)(void); + +#include "watch_rtc.h" // #include "watch_slcd.h" // #include "watch_extint.h" #include "watch_tcc.h" diff --git a/watch-library/shared/watch/watch_rtc.h b/watch-library/shared/watch/watch_rtc.h index 3e63bb55..dcdbf798 100644 --- a/watch-library/shared/watch/watch_rtc.h +++ b/watch-library/shared/watch/watch_rtc.h @@ -21,44 +21,31 @@ * 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 + +#pragma once + ////< @file watch_rtc.h #include "watch.h" -#include "hpl_calendar.h" +#include "rtc.h" /** @addtogroup rtc Real-Time Clock * @brief This section covers functions related to the SAM L22's real-time clock peripheral, including * date, time and alarm functions. * @details The real-time clock is the only peripheral that main.c enables for you. It is the cornerstone * of low power operation on the watch, and it is required for several key functions that we - * assume will be available, namely the wake from BACKUP mode and the callback on the ALARM button. - * It is also required for the operation of the 1 Hz tick interrupt, which you will most likely use - * to wake from STANDBY mode. + * assume will be available, namely waking on a press of the ALARM button. It is also required + * for the operation of the 1 Hz tick interrupt, which we use to wake from STANDBY mode. */ /// @{ +extern watch_cb_t btn_alarm_callback; +extern watch_cb_t a2_callback; +extern watch_cb_t a4_callback; + #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; +#define watch_date_time rtc_date_time /** @brief Called by main.c to check if the RTC is enabled. * You may call this function, but outside of app_init, it should always return true. @@ -73,20 +60,20 @@ bool _watch_rtc_is_enabled(void); * 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); +void watch_rtc_set_date_time(rtc_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. + * @return A rtc_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(void); +rtc_date_time watch_rtc_get_date_time(void); /** @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. + * @param mask One of the values in 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 all sleep modes. The key to its versatility is the mask parameter. * Suppose we set an alarm for midnight, 00:00:00. @@ -96,7 +83,7 @@ watch_date_time watch_rtc_get_date_time(void); * 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); +void watch_rtc_register_alarm_callback(watch_cb_t callback, rtc_date_time alarm_time, rtc_alarm_match mask); /** @brief Disables the alarm callback. */ @@ -109,7 +96,7 @@ void watch_rtc_disable_alarm_callback(void); * 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); +void watch_rtc_register_tick_callback(watch_cb_t callback); /** @brief Disables the tick callback for the given period. */ @@ -130,7 +117,7 @@ void watch_rtc_disable_tick_callback(void); * 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); +void watch_rtc_register_periodic_callback(watch_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. @@ -158,4 +145,3 @@ void watch_rtc_enable(bool en); void watch_rtc_freqcorr_write(int16_t value, int16_t sign); /// @} -#endif