This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

WDT interrupt not firing

I am trying to use the watchdog interrupt on an NRF52832 but am unable to get it to fire; the watchdog fires, but as far as I can tell not the preceding interrupt.  Here is some sample code to show the problem:

#include "mbed.h"
#include <SerialWireOutput.h>

// An unsigned int in an uninitialised RAM area
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
__attribute__ ((section(".bss.uninitialised"),zero_init))
unsigned int gRetained;
#elif defined(__GNUC__)
__attribute__ ((section(".uninitialised")))
unsigned int gRetained;
#elif defined(__ICCARM__)
unsigned int gRetained @ ".uninitialised";
#endif

// Hook into the weak function to allow Serial Wire Output (because that's how my board speaks to the world)
namespace mbed {
FileHandle *mbed_target_override_console(int)
{
static SerialWireOutput swo;
return &swo;
}
}

// Watchdog interrupt handler
void WDT_IRQHandler(void)
{
gRetained++;
NRF_WDT->EVENTS_TIMEOUT = 0;
}

// Entry point
int main()
{
printf("\nStarting up and setting the watchdog timer to 5 seconds.\n");
// Setting watchdog to 10 seconds
// Set timeout value timeout [s] = ( CRV + 1 ) / 32768
NRF_WDT->CRV = (5 * 32768) - 1;
NVIC_SetPriority(WDT_IRQn, 7);
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_EnableIRQ(WDT_IRQn);
NRF_WDT->INTENSET = 1;
NRF_WDT->TASKS_START = 1;

printf("Retained RAM variable is %d.\n", gRetained);
if (gRetained > 2) {
printf("Setting retained RAM variable to 0 and resetting...\n");
gRetained = 0;
wait_ms(1000);
NVIC_SystemReset();
}

gRetained++;
printf("Retained RAM variable incremented to %d.\n", gRetained);

if (gRetained < 2) {
printf("Resetting...\n");
wait_ms(1000);
NVIC_SystemReset();
} else {
printf("Now waiting for 10 seconds so that the watchdog goes off, which should increment the retained RAM variable to %d.\n",
gRetained + 1);
wait_ms(10000);
}

printf("Should never get here.\n");
while(1) {}
}

This code should show that the retained RAM variable is retained across a reset (so it really is being retained) and when the watchdog reset occurs, the retained RAM variable should be incremented by the watchdog interrupt.  However the output (compiled under ARMCC) shows that it is not:

Starting up and setting the watchdog timer to 5 seconds.
Retained RAM variable is 0.
Retained RAM variable incremented to 1.
Resetting...

Starting up and setting the watchdog timer to 5 seconds.
Retained RAM variable is 1.
Retained RAM variable incremented to 2.
Now waiting for 10 seconds so that the watchdog goes off, which should increment the retained RAM variable to 3.

Starting up and setting the watchdog timer to 5 seconds.
Retained RAM variable is 2.
...

Can anyone spot what I'm doing wrong?

Rob

Parents Reply Children
  • How interesting.  Unfortunately it's a bit complicated for me to run my board under the debugger right now or I'd try that myself.  Any suggestions as to what I might try to workaround/explore the issue are welcomed.

  • A possibility that exists, but which I've been afraid to mention, is that when the watchdog  interrupt goes off the clock is still 32 kHz and so you actually only get two CPU clock cycles, at 32 kHz, to do anything.  This would hardly be enough to run one assembler instruction before the device was reset, making the watchdog interrupt feature virtually useless.  So I hope I'm wrong :-) 

  • CPU runs on 64MHz, so two 32 KHz clocks means around 3900 cpu cycles which should be more than enough for the saving some state in the watchdog interrupt. I have not seen anything like this before, but the code is so simple to fail. I think we are missing something very obvious. I am home with sick kids so, cannot run the code here. Can you see if configuring the RR registers makes any difference here. I understand that you do not want to kick the watchdog as you want it to expire and reset the chip. But I am just wondering if the functioning of the watchdog depends on configuring the RR register and enabling it. Can you please give it a try..

  • Tried that, no change I'm afraid:

    @time  0: starting up and setting the watchdog timer to 5 seconds.
    @time  0: retained RAM variable is 0.
    @time  0: retained RAM variable incremented to 1.
    @time  0: resetting...

    @time  0: starting up and setting the watchdog timer to 5 seconds.
    @time  0: retained RAM variable is 1.
    @time  0: retained RAM variable incremented to 2.
    @time  0: waiting for 10 seconds while feeding the watchdog every second...
    @time  1: feeding watchdog...
    @time  2: feeding watchdog...
    @time  3: feeding watchdog...
    @time  4: feeding watchdog...
    @time  5: feeding watchdog...
    @time  6: feeding watchdog...
    @time  7: feeding watchdog...
    @time  8: feeding watchdog...
    @time  9: feeding watchdog...
    @time 10: feeding watchdog...
    @time 10: no longer feeding the watchdog; it should go off and the interrupt should increment the retained RAM variable to 3.

    @time  0: starting up and setting the watchdog timer to 5 seconds.
    @time  0: retained RAM variable is 2.

    Any other things I can try?  FYI, I also tried changing the wait_ms() call while we're waiting for the watchdog to go off into a busy-wait (calling nop), just to make sure that the processor was not sleeping (and hence definitely running off HFCLK), and that made no difference, still the interrupt didn't go off.

  • seems like we forgot to enable the lfclock.

    Can you enable by defining and calling this function in your code. I can see that the WDT interrupt is being called after this.

    void lfclk_start()
    {
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
        __DSB();     //<-- This will wait until write buffers are emptied.
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0){  }
    }
    
    call this in main before initializing the WDT registers

Related