SAMD21 double interrupt after deep sleep

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The end goal is to have a 1 mibisecond (1/1024) tick when awake, and then to sleep for 10-20 seconds.  We are using the RTC connected to a 32 kHz external oscillator for timing.  We have attempted to use the RTC CNT/COMP, but whenever you reset the count then jitter is introduce into the system.  To fix this we are using the RTC/event system to generate the mibisecond tick and then using RTC CNT/COMP for sleep.  This appears to work and there is no longer any jitter.  The problem I am seeing is that after wake up from deep sleep and activation of the RTC event interrupt I will often see two ticks that are spaced about 200 us apart, with the second one being right on the mibisecond tick.  The first one, of course, throws off the tick count.  The following is some test code.  Any techniques for eliminating the first tick?  I have tried adding delays and adjusting the order of things but nothing seems to stabilize this double interrupt.  The difficult part is that it doesn't always show up after every deep sleep, thus making it hard to account for in code.

 

volatile static u32 Elapsed;
volatile bool ElapsedFlag = false;
static void rtcBootup(void) {
	PM->APBAMASK.bit.RTC_ = true;
	GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_Type){{.ID=GCLK_CLKCTRL_ID_RTC_Val, .GEN=GCLK_CLKCTRL_GEN_GCLK1_Val, .CLKEN=true}}.reg;
	while (GCLK->STATUS.bit.SYNCBUSY) { }
	RTC->MODE0.CTRL.bit.ENABLE = false;
	while (RTC->MODE0.STATUS.bit.SYNCBUSY) { }
	RTC->MODE0.CTRL.bit.SWRST = true;
	while (RTC->MODE0.STATUS.bit.SYNCBUSY || RTC->MODE0.CTRL.bit.SWRST) { }
	RTC->MODE0.EVCTRL.bit.PEREO2 = true;
	RTC->MODE0.CTRL.reg = (RTC_MODE0_CTRL_Type){{.MODE=RTC_MODE0_CTRL_MODE_COUNT32_Val, .MATCHCLR=false, .PRESCALER=RTC_MODE0_CTRL_PRESCALER_DIV32_Val, .ENABLE=true}}.reg;
	while (RTC->MODE0.STATUS.bit.SYNCBUSY) { }
	NVIC_EnableIRQ(RTC_IRQn);
	RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;

	PM->APBCMASK.bit.EVSYS_ = true;
	GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_Type){{.ID=GCLK_CLKCTRL_ID_EVSYS_0_Val, .GEN=GCLK_CLKCTRL_GEN_GCLK1_Val, .CLKEN=true}}.reg;
	while (GCLK->STATUS.bit.SYNCBUSY) { }
	EVSYS->CHANNEL.reg = (EVSYS_CHANNEL_Type){{.CHANNEL=0, .EDGSEL=EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val, .PATH=EVSYS_CHANNEL_PATH_SYNCHRONOUS_Val, .EVGEN=0x06}}.reg;
	NVIC_EnableIRQ(EVSYS_IRQn);
	EVSYS->INTENSET.reg = EVSYS_INTENSET_EVD0;
}

void EVSYS_Handler(void) {
	EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVD0;
	gpioSet(PinTestPoint2);
	Elapsed++;
	if (Elapsed == 20) {
		gpioToggle(PinTestPoint1);
		ElapsedFlag = true;
	}
	gpioClear(PinTestPoint2);
}

void RTC_Handler(void) {
	RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
}

static void steadyMode(void) {
	RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
	while (RTC->MODE0.COUNT.reg < 15) { }
	Elapsed = RTC->MODE0.COUNT.reg;
	EVSYS->INTENSET.reg = EVSYS_INTFLAG_EVD0;
	EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVD0;
}

static void snoozeMode(void) {
	EVSYS->INTENCLR.reg = EVSYS_INTENCLR_EVD0;
	RTC->MODE0.COUNT.reg = 0;
	RTC->MODE0.COMP[0].reg = 10;
	RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
	RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;

}

static void playRTC(void) {
	while(1) {
		snoozeMode();
		ElapsedFlag = false;
		SCB->SCR |=  SCB_SCR_SLEEPDEEP_Msk;
		__DSB(); // data-sync-barrier
		__WFI(); // wait-for-interrupt
		steadyMode();
		while (ElapsedFlag == false) {
		}
	}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So with some help from Microchip support they enlightened me that I need to clear the event flag: 

EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVD0;

Before I turn it back on:

EVSYS->INTENSET.reg = EVSYS_INTFLAG_EVD0;

So swapping those two lines of code and the jitter or double tap goes away.