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

Watchdog reset detected after Buttonless DFU

Background

I intend to use an nrf52 based board in remote inaccessible locations. It is important that I can always recover from a problem. As such, I want to use the watchdog timer to reboot into DFU mode so that if there is ever a problem with the application I can flash a new one remotely. After some searching I found that since the bootloader code does not support this naively, a couple functions in the SDK have to be edited. I didn't want to make changes to the sdk, as that would effect the repeatability of environment setup for my project. Instead, I opted to call the following application at the beginning of my application main.

void boot_bootloader_if_wdt_reset(void)
{
    if (NRF_POWER->RESETREAS & POWER_RESETREAS_DOG_Msk)
    {
        nrf_gpio_pin_dir_set(LED_RED, NRF_GPIO_PIN_DIR_OUTPUT);
        nrf_gpio_pin_clear(LED_RED);
        nrf_delay_ms(5000);
        // Clear DOG flag.
        NRF_POWER->RESETREAS |= POWER_RESETREAS_DOG_Msk;

        // Signal that DFU mode is to be entered to the power management module
        nrf_power_gpregret_set(nrf_power_gpregret_get() | BOOTLOADER_DFU_START);
        nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
    }
    else
    {
        nrf_gpio_pin_dir_set(LED_GREEN, NRF_GPIO_PIN_DIR_OUTPUT);
        nrf_gpio_pin_clear(LED_GREEN);
        nrf_delay_ms(5000);
    }
}

This works as intended. If I stop feeding the watchdog the system reboots, the application checks the reset reason, and boots back to DFU mode if the watchdog fired.

The Problem

After implementing this I can still perform updates using the buttonless dfu service, however after the upgrade, the application always detects a watchdog reset. This boots the board back into DFU mode, where it sits until the inactivity timeout. In an attempt to prevent this, I try to feed the watchdog for 10 minutes worth of ticks before the bootloader is entered, which is 5 times the inactivity timeout, yet the WDT still seems to fire at the end of the process.

Am I feeding the watchdog wrong? Is the bootloader somehow resetting the number of ticks left in the WDT?

/**@brief Function for handling DFU events
*
* @details This function is called when entering buttonless DFU
*
* @param[in] event Buttonless DFU event.
*/
void ble_dfu_buttonless_evt_handler(ble_dfu_buttonless_evt_type_t event)
{
    switch (event)
    {
    case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
        NRF_LOG_INFO("Device is preparing to enter bootloader mode\r\n");
        break;
    case BLE_DFU_EVT_BOOTLOADER_ENTER:
        NRF_LOG_INFO("Device will enter bootloader mode\r\n");
        NRF_LOG_INFO("Feeding WDT for 10 minutes\r\n");
        NRF_WDT->CRV = 19660800; //10 minutes
        NRF_WDT->RR[0] = 0x6E524635UL;
        break;
    case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
        NRF_LOG_ERROR("Device failed to enter bootloader mode\r\n");
        break;
    default:
        NRF_LOG_INFO("Unknown event from ble_dfu.\r\n");
        break;
    }
}

Parents Reply Children
  • Changing my initial CRV value seems to have done the trick, however after re-reading the documentation I have some concerns about when the watchdog config can be reset. In my use-case the system will be always on, and updated via ble dfu. According to this reset chart I will never be able to change the value of the CRV register via an update in my use-case. Is there a recommended way to handle this? The only way I can see to do it based on this chart is to let the watchdog expire, but then I would boot back into DFU mode until the bootloader's inactivity timeout.

Related