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
  • 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 :-) 

Children
  • 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

  • Hmmm.  I've added that but it makes no difference for me I'm afraid.  I get this output:

        @time  0: starting up and enable LF clock.
        @time  0: 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 enable LF clock.
        @time  0: setting the watchdog timer to 5 seconds.
        @time  0: retained RAM variable is 1.
        @time  0: retained RAM variable incremented to 2.
        @time  0: no longer feeding the watchdog; it should go off and increment the retained RAM variable to 3.
       
        @time  0: starting up and enable LF clock.
        @time  0: setting the watchdog timer to 5 seconds.
        @time  0: retained RAM variable is 2.

        ...

    ...with this code:

    #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.noinit"),zero_init))
    unsigned int gRetained;
    #elif defined(__GNUC__)
    __attribute__ ((section(".noinit")))
    unsigned int gRetained;
    #elif defined(__ICCARM__)
    unsigned int gRetained @ ".noinit";
    #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;
    }

    // Start LF clock, required by watchdog
    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){  }
    }

    // Entry point
    int main()
    {
        wait_ms(1000);

        // Start LF clock
        printf("\n@time %2d: starting up and enable LF clock.\n", (int) time(NULL));
        lfclk_start();
        
        printf("@time %2d: setting the watchdog timer to 5 seconds.\n", (int) time(NULL));
        // Setting watchdog to 5 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("@time %2d: retained RAM variable is %d.\n", (int) time(NULL), gRetained);
        if (gRetained > 2) {
            printf("Setting retained RAM variable to 0 and resetting...\n");
            gRetained = 0;
            wait_ms(1000);
            NVIC_SystemReset();
        }

        gRetained++;
        printf("@time %2d: retained RAM variable incremented to %d.\n", (int) time(NULL), gRetained);

        if (gRetained < 2) {
            printf("@time %2d: resetting...\n", (int) time(NULL));
            wait_ms(1000);
            NVIC_SystemReset();
        } else {
            printf("@time %2d: no longer feeding the watchdog; it should go off and increment the retained RAM variable to %d.\n",
                   (int) time(NULL), gRetained + 1);
            for (unsigned int x = 0; x < 0xFFFFFFFF; x++) {
                 __asm__ __volatile__ ("nop");
            }
        }
     
        printf("@time %2d: Should never get here.\n", (int) time(NULL));
        while(1) {}
    }

  • Rob,

    I made a small change to remove all resets to see if the WDT interrupt is being fired or not. And it seems that it is being fired normally. I think the problem was that the logs of the interrupt will not come out before the reset and also I think something was wrong with my no init configuration. So I used Keil and forced the no init on RAM location. Please see the changed main.c file 

    /**
     * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     *
     * @defgroup blinky_example_main main.c
     * @{
     * @ingroup blinky_example
     * @brief Blinky Example Application main file.
     *
     * This file contains the source code for a sample application to blink LEDs.
     *
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf_delay.h"
    #include "boards.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_Conf.h"
    
    __attribute__((at(0x20009000))) unsigned int gRetained;
    // An unsigned int in an uninitialised RAM area
    #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
    //__attribute__ ((section(".bss.uninitialised"),zero_init))
    
        uint32_t *ptr = &gRetained;
    #elif defined(__GNUC__)
    __attribute__ ((section(".uninitialised")))
    unsigned int gRetained;
    #elif defined(__ICCARM__)
    unsigned int gRetained @ ".uninitialised";
    #endif
    
    
    // Watchdog interrupt handler
    void WDT_IRQHandler(void)
    {
        gRetained++;
        NRF_WDT->EVENTS_TIMEOUT = 0;
        SEGGER_RTT_printf(0, "WDT_IRQHandler incrementing RAM variable to %d.\n", gRetained);
    }
    
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    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){  }
    }
        
    // Entry point
    int main()
    {
    
            log_init();
        SEGGER_RTT_printf(0, "\nStarting up and setting the watchdog timer to 5 seconds.\n");
        // Setting watchdog to 10 seconds
        // Set timeout value timeout [s] = ( CRV + 1 ) / 32768
        lfclk_start();
        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;
    
        SEGGER_RTT_printf(0, "Retained RAM variable is %d.\n", gRetained);
        if (gRetained > 2) {
            SEGGER_RTT_printf(0, "Setting retained RAM variable to 0 and resetting...\n");
            gRetained = 0;
            nrf_delay_ms(1000);
            //NVIC_SystemReset();
        }
    
        gRetained++;
        SEGGER_RTT_printf(0, "Retained RAM variable incremented to %d.\n", gRetained);
    
        if (gRetained < 2) {
            SEGGER_RTT_printf(0, "Resetting...\n");
            nrf_delay_ms(10000);
            //NVIC_SystemReset();
        } else {
            SEGGER_RTT_printf(0, "Now waiting for 10 seconds so that the watchdog goes off, which should increment the retained RAM variable to %d.\n",
            gRetained + 1);
            nrf_delay_ms(10000);
        }
     
        SEGGER_RTT_printf(0, "Should never get here.\n");
        while(1) {}
    }
    
    /**
     *@}
     **/
    

    Then the results got are as expected

    ...

Related