Anyone have experience with the Atmel "RTC" modules that they're putting on their small ARMs? I'm having mysterious problems! [copied from AVRFreaks...)
=====
I haven't quite solved the debug strangeness, but the code overall is working better, except for a little problem that seems like it's probably a generic timer issue rather than something SAM specific.
In order to get microsecond and millisecond counters, I've configured the RTC to have a 1MHz clock (us) and COMP[0] = 999 to cause an interrupt every 1000 ticks (ms) The ISR increments the ms counter, and to get elapsed microseconds I add the current RTC counter value to 1000*mscount from the ISR. It seems straightforward, barring minor complications like making the math interrupt safe and accounting for counter resets that haven't had the ISR serviced yet. I *thought* I had those taken care of.
But sometimes my microsecond count moves backwards, and I can't figure our why. :-( Am I missing some well-known technique for dividing up a timer between HW and ISR?
Here is the meat of the code:
void RTC_init()
{
//Configure GCLK Generator 2 to use a divided XOSC as input, and feed this clock to RTC
// This gives us a 1MHz RTC clock.
GCLK->GENDIV.reg = ((8 << GCLK_GENDIV_DIV_Pos) | (2 << GCLK_GENDIV_ID_Pos));
GCLK->GENCTRL.reg = ((2 << GCLK_GENCTRL_ID_Pos) | (GCLK_GENCTRL_SRC_XOSC) | (GCLK_GENCTRL_GENEN));
GCLK->CLKCTRL.reg = ((GCLK_CLKCTRL_GEN_GCLK2) | (GCLK_CLKCTRL_CLKEN) | (GCLK_CLKCTRL_ID(RTC_GCLK_ID)));
RTC->MODE0.CTRL.reg = 0; // disable, so that we can reset
RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_SWRST; //reset
RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_MODE_COUNT32 | RTC_MODE0_CTRL_MATCHCLR;
RTC->MODE0.COMP[0].reg = 1000 - 1;
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
RTC->MODE0.CTRL.reg |= RTC_MODE0_CTRL_ENABLE;
RTC->MODE0.READREQ.reg |= RTC_READREQ_RCONT|RTC_READREQ_RREQ; // continuous read sync
RTC->MODE0.INTFLAG.reg = 0xFF;
NVIC_SetPriority (RTC_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
NVIC_EnableIRQ(RTC_IRQn);
}
void RTC_Handler(void)
{
millisecondcount++;
RTC->MODE0.INTFLAG.reg = 0xFF; // Clear all possible interrupts
}
volatile uint32_t lastmicros;
volatile uint32_t question = 0;
volatile uint32_t asked = 0;
uint32_t micros()
{
uint32_t thismicros;
cpu_irq_enter_critical();
asked++; // how many calls to us?
thismicros = RTC->MODE0.COUNT.reg;
if (RTC->MODE0.INTFLAG.bit.CMP0) {
/*
* Check for a ms interrupt pending but not yet
* serviced, and correct for it.
*/
thismicros += 1000;
}
thismicros += 1000*millisecondcount;
if (thismicros < lastmicros) {
// We shouldn't get here. But allow it to BKPT
question++; // how many "questionable" results
}
lastmicros = thismicros;
cpu_irq_leave_critical();
return thismicros;
}
"question", which ought to stay zero, runs to about 7000 in the first 10 seconds of execution (so, not an overflow problem, either.)
The main loop is calling micros() pretty much continuously. "asked" is about 3 million.