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

DFU and Watchdog timer (WDT) reset

As many others have found, and answered questions here and here and in other posts, DFU will prematurely exit IF you have enabled WDT in your application, as the current Nordic SDK Buttonless DFU doesn't consider the WDT. I hope that Nordic recognizes this flaw and provide some flexibility in the DFU with WDT in the next SDK release.

We fixed this issue with a hack similar to this post in SDK 12.x.x and 13 and the issue came up again as we switched to SDK14 as there seems to be a new feature to put the processor to sleep in DFU mode in the absence of events, using a call to

sd_app_evt_wait() 

in

static void wait_for_event()
{
    while (true)
    {

        /* if the watchdog is enabled/running then kick it  */
        if ((bool)(NRF_WDT->RUNSTATUS) == true)
        {
          NRF_WDT->RR[0] = WDT_RR_RR_Reload;
        }

        app_sched_execute();
        if (!NRF_LOG_PROCESS())
        {
        #ifdef BLE_STACK_SUPPORT_REQD
            (void)sd_app_evt_wait();
        #else
            __WFE();
        #endif
        }
    }
}

Now, if WDT was not configured to sleep when processor is sleep, this will cause a WDT reset if there are no events for time remaining until WDT times out.

My proposed fix for this was to setup another timer to frequently wake up the processor and kick the watchdog in case there are no DFU events for a long time (i.e. longer than remaining WDT ticks)

add this at the end of timers_init() in nrf_dfu.c

app_timer_create(&nrf_dfu_wdt_kick_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                wdt_kick_timer_handler);

The timeout handler for the timer, which simply kicks the dog:

static void wdt_kick_timer_handler (void * p_context)
{
    /* if the watchdog is enabled/running then kick it  */
    if ((bool)(NRF_WDT->RUNSTATUS) == true)
    {
        NRF_WDT->RR[0] = WDT_RR_RR_Reload;
    }
}

start the timer in nrf_dfu_init()

ret_val = app_timer_start(nrf_dfu_wdt_kick_timer_id,
                          APP_TIMER_TICKS(WDT_KICK_TIMEOUT_MS),
                          NULL);

A completely different approach would be to change the WDT behavior setting to NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT when initing it. This is supposed to pause the WDT if the processor is in sleep or halt mode. I haven't tried this setting, as it has the caveat of forcing this setting to the WDT, e.g. if for some reason no tasks in my application run, then processor will be in sleep mode and WDT will be paused, not causing a reset, which defeats the purpose of WDT

P.S. Although I managed to fix the WDT reset issue by kicking the dog in DFU, DFU sometimes fails prematurely in the middle of package transfer. I haven't figured out the cause to that issue yet.

Any comments, suggestions would be appreciated.

Parents
  • Hi Farhang,

    the use of the WDT is application specific and it is difficult to create a generic solution that fits all, e.g. the number of RR registers enabled and the WDT configuration ( Sleep or Halt). Hence, we have left it to the application developer to feed WDT in the bootloader.

    That said, I agree that we should at a minimum state in the bootloader documentation that if the WDT is enabled by the application, then it must be feed by the bootloader during the DFU process to avoid the device to reset prematurely. I think also we should point out where in the bootloader code it must be feed, e.g. add the following comment in wait_for_event():

    /* 
       WDT: If the Watchdog Timer has been enabled by the application, 
            then the it must be feed here 
    */ 
    

    Your solution looks good and I think that we can suggest it to other users that experience this issue.

    Best regards

    Bjørn

Reply
  • Hi Farhang,

    the use of the WDT is application specific and it is difficult to create a generic solution that fits all, e.g. the number of RR registers enabled and the WDT configuration ( Sleep or Halt). Hence, we have left it to the application developer to feed WDT in the bootloader.

    That said, I agree that we should at a minimum state in the bootloader documentation that if the WDT is enabled by the application, then it must be feed by the bootloader during the DFU process to avoid the device to reset prematurely. I think also we should point out where in the bootloader code it must be feed, e.g. add the following comment in wait_for_event():

    /* 
       WDT: If the Watchdog Timer has been enabled by the application, 
            then the it must be feed here 
    */ 
    

    Your solution looks good and I think that we can suggest it to other users that experience this issue.

    Best regards

    Bjørn

Children
Related