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;
}
}