/* * MIT License * * Copyright (c) 2022 Joey Castillo * Copyright (c) 2025 Alessandro Genova * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "rtc32.h" #include "sam.h" rtc_cb_t _rtc_callback = NULL; #if defined(_SAMD21_) || defined(_SAMD11_) #define CTRLREG (RTC->MODE0.CTRL) #define MODE_SETTING (RTC_MODE0_CTRL_MODE_COUNT32_Val) // Mode 0 Count32 #define PRESCALER_SETTING (RTC_MODE0_CTRL_PRESCALER_DIV8_Val) #else #define CTRLREG (RTC->MODE0.CTRLA) #define MODE_SETTING (RTC_MODE0_CTRLA_MODE_COUNT32_Val) // Mode 0 Count32 #define PRESCALER_SETTING (RTC_MODE0_CTRLA_PRESCALER_DIV8_Val) #endif bool rtc_is_enabled(void) { return CTRLREG.bit.ENABLE; } static void _rtc_sync(void) { #if defined(_SAMD21_) || defined(_SAMD11_) while (RTC->MODE0.STATUS.bit.SYNCBUSY); #else while (RTC->MODE0.SYNCBUSY.reg & RTC_MODE0_SYNCBUSY_MASK); #endif } void rtc_init(void) { #if defined(_SAMD21_) || defined(_SAMD11_) // enable the RTC PM->APBAMASK.reg |= PM_APBAMASK_RTC; // clock RTC with GCLK3 (prescaled 1024 Hz output from the external crystal) GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN(3) | GCLK_CLKCTRL_ID(RTC_GCLK_ID) | GCLK_CLKCTRL_CLKEN; #else MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC; #endif if (rtc_is_enabled()) return; // don't reset the RTC if it's already set up. _rtc_sync(); CTRLREG.bit.SWRST = 1; _rtc_sync(); CTRLREG.bit.MODE = MODE_SETTING; CTRLREG.bit.PRESCALER = PRESCALER_SETTING; #if defined(_SAML21_) || defined(_SAML22_) || defined(_SAMD51_) CTRLREG.bit.COUNTSYNC = 1; #endif RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_OVF; } void rtc_enable(void) { if (rtc_is_enabled()) return; CTRLREG.bit.ENABLE = 1; _rtc_sync(); } void rtc_set_counter(rtc_counter_t counter) { // // syncing before and after was found to increase reliability on Sensor Watch _rtc_sync(); RTC->MODE0.COUNT.reg = counter; _rtc_sync(); } rtc_counter_t rtc_get_counter(void) { rtc_counter_t counter; #if defined(_SAML21_) || defined(_SAML22_) || defined(_SAMD51_) CTRLREG.bit.COUNTSYNC = 1; #endif _rtc_sync(); counter = RTC->MODE0.COUNT.reg; return counter; } void rtc_enable_compare_interrupt(uint32_t compare_time) { RTC->MODE0.COMP[0].reg = compare_time; _rtc_sync(); RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; // NVIC_ClearPendingIRQ(RTC_IRQn); // NVIC_EnableIRQ(RTC_IRQn); } void rtc_configure_callback(rtc_cb_t callback) { _rtc_callback = callback; } void rtc_disable_compare_interrupt(void){ RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; // NVIC_ClearPendingIRQ(RTC_IRQn); // NVIC_DisableIRQ(RTC_IRQn); } void irq_handler_rtc(void); void irq_handler_rtc(void) { uint16_t int_cause = (uint16_t)RTC->MODE0.INTFLAG.reg; RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_MASK; (void)RTC->MODE0.INTFLAG.reg; /* Invoke registered Callback function */ if (_rtc_callback != NULL) { _rtc_callback(int_cause); } // NVIC_ClearPendingIRQ(RTC_IRQn); }