Sodaq One Wait For Interrupt not suspending operation

Dear Fora,

I am currently having a quandry where the __WFI() command does not seem to suspend operation until a trigger is reached. The idea of the code is to set an RTC counter for a minute and when the trigger is reached the loop{ } code runs once.

void rtcSetup(void)                     // Function to Setup the RTC & Timers
{
  //Set up the OSC32K to always run, also in deep sleep (for later)	
  SYSCTRL->OSC32K.bit.ONDEMAND = 0;		
  SYSCTRL->OSC32K.bit.RUNSTDBY = 1;
  SYSCTRL->OSC32K.bit.EN32K = 1;
  SYSCTRL->OSC32K.bit.ENABLE = 1;
  while((SYSCTRL->PCLKSR.bit.OSC32KRDY) == 0){}

  //Connect and divide OSC32K to a GCLK for the RTC
  GCLK->GENDIV.reg = ( GCLK_GENDIV_DIV(32) | GCLK_GENDIV_ID(RTC_GCLK_ID));
  GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_ID(RTC_GCLK_ID)) ; 

  while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

  //Connect and enable GCLK to RTC  
  GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(GCLK_CLKCTRL_ID_RTC) | GCLK_CLKCTRL_GEN(RTC_GCLK_ID) | GCLK_CLKCTRL_CLKEN);
  while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);

  REG_RTC_MODE0_COUNT = 0;                  //reset counter bc a software reset no longer clears the value
  REG_RTC_MODE0_CTRL = (uint16_t) (0x0A80); //select Mode0, 2^10 clock divider for 1Hz, Clear on match
  REG_RTC_MODE0_INTENSET = (uint8_t) 1;     //compare interrupt enabled
  REG_RTC_MODE0_COMP0 = (uint32_t) 60;     //1Hz counter, count to 60s

  NVIC_EnableIRQ(RTC_IRQn);		   //Enable interrupt
}

void RTC_Handler(void)                  // Function to clear flag, turn on green led for debug
  REG_RTC_MODE0_INTFLAG = (uint8_t) 1;  // if flag high and IRQ handler is called, write a 1 to remove flag
  setLedColor(GREEN);
}

void setup()
{
  rtcSetup();                                                 // Initialize RTC
  REG_RTC_MODE0_CTRL |= 2;                                    // engage the RTC enable (which must be low to set settings)

}

void loop()
{
  __WFI();

 delay(500);
 setLedColor(NONE);
 delay(500);
 setLedColor(RED);
 delay(500);
 setLedColor(NONE);
}

Where I expect the light to flash green, then red every time the interrup triggers, instead it is just blinking red all the time with a green led adding a blink every minute. I was under the impression that __WFI() suspended processor operation, effectively pausing the loop, until an interrupt was reached. What is going on here?

For clarification, the code is currently running on a SODAQ ONE v3

Hi Dan,

You forgot to include the following code:

SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

Try adding that to your setup and running it again.

Do note that this will block you from uploading. If you can short the reset pin with the ground with two taps you can forget about this, but to be safe I’d recommend a 5 second delay in setup ( or longer ).

Regards

Dear Thom,

adding the deep sleep bit does make the code run as expected, and low power is the intended goal so that is a relieve. I did find it strange, because the manual for the SAM D21 microchip specifically mentions 3 levels of Idle power modes that the chip enters when WFI is run without the sleep deep bit. The full code fortunately waits 10 seconds to confirm USB connection before going into standby.

thanks for the assistance

Hi Dan,

You are correct, but don’t forget about the arduino millis() function; every ms an interrupt fires that increments a counter.
This also means that the device will wake when using __WFI() and when not using SLEEPDEEP.
There are some ways to get around this, but I’d recommend just working around this.

Regards