WIP: refactor RTC to use clock mode directly
This commit is contained in:
		
							parent
							
								
									751ed9c7a4
								
							
						
					
					
						commit
						a65dcf1ec8
					
				@ -376,55 +376,8 @@ int32_t _calendar_register_callback(struct calendar_dev *const dev, calendar_drv
 | 
				
			|||||||
	return ERR_NONE;
 | 
						return ERR_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * \brief RTC interrupt handler
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \param[in] dev The pointer to calendar device struct
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void _rtc_interrupt_handler(struct calendar_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* Read and mask interrupt flag register */
 | 
					 | 
				
			||||||
	uint16_t interrupt_status  = hri_rtcmode0_read_INTFLAG_reg(dev->hw);
 | 
					 | 
				
			||||||
	uint16_t interrupt_enabled = hri_rtcmode0_read_INTEN_reg(dev->hw);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_ALARM0) {
 | 
					 | 
				
			||||||
		if (dev->callback_alarm != NULL) {
 | 
					 | 
				
			||||||
			dev->callback_alarm();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Clear interrupt flag */
 | 
					 | 
				
			||||||
		hri_rtcmode0_clear_interrupt_CMP0_bit(dev->hw);
 | 
					 | 
				
			||||||
	} else if ((interrupt_status & interrupt_enabled) & RTC_MODE2_INTFLAG_PER7) {
 | 
					 | 
				
			||||||
		if (dev->callback_tick != NULL) {
 | 
					 | 
				
			||||||
			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);
 | 
					 | 
				
			||||||
		if (dev->callback_tamper != NULL) {
 | 
					 | 
				
			||||||
			dev->callback_tamper(reason);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		hri_rtc_write_TAMPID_reg(dev->hw, reason);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Clear interrupt flag */
 | 
					 | 
				
			||||||
		hri_rtcmode0_clear_interrupt_TAMPER_bit(dev->hw);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * \brief Set calendar IRQ
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void _calendar_set_irq(struct calendar_dev *const dev)
 | 
					void _calendar_set_irq(struct calendar_dev *const dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	(void)dev;
 | 
						(void)dev;
 | 
				
			||||||
	NVIC_SetPendingIRQ(RTC_IRQn);
 | 
						NVIC_SetPendingIRQ(RTC_IRQn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * \brief Rtc interrupt handler
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void RTC_Handler(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	_rtc_interrupt_handler(_rtc_dev);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -13,19 +13,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct slcd_sync_descriptor SEGMENT_LCD_0;
 | 
					struct slcd_sync_descriptor SEGMENT_LCD_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct calendar_descriptor CALENDAR_0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct i2c_m_sync_desc I2C_0;
 | 
					struct i2c_m_sync_desc I2C_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CALENDAR_0_CLOCK_init(void) {
 | 
					 | 
				
			||||||
	hri_mclk_set_APBAMASK_RTC_bit(MCLK);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CALENDAR_0_init(void) {
 | 
					 | 
				
			||||||
	CALENDAR_0_CLOCK_init();
 | 
					 | 
				
			||||||
	calendar_init(&CALENDAR_0, RTC);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void I2C_0_PORT_init(void) {
 | 
					void I2C_0_PORT_init(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpio_set_pin_pull_mode(SDA,
 | 
						gpio_set_pin_pull_mode(SDA,
 | 
				
			||||||
 | 
				
			|||||||
@ -38,36 +38,16 @@ extern "C" {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern struct adc_sync_descriptor ADC_0;
 | 
					extern struct adc_sync_descriptor ADC_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct calendar_descriptor CALENDAR_0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern struct i2c_m_sync_desc I2C_0;
 | 
					extern struct i2c_m_sync_desc I2C_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct pwm_descriptor PWM_0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern struct pwm_descriptor       PWM_1;
 | 
					 | 
				
			||||||
extern struct slcd_sync_descriptor SEGMENT_LCD_0;
 | 
					extern struct slcd_sync_descriptor SEGMENT_LCD_0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADC_0_PORT_init(void);
 | 
					 | 
				
			||||||
void ADC_0_CLOCK_init(void);
 | 
					 | 
				
			||||||
void ADC_0_init(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CALENDAR_0_CLOCK_init(void);
 | 
					 | 
				
			||||||
void CALENDAR_0_init(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void I2C_0_CLOCK_init(void);
 | 
					void I2C_0_CLOCK_init(void);
 | 
				
			||||||
void I2C_0_init(void);
 | 
					void I2C_0_init(void);
 | 
				
			||||||
void I2C_0_PORT_init(void);
 | 
					void I2C_0_PORT_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void delay_driver_init(void);
 | 
					void delay_driver_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PWM_0_PORT_init(void);
 | 
					 | 
				
			||||||
void PWM_0_CLOCK_init(void);
 | 
					 | 
				
			||||||
void PWM_0_init(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void PWM_1_PORT_init(void);
 | 
					 | 
				
			||||||
void PWM_1_CLOCK_init(void);
 | 
					 | 
				
			||||||
void PWM_1_init(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EXTERNAL_IRQ_0_init(void);
 | 
					void EXTERNAL_IRQ_0_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SEGMENT_LCD_0_init(void);
 | 
					void SEGMENT_LCD_0_init(void);
 | 
				
			||||||
 | 
				
			|||||||
@ -29,24 +29,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.
 | 
					#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
 | 
					#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) {
 | 
					void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool level) {
 | 
				
			||||||
    uint32_t pinmux;
 | 
					    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) {
 | 
					    switch (pin) {
 | 
				
			||||||
        case A4:
 | 
					        case A4:
 | 
				
			||||||
@ -84,16 +69,17 @@ void watch_register_extwake_callback(uint8_t pin, ext_irq_cb_t callback, bool le
 | 
				
			|||||||
    gpio_set_pin_function(pin, pinmux);
 | 
					    gpio_set_pin_function(pin, pinmux);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // disable the RTC
 | 
					    // disable the RTC
 | 
				
			||||||
	if (hri_rtcmode0_get_CTRLA_ENABLE_bit(RTC)) {
 | 
					    RTC->MODE2.CTRLA.bit.ENABLE = 0;
 | 
				
			||||||
		hri_rtcmode0_clear_CTRLA_ENABLE_bit(RTC);
 | 
					    while (RTC->MODE2.SYNCBUSY.bit.ENABLE);
 | 
				
			||||||
		hri_rtcmode0_wait_for_sync(RTC, RTC_MODE0_SYNCBUSY_ENABLE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
    // update the configuration
 | 
					 | 
				
			||||||
    hri_rtc_write_TAMPCTRL_reg(RTC, config);
 | 
					 | 
				
			||||||
    // re-enable the RTC
 | 
					 | 
				
			||||||
    hri_rtcmode0_set_CTRLA_ENABLE_bit(RTC);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _extwake_register_callback(&CALENDAR_0.device, extwake_callback);
 | 
					    // update the configuration
 | 
				
			||||||
 | 
					    RTC->MODE2.TAMPCTRL.reg = config;
 | 
				
			||||||
 | 
					    // re-enable the RTC
 | 
				
			||||||
 | 
					    RTC->MODE2.CTRLA.bit.ENABLE = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NVIC_ClearPendingIRQ(RTC_IRQn);
 | 
				
			||||||
 | 
					    NVIC_EnableIRQ(RTC_IRQn);
 | 
				
			||||||
 | 
					    RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_TAMPER;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void watch_disable_extwake_interrupt(uint8_t pin) {
 | 
					void watch_disable_extwake_interrupt(uint8_t pin) {
 | 
				
			||||||
@ -176,7 +162,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_register_tick_callback(NULL);
 | 
					    watch_disable_tick_callback();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 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;
 | 
				
			||||||
@ -202,7 +188,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_register_tick_callback(NULL);
 | 
					    watch_disable_tick_callback();
 | 
				
			||||||
    _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);
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,11 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
////< @file watch_deepsleep.h
 | 
					////< @file watch_deepsleep.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
 | 
					/** @addtogroup deepsleep Deep Sleep Control
 | 
				
			||||||
  * @brief This section covers functions related to preparing for and entering BACKUP mode, the
 | 
					  * @brief This section covers functions related to preparing for and entering BACKUP mode, the
 | 
				
			||||||
  *        deepest sleep mode available on the SAM L22
 | 
					  *        deepest sleep mode available on the SAM L22
 | 
				
			||||||
 | 
				
			|||||||
@ -56,8 +56,7 @@ void _watch_init() {
 | 
				
			|||||||
    SUPC->BOD33.bit.ENABLE = 1;
 | 
					    SUPC->BOD33.bit.ENABLE = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // External wake depends on RTC; calendar is a required module.
 | 
					    // External wake depends on RTC; calendar is a required module.
 | 
				
			||||||
    CALENDAR_0_init();
 | 
					    _watch_rtc_init();
 | 
				
			||||||
    calendar_enable(&CALENDAR_0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // set up state
 | 
					    // set up state
 | 
				
			||||||
    btn_alarm_callback = NULL;
 | 
					    btn_alarm_callback = NULL;
 | 
				
			||||||
 | 
				
			|||||||
@ -22,19 +22,153 @@
 | 
				
			|||||||
 * SOFTWARE.
 | 
					 * SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 bool _watch_rtc_is_enabled() {
 | 
					ext_irq_cb_t tick_callback;
 | 
				
			||||||
    return RTC->MODE0.CTRLA.bit.ENABLE;
 | 
					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 watch_set_date_time(struct calendar_date_time date_time) {
 | 
					void _sync_rtc() {
 | 
				
			||||||
    calendar_set_date(&CALENDAR_0, &date_time.date);
 | 
					    while (RTC->MODE2.SYNCBUSY.reg);
 | 
				
			||||||
    calendar_set_time(&CALENDAR_0, &date_time.time);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void watch_get_date_time(struct calendar_date_time *date_time) {
 | 
					void _watch_rtc_init() {
 | 
				
			||||||
    calendar_get_date_time(&CALENDAR_0, date_time);
 | 
					    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_Type val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val.bit.SECOND = date_time.second;
 | 
				
			||||||
 | 
					    val.bit.MINUTE = date_time.minute;
 | 
				
			||||||
 | 
					    val.bit.HOUR = date_time.hour;
 | 
				
			||||||
 | 
					    val.bit.DAY = date_time.day;
 | 
				
			||||||
 | 
					    val.bit.MONTH = date_time.month;
 | 
				
			||||||
 | 
					    val.bit.YEAR = (uint8_t)(date_time.year - WATCH_RTC_REFERENCE_YEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RTC->MODE2.CLOCK.reg = val.reg;
 | 
				
			||||||
 | 
					    _sync_rtc();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watch_date_time watch_rtc_get_date_time() {
 | 
				
			||||||
 | 
					    watch_date_time retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _sync_rtc();
 | 
				
			||||||
 | 
					    RTC_MODE2_CLOCK_Type val = RTC->MODE2.CLOCK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    retval.year = val.bit.YEAR + WATCH_RTC_REFERENCE_YEAR;
 | 
				
			||||||
 | 
					    retval.month = val.bit.MONTH;
 | 
				
			||||||
 | 
					    retval.day = val.bit.DAY;
 | 
				
			||||||
 | 
					    retval.hour = val.bit.HOUR;
 | 
				
			||||||
 | 
					    retval.minute = val.bit.MINUTE;
 | 
				
			||||||
 | 
					    retval.second = val.bit.SECOND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void watch_register_tick_callback(ext_irq_cb_t callback) {
 | 
					void watch_register_tick_callback(ext_irq_cb_t callback) {
 | 
				
			||||||
    _prescaler_register_callback(&CALENDAR_0.device, callback);
 | 
					    tick_callback = callback;
 | 
				
			||||||
 | 
					    NVIC_ClearPendingIRQ(RTC_IRQn);
 | 
				
			||||||
 | 
					    NVIC_EnableIRQ(RTC_IRQn);
 | 
				
			||||||
 | 
					    RTC->MODE2.INTENSET.reg = RTC_MODE2_INTENSET_PER7;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void watch_disable_tick_callback() {
 | 
				
			||||||
 | 
					    RTC->MODE2.INTENCLR.reg = RTC_MODE2_INTENCLR_PER7;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.bit.SECOND = alarm_time.second;
 | 
				
			||||||
 | 
					    RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE = alarm_time.minute;
 | 
				
			||||||
 | 
					    RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR = alarm_time.hour;
 | 
				
			||||||
 | 
					    RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY = alarm_time.day;
 | 
				
			||||||
 | 
					    RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH = alarm_time.month;
 | 
				
			||||||
 | 
					    RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR = (uint8_t)(alarm_time.year - WATCH_RTC_REFERENCE_YEAR);
 | 
				
			||||||
 | 
					    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_ALARM0) {
 | 
				
			||||||
 | 
					        if (alarm_callback != NULL) {
 | 
				
			||||||
 | 
					            alarm_callback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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) {
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///////////////////////
 | 
				
			||||||
 | 
					// Deprecated functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void watch_set_date_time(struct calendar_date_time date_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) {
 | 
				
			||||||
 | 
					    _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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -35,24 +35,84 @@
 | 
				
			|||||||
  *          to wake from STANDBY mode.
 | 
					  *          to wake from STANDBY mode.
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
/// @{
 | 
					/// @{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WATCH_RTC_REFERENCE_YEAR (2020)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct watch_date_time {
 | 
				
			||||||
 | 
					    uint16_t year;
 | 
				
			||||||
 | 
					    uint8_t month;
 | 
				
			||||||
 | 
					    uint8_t day;
 | 
				
			||||||
 | 
					    uint8_t hour;
 | 
				
			||||||
 | 
					    uint8_t minute;
 | 
				
			||||||
 | 
					    uint8_t second;
 | 
				
			||||||
 | 
					} 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.
 | 
					/** @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();
 | 
					bool _watch_rtc_is_enabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Sets the date and time.
 | 
				
			||||||
 | 
					  * @param date_time The time you wish to set.
 | 
				
			||||||
 | 
					  * @note Internally, 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. For now, this library uses 2020 as
 | 
				
			||||||
 | 
					  *       the reference year, so the range of valid values is 2020 to 2083.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					void watch_rtc_set_date_time(watch_date_time date_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Returns the system date and time in the provided struct.
 | 
				
			||||||
 | 
					  * @return A watch_date_time with the current date and time.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					void watch_register_tick_callback(ext_irq_cb_t callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @brief Disables the tick callback.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					void watch_disable_tick_callback();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @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.
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
 | 
					__attribute__((deprecated("Use watch_rtc_set_date_time function instead")))
 | 
				
			||||||
void watch_set_date_time(struct calendar_date_time date_time);
 | 
					void watch_set_date_time(struct calendar_date_time date_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @brief Returns the system date and time in the provided struct.
 | 
					/** @brief Returns the system date and time in the provided struct.
 | 
				
			||||||
  * @param date_time A pointer to a calendar_date_time struct.
 | 
					  * @param date_time A pointer to a calendar_date_time struct. It will have with the correct date and time on return.
 | 
				
			||||||
                     It will be populated 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);
 | 
					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.
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
void watch_register_tick_callback(ext_irq_cb_t callback);
 | 
					 | 
				
			||||||
/// @}
 | 
					/// @}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user