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

Bootloader WDT Issues

Hi all,

I am using a nRF52840 with SDK v16.0 on SES. I am trying to understand the flow of code in the secure Booloader(/SDK_v16\examples\dfu\secure_bootloader\pca10056_s140_ble\ses\)

I have a application with buttonless DFU implemented. Application also has a watchdog timer which will check and reset the device every 120seconds if there is a software fault. An app_timer feeds the device every 100seconds to prevent the reset. I am able to do DFU OTA without any issues on the bootloader hex file generated via the normal unedited secure Bootloader project. In the app, I also have connected an external button to soft reset the device when it is pressed via sd_nvic_SystemReset()

I came to know that Bootloader needs to be also edited to implement WDT. This is where my troubles start. I added the following lines of code to the secure bootloader in the main.c right after the NRF_LOG_INFO("Inside main") and WATCHDOG_TIMER_DELAY_MS is set to 120000 (For 120 second timeout). (I have attached the main.c for reference)

    // WDT Block Begin
    uint64_t ticks = (WATCHDOG_TIMER_DELAY_MS * 32768ULL) / 1000;
    NRFX_ASSERT(ticks <= UINT32_MAX);

    NRF_WDT->CRV = (uint32_t) ticks; // Initial loading of the watchdog timer
    nrf_bootloader_wdt_init();
    // WDT Block End
 
 

Once I compile and generate the hex file and program the device with the new bootloader something weird is happening.

First time when I reset device via the external button, the watchdog timer is resetting the device after exactly 220seconds(100 +120) and only once. After this WDT doesnt trigger and the value is reset by the app_timer and application functions normally. Only when its reset(or power on bootup first time)WDT resets the device and then everything goes back to normal.  This issue is only there when I use the edited bootloader with WDT code, functions fine with the normal bootloader hex file. Hence I suspecting that WDT code in my bootloader is the culprit.

1. Can anyone help in figuring out what seems to the bug which is causing the device to get reset once?

2. Will someone be able to explain the code flow for the bootloader? I mean how does the bootloader transfer the control to app and how does WDT work in between?

Thanking you in advance.

/**
 * Copyright (c) 2016 - 2019, 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 bootloader_secure_ble main.c
 * @{
 * @ingroup dfu_bootloader_api
 * @brief Bootloader project main file for secure DFU.
 *
 */

#include <stdint.h>
#include "boards.h"
#include "nrf_mbr.h"
#include "nrf_bootloader.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_dfu.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "app_error.h"
#include "app_error_weak.h"
#include "nrf_bootloader_info.h"
#include "nrf_delay.h"
// WDT Begin
#include "nrf_bootloader_wdt.h"
#define WATCHDOG_TIMER_DELAY_MS 120000      // Watchdog will reset the device every this delay as long as its not reloaded. In Milliseconds.  
// WDT End

static void on_error(void)
{
    NRF_LOG_FINAL_FLUSH();

#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
    // To allow the buffer to be flushed by the host.
    nrf_delay_ms(100);
#endif
#ifdef NRF_DFU_DEBUG_VERSION
    NRF_BREAKPOINT_COND;
#endif
    NVIC_SystemReset();
}


void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
{
    NRF_LOG_ERROR("%s:%d", p_file_name, line_num);
    on_error();
}


void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
    NRF_LOG_ERROR("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id, pc, info);
    on_error();
}


void app_error_handler_bare(uint32_t error_code)
{
    NRF_LOG_ERROR("Received an error: 0x%08x!", error_code);
    on_error();
}

/**
 * @brief Function notifies certain events in DFU process.
 */
static void dfu_observer(nrf_dfu_evt_type_t evt_type)
{
    switch (evt_type)
    {
        case NRF_DFU_EVT_DFU_FAILED:
        case NRF_DFU_EVT_DFU_ABORTED:
        case NRF_DFU_EVT_DFU_INITIALIZED:
            bsp_board_init(BSP_INIT_LEDS);
            bsp_board_led_on(BSP_BOARD_LED_0);
            bsp_board_led_on(BSP_BOARD_LED_1);
            bsp_board_led_off(BSP_BOARD_LED_2);
            break;
        case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
            bsp_board_led_off(BSP_BOARD_LED_1);
            bsp_board_led_on(BSP_BOARD_LED_2);
            break;
        case NRF_DFU_EVT_DFU_STARTED:
            break;
        default:
            break;
    }
}


