The watchdog

Another common feature in many microcontrollers is the presence of a watchdog timer. A watchdog ensures that the system is not stuck within an endless loop or any other blocking situation within the code. This is particularly useful in bare-metal applications that rely on an event-driven loop, where calls are required not to block, and to return to the main event loop within the allowed amount of time.

The watchdog must be seen as the very last resort to recover an unresponsive system, by triggering a forced reboot regardless of the current state of the execution in the CPU.

The reference platform provides one independent watchdog timer, with a counter similar to those of the generic timers, with a 12-bit granularity and a prescaler factor. The prescaler of the watchdog, however, is expressed in multiples of 2, and has a range between 4 (represented by the value 0) and 256 (value 6).

The clock source is connected to a lower-speed oscillator, through an independent branch of the clock distribution. For this reason, the clock gating is not involved in the activation of this peripheral.

The watchdog configuration area is mapped within the peripherals address region, and consists of four registers:

  • The key register (offset 0), used to trigger the three operations unlock, start, and reset by writing predefined values in the lowest 16 bits
  • The prescale register (offset 4), to set the prescale factor of the counter
  • The reload register (offset 8), containing the reload value for the counter
  • The status register (offset 12), providing the status flags to synchronize the setup operations

The registers can be referenced using shortcut macros:

#define IWDG_BASE (0x40003000)
#define IWDG_KR (*(volatile uint32_t *)(IWDG_BASE + 0x00))
#define IWDG_PR (*(volatile uint32_t *)(IWDG_BASE + 0x04))
#define IWDG_RLR (*(volatile uint32_t *)(IWDG_BASE + 0x08))
#define IWDG_SR (*(volatile uint32_t *)(IWDG_BASE + 0x0c))

The three possible operations that can be triggered via the key register are as follows:

#define IWDG_KR_RESET     0x0000AAAA
#define IWDG_KR_UNLOCK 0x00005555
#define IWDG_KR_START 0x0000CCCC

Two meaningful status bits are provided in the status, and they must be checked to ensure that the watchdog is not busy before unlocking and setting the value for prescale and reload:

#define IWDG_SR_RVU (1 << 1)
#define IWDG_SR_PVU (1 << 0)

The initialization function to configure and start the watchdog may look like the following:

int iwdt_init(uint32_t interval_ms)
{
uint32_t pre = 0;
uint32_t counter;

In the next line, the input value in milliseconds is scaled to the frequency of the watchdog clock, which is 32 KHz:

    counter = interval_ms << 5;

The minimum prescaler factor is 4, however, so the value should be divided again. We then look for the minimum prescaler value that results in a counter that fits the 12 bits available, by halving the counter value and increasing the prescaler factor until the counter is appropriately scaled:

    counter >>= 2;
while (counter > 0xFFF) {
pre++;
counter >>= 1;
}

The following checks ensure that the interval provided does not result in a zero-counter, or a value that is too large for the available scaling factor:

    if (counter == 0)
counter = 1;
if (pre > 6)
return -1;

The actual initialization of the registers is done, but the device requires us to initiate the write with an unlock operation, and only after checking that the registers are available for writing:

    while(IWDG_SR & IWDG_SR_PR_BUSY);
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_PR = pre;
while (IWDG_SR & IWDG_SR_RLR_BUSY);
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_RLR = counter;

Starting the watchdog simply consists of setting the START command in the key register to initiate the start operation:

    IWDG_KR = IWDG_KR_START;
return 0;
}

Once started, the watchdog cannot be stopped and will run forever, decreasing the counter until it reaches zero, and rebooting the system.

The only way to prevent the system from being rebooted is resetting the timer manually, an operation often referred to as kicking the watchdog. A watchdog driver should export a function that allows the application to reset the counter, for example, at the end of each iteration in the main loop. Here is ours:

void iwdt_reset(void)
{
IWDG_KR = IWDG_KR_RESET;
}

As a simple test for the watchdog driver, a watchdog counter of two seconds can be initialized in main():

void main(void) {
flash_set_waitstates();
clock_config();
button_setup();
iwdt_init(2000);
while(1)
WFI();
}
}

The watchdog is reset upon button press, in the interrupt service routine of the button GPIO:

void isr_exti0(void)
{
EXTI_PR |= (1 << BUTTON_PIN);
iwdt_reset();
}

In this test, the system will reboot if the user button is not pressed for two seconds in a row, so the only way to keep the system running is by repeatedly pressing the button.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.208.117