Context: For power savings, I'm putting the SAMD21 into STANDBY mode until an RTC COMP interrupt wakes it back up. (The RTC is driven from the OSCULP32K.) The challenge is to make sure that the RTC COMP register is set to be greater than the COUNT register before going so sleep.
Consider this code:
// Assume RTC COMP interrupts have been enabled. // Set RTC to wake processor in two tics from now. uint32_t now = hri_rtcmode0_read_COUNT_COUNT_bf(RTC); hri_rtcmode0_write_COMP_COMP_bf(RTC, 0, now + 2); sleep(SLEEP_STANDBY_MODE);
The problem is that there's a race condition: if an interrupt occurs between reading `now` and entering sleep mode, the RTC COUNT register might have advanced past the COMP value, so the system will sleep "forever" (or at least for 2^32 RTC tics). This is only slightly better:
CRITICAL_SECTION_ENTER() uint32_t now = hri_rtcmode0_read_COUNT_COUNT_bf(RTC); hri_rtcmode0_write_COMP_COMP_bf(RTC, 0, now + 2); CRITICAL_SECTION_LEAVE() sleep(SLEEP_STANDBY_MODE);
...but it still has the same race condition after leaving the critical section and before entering sleep.
Of course, RTC interrupts must be enabled before calling sleep, which suggests something like this:
CRITICAL_SECTION_ENTER() uint32_t now = hri_rtcmode0_read_COUNT_COUNT_bf(RTC); hri_rtcmode0_write_COMP_COMP_bf(RTC, 0, now + 2); <enable only RTC COMP interrupts> sleep(SLEEP_STANDBY_MODE); CRITICAL_SECTION_LEAVE()
So the questions:
1. Is this the way you'd do it?
2. What's the approved way to <enable only RTC COMP interrupts>?