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