/**@brief Function for application main entry. */
int main(void)
{
    uint32_t ret_val;

    // Must happen before flash protection is applied, since it edits a protected page.
    nrf_bootloader_mbr_addrs_populate();

    // Protect MBR and bootloader code from being overwritten.
    ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);
    APP_ERROR_CHECK(ret_val);
    ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE, false);
    APP_ERROR_CHECK(ret_val);

    (void) NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("Inside main");

    // WDT Block Begin
    uint64_t ticks = (WATCHDOG_TIMER_DELAY_MS * 32768ULL) / 1000;
    NRFX_ASSERT(ticks <= UINT32_MAX);

    //nrf_wdt_reload_value_set((uint32_t) ticks);
    NRF_WDT->CRV = (uint32_t) ticks; // Initial loading of the watchdog timer
    nrf_bootloader_wdt_init();
    // WDT Block End
 

    ret_val = nrf_bootloader_init(dfu_observer);
    APP_ERROR_CHECK(ret_val);

    NRF_LOG_FLUSH();

    NRF_LOG_ERROR("After main, should never be reached.");
    NRF_LOG_FLUSH();

    APP_ERROR_CHECK_BOOL(false);
}

/**
 * @}
 */

  • Hi,

    1. Can anyone help in figuring out what seems to the bug which is causing the device to get reset once?

    The bootloader in SDK 16 automatically feeds of the watchdog timer without any configuration (see Automated feeding of the watchdog). Therefore you do not need to do anything in order to prevent the WDT from resetting the device while in the bootloader and should remove the code you have added for that.

    Regarding it only resetting once, that would be because a WDT reset causes the WDT to be disabled. And the bootloader does not enable the WDT, just continues to feed it if allready enabled. But I do not see why this code should cause the WDT to reset. The code you added just looks useless, but not harmfull (since an enabled WDT cannot be reconfigured, only feed/reloaded or timeout and reset).

    2. Will someone be able to explain the code flow for the bootloader? I mean how does the bootloader transfer the control to app and how does WDT work in between?

    Regarding the WDT, the bootloader just checks the configuration of the WDT peripheral and uses an app_timer to feed it regularly if it is enabled. You can see all the details by looking at the implementation in <SDK>\components\libraries\bootloader\nrf_bootloader_wdt.c.

    Regarding the general flow of the bootloader that is not really related to the WDT. But it goes like this:

    1. At startup, MBR runs and if the bootloader is present, jumps to the bootloader.
    2. The bootloader checks if it should enter DFU mode by checking if any of the DFU triggers are present, of if there is no valid application.
    3. If not entering DFU mode, it starts the application. In short, it disables all interrupts, configures the MBR to forward interrupts to the application and jumps to the application. You can refer to nrf_bootloader_app_start() in <SDK>\components\libraries\bootloader\nrf_bootloader_app_start.c and the function it calls to see the details of how it is done. 
  • Thanks a lot for the clarification regarding SDK 16 and WDT. I will remove the extra code from the bootloader main.c section
    Question of why the reset is happening is still strange.

    How does the bootloader initially know if WDT is enabled in the application when it runs for the first time? Because I am configuring the WDT in the application. Control flow as you mentioned is power-on--> Bootloader --> application.

    One more query, in the SDK 16 while OTA is happening what happens to the WDT? Does it keep feeding the WDT to prevent a reset or is it paused?

  • Hi,

    dev_000 said:
    How does the bootloader initially know if WDT is enabled in the application when it runs for the first time? Because I am configuring the WDT in the application. Control flow as you mentioned is power-on--> Bootloader --> application.

    If the application enabled the WDT it is still running after resetting into the bootloader, since the WDT is not reset by a soft reset (see reset behavior). Then the bootloader simply checks the WDT registers to see if it is enabled and what the reload counter value is. If it is enabled, the bootloader will start feeding it regularly at an interval determined by the reload counter value. You can see this from the implementation of nrf_bootloader_wdt_init().

    dev_000 said:
    One more query, in the SDK 16 while OTA is happening what happens to the WDT? Does it keep feeding the WDT to prevent a reset or is it paused?

    It is not possible to pause the WDT once it has been started. The bootloader will continue to feed it (which is basically the only thing the bootloader does with the WDT), since the bootloader itself never starts it.

  • Thanks. Your answer makes sense when WDT is enabled in application and then resetting into bootloader. My query was about the edge case when lets a power on happens, bootloader wouldnt know that WDT is enabled(as its not). It will come to know only from the second cycle. Am I correct in that assumption?

  • Yes. The bootloader does not start the WDT, so the WDT will not be running when the bootloader runs immediately after a power-on reset.

Related