MartinL:
Here's the complete code that'll force a system reset if the loop() blocks for more than 1 second:
// Set up the WDT to perform a system reset if the loop() blocks for more than 1 second
void setup()
{
// Set up the generic clock (GCLK2) used to clock the watchdog timer at 1.024kHz
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(4) | // Divide the 32.768kHz clock source by divisor 32, where 2^(4 + 1): 32.768kHz/32=1.024kHz
GCLK_GENDIV_ID(2); // Select Generic Clock (GCLK) 2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_DIVSEL | // Set to divide by 2^(GCLK_GENDIV_DIV(4) + 1)
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK2
GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to the ultra low power oscillator (OSCULP32K)
GCLK_GENCTRL_ID(2); // Select GCLK2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK2 to WDT (Watchdog Timer)
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK2 to the WDT
GCLK_CLKCTRL_GEN_GCLK2 | // Select GCLK2
GCLK_CLKCTRL_ID_WDT; // Feed the GCLK2 to the WDT
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CONFIG = WDT_CONFIG_PER_1K; // Set the WDT reset timeout to 1 second
while(WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CTRL = WDT_CTRL_ENABLE; // Enable the WDT in normal mode
while(WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
}
void loop()
{
if (!WDT->STATUS.bit.SYNCBUSY) // Check if the WDT registers are synchronized
{
REG_WDT_CLEAR = WDT_CLEAR_CLEAR_KEY; // Clear the watchdog timer
}
// Application code goes here...
}
Hi Martin,
I wanted to thank you for posting your code for the SAMD21 watchdog timer (WDT). I'm making the switch over from AVR and it was a great help in getting me started on understanding how everything works.
I'm hoping to use the SAMD21's WDT in conjunction with alarm interrupts from an external real-time clock that will wake my Adafruit Feather M0 from deep sleep. I would really like to get the Early Warning interrupt working with the SAMD21 but have been struggling to understand some aspects of programming registers. Section 18.6.2.1 of the manual lists the steps to enable Normal Mode with Early Warning interrupt as:
- Define the required Time-Out Period bits in the Configuration register (CONFIG.PER).
- Define the Early Warning Interrupt Time Offset bits in the Early Warning Interrupt Control register
(EWCTRL. EWOFFSET).
- Set Early Warning Interrupt Enable bit in the Interrupt Enable Set register (INTENSET.EW).
Based on one of your other very helpful post, I was able to find the SAMD21 wdt.h files to look up all the register definitions, but I'm having a bit of trouble putting it all together. It's difficult to know whether I've programmed all the necessary registers to to enable the Early Warning interrupt. There doesn't appear to be very many examples of this functionality being enabled in commonly available libraries, though the Adafruit Sleepydog library does enable the EW interrupt in window mode.
After delving into the Adafruit Sleepydog library, I believe that I'll need to add the following code to what you've provided above:
WDT->EWCTRL.bit.EWOFFSET = 0xA; // Set the Early Warning Interrupt Time Offset to 8 seconds
//REG_WDT_EWCTRL = WDT_EWCTRL_EWOFFSET_8K;
WDT->INTENSET.bit.EW = 1; // Enable the Early Warning interrupt
//REG_WDT_INTENSET = WDT_INTENSET_EW; // Is this the equivalent analog comparator register definition?
// Configure and enable WDT interrupt
NVIC_DisableIRQ(WDT_IRQn);
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0);
NVIC_EnableIRQ(WDT_IRQn);
// Watchdog interrupt service routine (ISR)
void WDT_Handler()
{
WDT->INTFLAG.bit.EW = 1; // Clear the Early Warning interrupt flag
//REG_WDT_INTFLAG = WDT_INTFLAG_EW;
WDT->CLEAR.bit.CLEAR = 0xA5; // Clear the Watchdog Timer and restart time-out period
//REG_WDT_CLEAR = WDT_CLEAR_CLEAR_KEY;
while (WDT->STATUS.bit.SYNCBUSY); // Await synchronization of registers between clock domains
}
I've done some testing with this additional code and everything appears to be working properly. I'm now hoping someone will be able to tell me if I've forgotten or made any mistakes with programming these registers. I'm also not overly worried about performance at this time, and am okay with the synchronization delay in the WDT ISR.
Cheers,
Adam