cpu/sam0_common: rtt: correcly clear flags.

The INTFLAGS register is cleared by writing a 1 to the corresponding interrupt
flag bit. From the samr21's manual:

> Writing a zero to this bit has no effect.
> Writing a one to this bit clears the Compare 0 interrupt flag.

This is a common pattern in flag registers.

This RTT driver is using or-equal to clear the flags, which means it can
possibly clear other interrupts. There's a small chance that one event is
missed if it happens very close to another event.

Credits to @benpicco, @dylad for pointing out missing fixes.
This commit is contained in:
Juan Carrano 2019-09-10 11:41:28 +02:00
parent 741d5437a7
commit f7279c84bb

View File

@ -98,7 +98,7 @@ void rtt_init(void)
_wait_syncbusy();
/* initially clear flag */
RTC->MODE0.INTFLAG.reg |= RTC_MODE0_INTFLAG_CMP0
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0
| RTC_MODE0_INTFLAG_OVF;
NVIC_EnableIRQ(RTC_IRQn);
@ -116,12 +116,12 @@ void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
_overflow_arg = arg;
/* enable overflow interrupt */
RTC->MODE0.INTENSET.bit.OVF = 1;
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_OVF;
}
void rtt_clear_overflow_cb(void)
{
/* disable overflow interrupt */
RTC->MODE0.INTENCLR.bit.OVF = 1;
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_OVF;
}
uint32_t rtt_get_counter(void)
@ -158,14 +158,14 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
_wait_syncbusy();
/* enable compare interrupt and clear flag */
RTC->MODE0.INTFLAG.reg |= RTC_MODE0_INTFLAG_CMP0;
RTC->MODE0.INTENSET.reg |= RTC_MODE0_INTENSET_CMP0;
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
}
void rtt_clear_alarm(void)
{
/* clear compare interrupt */
RTC->MODE0.INTENCLR.bit.CMP0 = 1;
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
}
void rtt_poweron(void)
@ -189,16 +189,16 @@ void rtt_poweroff(void)
void isr_rtc(void)
{
if (RTC->MODE0.INTFLAG.bit.OVF) {
RTC->MODE0.INTFLAG.reg |= RTC_MODE0_INTFLAG_OVF;
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_OVF;
if (_overflow_cb) {
_overflow_cb(_overflow_arg);
}
}
if (RTC->MODE0.INTFLAG.bit.CMP0) {
/* clear flag */
RTC->MODE0.INTFLAG.reg |= RTC_MODE0_INTFLAG_CMP0;
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
/* disable interrupt */
RTC->MODE0.INTENCLR.bit.CMP0 = 1;
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
if (_cmp0_cb) {
_cmp0_cb(_cmp0_arg);
}