No wake up on Explorer board

A timer (that works) does not wake the program after __WFI ().

Here is the code:

#define NbSecondes 20;
volatile unsigned int CompteurSecondes = NbSecondes;

unsigned int loop_count = 0;
unsigned int irq_ovf_count = 0;

void setup() {

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_BLUE, HIGH);

InitInterruption();
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // registre de sommeil en mode veille profonde

}

void loop() {
CompteurSecondes–;
if (CompteurSecondes <= 0)
{
digitalWrite(LED_BUILTIN, ! digitalRead (LED_BUILTIN));
delay(3000);
digitalWrite(LED_BUILTIN, ! digitalRead (LED_BUILTIN));
delay (1000);
CompteurSecondes = NbSecondes;
}

//Disable USB
//USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE;
//PM->AHBMASK.reg &= ~PM_AHBMASK_USB;
//PM->APBBMASK.reg &= ~PM_APBBMASK_USB;
__WFI(); // Attente interruption, veille (Wait For Interrupt)

//Enable USB

//PM->APBBMASK.reg |= PM_APBBMASK_USB;
//PM->AHBMASK.reg |= PM_AHBMASK_USB;
//USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE;
digitalWrite(LED_GREEN, ! digitalRead (LED_GREEN)); // A chaque réveil

}

void InitInterruption()
{
// Active l’horloge pour le timer
REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC0_TCC1) ;
while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); // Sync

// Le type cast doit correspondre au timer sélectionné
Tcc* TC = (Tcc*) TCC0; // Structure du timer

TC->CTRLA.reg &= ~TCC_CTRLA_ENABLE; // DĂ©sactive TC
while (TC->SYNCBUSY.bit.ENABLE == 1); // Sync

TC->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV256; // 256 est le plus long ?

TC->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ; // Configuration wave form
while (TC->SYNCBUSY.bit.WAVE == 1); // Sync

TC->PER.reg = 0xFFFF; // Compteur Top utilise registre PER
while (TC->SYNCBUSY.bit.PER == 1); // Sync

TC->CC[0].reg = 0xFFF;
while (TC->SYNCBUSY.bit.CC0 == 1); // Sync

// Interrupts
TC->INTENSET.reg = 0; // DĂ©sactive toutes les interruptions
TC->INTENSET.bit.OVF = 1; // Active overflow
TC->INTENSET.bit.MC0 = 1; // Active compare match to CC0

// Enable InterruptVector
NVIC_EnableIRQ(TCC0_IRQn);

// Enable TC
TC->CTRLA.reg |= TCC_CTRLA_ENABLE ;
while (TC->SYNCBUSY.bit.ENABLE == 1); // Sync

}

void TCC0_Handler() // Redéfinit la fonction
{
Tcc* TC = (Tcc*) TCC0; // Structure du timer
if (TC->INTFLAG.bit.OVF == 1) { // Une overflow déclenche l’interruption
//digitalWrite(LED_RED, ! digitalRead (LED_RED)); // Test
TC->INTFLAG.bit.OVF = 1; // DĂ©sactive les ovf flags
irq_ovf_count++; // Test
}

if (TC->INTFLAG.bit.MC0 == 1) {  // A comparé à CC0 cause l'interruption
  TC->INTFLAG.bit.MC0 = 1;    // DĂ©sactive les ovf flags
}

}

I believe the issue is that one or more of the components are being powered off when the board enters standby mode. This powering off is done via the clock system, where the lack of a clock signal will power down the peripheral.

Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf

For the oscillators there is the RUNSTBY bit in each Oscillator register under SYSCTRL (p. 170)
For the GCLK unit there is the RUNSTBY bit of the GENCTRL register (p.120).
For the TC unit there is the RUNSTDBY bit of the CTRLA register (p.551).

I’m not certain, but I believe that setting the RUNSTBY bit of a dependent peripheral, may also configure the units for which it is dependent on (e.g. setting the TC to run in standby may also configure the GCLK and OSC).

One thing to keep in mind is that each different oscillator has different power requirements. Also, you may want to configure a different GCLK unit (other than 0) to ensure that the other components or peripherals, which are attach to GCLK0, are not also kept awake.

For reference GCLK0 is running at the full 48 Mhz. You can find the details of the initial GCLK configuration in startup.c of the Arduino core files: https://github.com/SodaqMoja/SodaqCore-samd/blob/v1.6.15-sodaq/cores/arduino/startup.c

GCLK3 might be a good option as it runs on the 8Mhz oscillator by default. This snippet will modify the default behaviour of OSC8M and GCLK3 to run in standby (modified from startup.c lines 250-261):

  SYSCTRL->OSC8M.bit.RUNSTDBY = 1;

  GCLK->GENDIV.reg = GCLK_GENDIV_ID(3) ; 

  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(3) | 
                      GCLK_GENCTRL_SRC_OSC8M | 
                      GCLK_GENCTRL_RUNSTDBY |
                      GCLK_GENCTRL_GENEN ;

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

Thank you very much Gabriel, for this quick response. I look at all this.