- Sun Mar 15, 2020 2:29 pm
#213296
Hi there,
I've been meaning to look into the SparkFun Artemis' Watchdog Timer (WDT) functionality for some time now, so I decided to spend the afternoon diving into what's actually involved. The am_hal_wdt.h, am_hal_wdt.c files from the AmbiqSuite SDK were very useful in getting started, as was the watchdog.c example that's provided. I didn't find it to be overly complicated, though there were still a few roadblocks along the way.
The code I've included below is based on the watchdog.c example and demonstrates some of the basic functionality of the Artemis' WDT.
While learning more about the Artemis' WDT, some of the things of note I noted were:
Keen to hear if anyone else has been working with the Artemis' WDT! I'd really like to get it working with the low power examples that Nathan wrote, but that's a challenge for another day.
Cheers,
Adam
I've been meaning to look into the SparkFun Artemis' Watchdog Timer (WDT) functionality for some time now, so I decided to spend the afternoon diving into what's actually involved. The am_hal_wdt.h, am_hal_wdt.c files from the AmbiqSuite SDK were very useful in getting started, as was the watchdog.c example that's provided. I didn't find it to be overly complicated, though there were still a few roadblocks along the way.
The code I've included below is based on the watchdog.c example and demonstrates some of the basic functionality of the Artemis' WDT.
While learning more about the Artemis' WDT, some of the things of note I noted were:
- The WDT runs off the Low Frequency RC Oscillator (LFRC) at a default value of 128 Hz, which provides a maximum interrupt and reset timeout of 2 seconds. However, the LFRC frequency can be decreased to 16 Hz (max timeout = ~16 s), 1 Hz (max timeout = 255 s) or 1/16 Hz (max timeout = 4080 s).
- Similar to the Early Warning interrupt flag of the SAMD21 Watchdog Timer, you can program the Artemis' WDT interrupt counter and reset counters independently to achieve different timeout periods. This is demonstrated in the code below (i.e. interrupt timeout occurs after 5 seconds and reset timeout occurs after 10 seconds).
- The am_hal_wdt_config_t Watchdog timer configuration structure is where the WDT is configured. I'm not entirely sure why Ambiq indicates that the interrupt and reset counters (ui16InterruptCount & ui16ResetCount) are 16-bit unsigned integers, when they are in fact both 8-bit registers (INTVAL & RESVAL). When calculating your timeout periods, ensure that your "ticks" don't exceed 255.
Code: Select all
// Global variables
volatile uint8_t watchdogCounter = 0; // Watchdog interrupt counter
uint32_t resetStatus = 0; // Reset status register
// Watchdog timer configuration structure.
am_hal_wdt_config_t g_sWatchdogConfig = {
// Configuration values for generated watchdog timer event.
.ui32Config = AM_HAL_WDT_LFRC_CLK_16HZ | AM_HAL_WDT_ENABLE_RESET | AM_HAL_WDT_ENABLE_INTERRUPT,
// Number of watchdog timer ticks allowed before a watchdog interrupt event is generated.
.ui16InterruptCount = 80, // Set WDT interrupt timeout for 10 seconds (80 / 16 = 5).
// Number of watchdog timer ticks allowed before the watchdog will issue a system reset.
.ui16ResetCount = 240 // Set WDT reset timeout for 15 seconds (240 / 16 = 15).
};
void setup(void) {
Serial.begin(115200);
//while (!Serial);
delay(1000);
Serial.println("Artemis Watchdog Example");
Serial.print("Interrupt Count = "); Serial.print(g_sWatchdogConfig.ui16InterruptCount ); Serial.println(" ticks");
Serial.print("Reset Count = "); Serial.print(g_sWatchdogConfig.ui16ResetCount); Serial.println(" ticks");
// (Note: See am_hal_reset.h for RESET status structure)
am_hal_reset_status_t sStatus;
// Print out reset status register.
// (Note: Watch Dog Timer reset = 0x40)
am_hal_reset_status_get(&sStatus);
resetStatus = sStatus.eStatus;
char rStatus[3];
sprintf(rStatus, "Reset Status Register = 0x%x", resetStatus);
Serial.println(rStatus);
// Set the clock frequency.
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
// Set the default cache configuration
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
am_hal_cachectrl_enable();
// Configure the board for low power operation.
am_bsp_low_power_init();
// Clear reset status register for next time we reset.
am_hal_reset_control(AM_HAL_RESET_CONTROL_STATUSCLEAR, 0);
// LFRC must be turned on for this example as the watchdog only runs off of the LFRC.
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_LFRC_START, 0);
// Configure the watchdog.
am_hal_wdt_init(&g_sWatchdogConfig);
// Enable the interrupt for the watchdog in the NVIC.
NVIC_EnableIRQ(WDT_IRQn);
am_hal_interrupt_master_enable();
// Enable the watchdog.
am_hal_wdt_start();
}
void loop(void) {
// Disable interrupts.
am_hal_interrupt_master_disable();
// Turn OFF the indicator LED.
digitalWrite(LED_BUILTIN, LOW);
// Go to deep sleep.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
// An interrupt woke us up so now enable them and take it.
am_hal_interrupt_master_enable();
// Turn ON the indicator LED.
digitalWrite(LED_BUILTIN, HIGH);
Serial.println(watchdogCounter);
delay(10);
}
// Interrupt handler for the watchdog.
extern "C" void am_watchdog_isr(void) {
// Clear the watchdog interrupt.
am_hal_wdt_int_clear();
// Catch the first four watchdog interrupts, but let the fifth through untouched.
if ( watchdogCounter < 4 ) {
// Restart the watchdog.
am_hal_wdt_restart(); // "Pet" the dog.
}
else {
digitalWrite(LED_BUILTIN, HIGH); // Indicator that a reset will occur.
while(1);
}
// Increment the number of watchdog interrupts.
watchdogCounter++;
}
Keen to hear if anyone else has been working with the Artemis' WDT! I'd really like to get it working with the low power examples that Nathan wrote, but that's a challenge for another day.
Cheers,
Adam