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

Entering DFU via GPREGET, secure bootloader serial example not feeding WDT in SDKv15

Hello!

I have a custom nRF52832 board with an FTDI usb/serial part running my app successfully.

I generally program the board with a JLINK and SWD, but I am working to add DFU over usb/serial using the secure bootloader serial example.

I can set GPREGET in my app and soft reset to enter DFU in the bootloader.

I am successfully able to use nrfutil to perform a DFU of my application over serial. Also, if I set GPREGET in my app and soft reset to enter the DFU, but do not initiate the DFU update using nrfutil, eventually, the bootloader times out for inactivity after 10 seconds or so and resets back into my application.

So far so good!

However, when I enable a WDT in my app, the trouble starts.

1. If I make my WDT very long (say 20 seconds), when soft resetting into the bootloader, the ~10s inactivity timer no longer works. If I simply disable the WDT, the ~10s inactivity timer works again. If I wait out the 20 second WDT timer when in the bootloader, the WDT does its thing and resets back to my app.

2. If I make my WDT short (say 4 seconds) while leaving the inactivity timer at ~10s, the WDT is clearly not being fed by the bootloader because a soft reset back to my app happens after 4 seconds.

3. If I leave my WDT short (say 4 seconds), and I add an nrf_delay_ms of 2 seconds at the start of the bootloader, followed by manually feeding the WDT with a nrf_wdt_reload_request_set(NRF_WDT_RR0), I can see that the feeding works, as the bootloader soft resets back to my app after 6 seconds. If I leave the nrf_delay_ms of 2 seconds without the manual feeding, the bootloader soft resets back to the app after 4 seconds.

So my questions are:

1. Why does the Nordic code in the SDKv15 secure bootloader not feed my WDT? Inspecting the code, it seems like it should be feeding the WDT in both the event scheduling loop and possibly by an app timer. I can't seem to get the bootloader code to feed my WDT either "out of the box" or by hacking in an application timer.

2. Why when I enable the WDT (for example 20 seconds), does my 10s inactivity timer stop working? The inactivity timer appears to just be a simple one shot app timer performing a system reset. I don't understand how the presence of the WDT would interfere with the 10s inactivity timer.

Thanks!

Jeremy

Parents
  • Hi Jeremy, 

     

    Could you clarify the inactivity timeout is 10 seconds ? By default our inactivity timeout is 120 seconds: NRF_BL_DFU_INACTIVITY_TIMEOUT_MS = 120000

    We do have a 10 second timeout but it's the timeout after you update the softdevice and waiting for the application to be updated for example. (NRF_BL_DFU_CONTINUATION_TIMEOUT_MS)

    Could you try to test by simply starting the WDT in the bootloader and see if there is any difference ? 

  • Yes, I can confirm that I mean that I changed NRF_BL_INACTIVITY_TIMEOUT_MS to be 10s (ie 10000).  When I do enable the WDT in my app, I am able to see that inactivity timeout taking effect (and changes to it taking effect).

    Enabling the WDT in my app, I can feed it in my app, but I can’t get the boot loader to feed it, and it seems to cause the inactivity timer to no longer work. 

    I will try starting the WDT in the bootloader as a test as you suggest.

  • Ok, I added the following lines to the top of the secure bootloader main.c:

    void wdt_event_handler(void) {
        NVIC_SystemReset();    
    }
    
    int main(void) {
        uint32_t err_code;
        nrf_drv_wdt_config_t config = {                                           \
            .behaviour          = (nrf_wdt_behaviour_t)1, \
            .reload_value       = 10000,                   \
            .interrupt_priority = 7,                   \
        };
        err_code = nrf_drv_wdt_init(&config, wdt_event_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_wdt_channel_alloc(&m_channel_id);
        APP_ERROR_CHECK(err_code);
        nrf_drv_wdt_enable(); 
    
        // Protect MBR and bootloader code from being overwritten.
        uint32_t 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);
        ...

    I also enable the WDT in the config, added nrfx_wdt.c to the Makefile and had to comment out WDT_IRQHandler from nrf_bootloader_wdt.c which conflicts with the one in nrfx_wdt.c.

    For this test, I removed all WDT code from my application.

    When I run enter the bootloader, the WDT will fire after 10s and bring me back from the bootloader to my application (via a soft reset). In other words, the WDT is not being "fed" or reset. No matter what I set the NRF_BL_INACTIVITY_TIMEOUT_MS to, it does not fire (i.e. 5s, 2s, etc) when the WDT is enabled.

    If I remove this WDT code from the top of the secure boot loader example's main.c, then the NRF_BL_INACTIVITY_TIMEOUT_MS works. I can set it to 5s, 2s (i.e. 5000ms or 2000ms) and it correctly brings me back from the bootloader to my application after the specified idle period.

    To be clear, I would expect with this added WDT code, and the NRF_BL_INACTIVITY_TIMEOUT_MS set to 5s, that after 5s of idle, it would reset back to my application. I would further expect if I set the WDT to 2s (i.e. 2000ms) with the NRF_BL_INACTIVITY_TIMEOUT_MS set to 10s, that nothing would happen at 2s (because the WDT should be being fed by the code in nrf_bootloader_wdt.c).

    Thoughts?

  • A little bit more information: I built the debug version of the bootloader, and configured it to log to SEGGER_RTT over SWD/JLINK.

    Here we can see that the nrf_bootloader_wdt detected that the WDT was enabled, and notice it says that it is starting a timer to feed the WDT and it sits idle at the log entry "<debug> app: Enter main loop".

    However at 10s after entering the bootloader, it is rebooted, and we can see the log entry "<info> app: Inside main". So the WDT is actually NOT being fed.

    I suspect that what is happening is that the event loop / app_scheduler is not working for some reason when the WDT is enabled, and neither the app timer for feeding the WDT nor the app timer for NRF_BL_INACTIVITY_TIMEOUT_MS are working. The puzzling thing is this is only when the WDT is enabled. Otherwise, things work.

    <info> app: Inside main
    <debug> app: In nrf_bootloader_init
    <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter nrf_bootloader_fw_activate
    <info> app: No firmware to activate.
    <debug> app: Enter nrf_dfu_app_is_valid
    <debug> app: Return true. App was valid
    <debug> app: DFU mode requested via GPREGRET.
    <info> nrf_bootloader_wdt: WDT enabled CRV:10240 ms
    <info> nrf_bootloader_wdt: Starting a timer (7680 ms) for feeding watchdog.
    <info> app_timer: RTC: initialized.
    <debug> app: in weak nrf_dfu_init_user
    <info> app: Entering DFU mode.
    <debug> app: Initializing transports (found: 1)
    <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter main loop
    <info> app: Inside main
    <debug> app: In nrf_bootloader_init
    <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter nrf_bootloader_fw_activate
    <info> app: No firmware to activate.
    <debug> app: Enter nrf_dfu_app_is_valid
    <debug> app: Return true. App was valid
    <warning> nrf_dfu_settings: No additional data erased
    <debug> app: Running nrf_bootloader_app_start with address: 0x00001000
    <debug> app: Disabling interrupts. NVIC->ICER[0]: 0x0
    <debug> app: running irq table set
    <debug> app: After running irq table set
    

    Here is what the log looks like if I disable the WDT, and the NRF_BL_INACTIVITY_TIMEOUT_MS works:

    <info> app: Inside main
    <debug> app: In nrf_bootloader_init
    <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter nrf_bootloader_fw_activate
    <info> app: No firmware to activate.
    <debug> app: Enter nrf_dfu_app_is_valid
    <debug> app: Return true. App was valid
    <debug> app: DFU mode requested via GPREGRET.
    <info> nrf_bootloader_wdt: WDT is not enabled
    <debug> app: scheduler init
    <debug> app: in weak nrf_dfu_init_user
    <info> app_timer: RTC: initialized.
    <info> app: Entering DFU mode.
    <debug> app: Initializing transports (found: 1)
    <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter main loop
    <debug> app: wait_for_event
    <debug> app: wait_for_event
    <info> app: Inactivity timeout.
    <debug> app: Resetting bootloader.
    <info> app: Inside main
    <debug> app: In nrf_bootloader_init
    <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    <debug> app: Enter nrf_bootloader_fw_activate
    <info> app: No firmware to activate.
    <debug> app: Enter nrf_dfu_app_is_valid
    <debug> app: Return true. App was valid
    <warning> nrf_dfu_settings: No additional data erased
    <debug> app: Running nrf_bootloader_app_start with address: 0x00001000
    <debug> app: Disabling interrupts. NVIC->ICER[0]: 0x0
    <debug> app: running irq table set
    <debug> app: After running irq table set
    

  • So I have things working, but basically, as above, if I have WDT enabled in my app, the app timers in the bootloader library component do not work at all for me (neither the timer to feed the WDT nor the inactivity timeout).

    So instead, I am using the nrfx_timer library myself and handling the feeding of the WDT and resetting for inactivity in the main.c of the secure bootloader.

    So in my modified main.c of the secure bootloader example, I have code like the following:

    ...
    #include "nrf_drv_timer.h"
    #include "nrf_wdt.h"
    
    const nrf_drv_timer_t ACTIVITY_TIMER = NRF_DRV_TIMER_INSTANCE(0);
    
    #define COUNTDOWN_INIT 30
    
    static int countdown = COUNTDOWN_INIT;
    
    void feed_wdt() 
    {
        if (nrf_wdt_started())
        {
            for (nrf_wdt_rr_register_t i = NRF_WDT_RR0; i < NRF_WDT_RR7; i++)
            {
                if (nrf_wdt_reload_request_is_enabled(i))
                {
                    nrf_wdt_reload_request_set(i);
                }
            }
        }        
    }
    
    static void dfu_observer(nrf_dfu_evt_type_t evt_type)
    {
        switch (evt_type)
        {
            case NRF_DFU_EVT_DFU_COMPLETED:
            case NRF_DFU_EVT_DFU_ABORTED:
                nrf_drv_timer_disable(&ACTIVITY_TIMER);
                break;
            case NRF_DFU_EVT_DFU_STARTED:
            case NRF_DFU_EVT_OBJECT_RECEIVED:
                countdown = COUNTDOWN_INIT;
                feed_wdt();
                break;
            default:
                break;
        }
    }
    
    void activity_timer_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
        switch (event_type)
        {
            case NRF_TIMER_EVENT_COMPARE0:
                countdown--;
                if( countdown < 0) {
                    nrf_drv_timer_disable(&ACTIVITY_TIMER);
                    NVIC_SystemReset();    
                } else {
                    feed_wdt();
                }
                break;
    
            default:
                //Do nothing.
                break;
        }
    }
    
    
    int main(void) {
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        uint32_t err_code = nrf_drv_timer_init(&ACTIVITY_TIMER, &timer_cfg, activity_timer_event_handler);
        APP_ERROR_CHECK(err_code);
        nrf_drv_timer_extended_compare(
             &ACTIVITY_TIMER, NRF_TIMER_CC_CHANNEL0, nrf_drv_timer_ms_to_ticks(&ACTIVITY_TIMER, 500), NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
        nrf_drv_timer_enable(&ACTIVITY_TIMER);
    
        // Protect MBR and bootloader code from being overwritten.
        uint32_t ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);
        APP_ERROR_CHECK(ret_val);
        ...
    }

Reply
  • So I have things working, but basically, as above, if I have WDT enabled in my app, the app timers in the bootloader library component do not work at all for me (neither the timer to feed the WDT nor the inactivity timeout).

    So instead, I am using the nrfx_timer library myself and handling the feeding of the WDT and resetting for inactivity in the main.c of the secure bootloader.

    So in my modified main.c of the secure bootloader example, I have code like the following:

    ...
    #include "nrf_drv_timer.h"
    #include "nrf_wdt.h"
    
    const nrf_drv_timer_t ACTIVITY_TIMER = NRF_DRV_TIMER_INSTANCE(0);
    
    #define COUNTDOWN_INIT 30
    
    static int countdown = COUNTDOWN_INIT;
    
    void feed_wdt() 
    {
        if (nrf_wdt_started())
        {
            for (nrf_wdt_rr_register_t i = NRF_WDT_RR0; i < NRF_WDT_RR7; i++)
            {
                if (nrf_wdt_reload_request_is_enabled(i))
                {
                    nrf_wdt_reload_request_set(i);
                }
            }
        }        
    }
    
    static void dfu_observer(nrf_dfu_evt_type_t evt_type)
    {
        switch (evt_type)
        {
            case NRF_DFU_EVT_DFU_COMPLETED:
            case NRF_DFU_EVT_DFU_ABORTED:
                nrf_drv_timer_disable(&ACTIVITY_TIMER);
                break;
            case NRF_DFU_EVT_DFU_STARTED:
            case NRF_DFU_EVT_OBJECT_RECEIVED:
                countdown = COUNTDOWN_INIT;
                feed_wdt();
                break;
            default:
                break;
        }
    }
    
    void activity_timer_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
        switch (event_type)
        {
            case NRF_TIMER_EVENT_COMPARE0:
                countdown--;
                if( countdown < 0) {
                    nrf_drv_timer_disable(&ACTIVITY_TIMER);
                    NVIC_SystemReset();    
                } else {
                    feed_wdt();
                }
                break;
    
            default:
                //Do nothing.
                break;
        }
    }
    
    
    int main(void) {
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        uint32_t err_code = nrf_drv_timer_init(&ACTIVITY_TIMER, &timer_cfg, activity_timer_event_handler);
        APP_ERROR_CHECK(err_code);
        nrf_drv_timer_extended_compare(
             &ACTIVITY_TIMER, NRF_TIMER_CC_CHANNEL0, nrf_drv_timer_ms_to_ticks(&ACTIVITY_TIMER, 500), NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
        nrf_drv_timer_enable(&ACTIVITY_TIMER);
    
        // Protect MBR and bootloader code from being overwritten.
        uint32_t ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);
        APP_ERROR_CHECK(ret_val);
        ...
    }

Children
  • Strange that app_timerv2 didn't work for you. 

     

    Attached is the nrf_bootloader.c file I modified to start a WDT that timeout in 7 seconds and then change the nrf_bootloader_dfu_inactivity_timer_restart() to blink an LED after 10 seconds, I didn't see the WDT triggered any reset. ( I commented out the feeding in the main loop). 

     

    /**
     * Copyright (c) 2016 - 2018, 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.
     * 
     */
    #include "nrf_bootloader.h"
    #include "nrf_bootloader_dfu_timers.h"
    #include "compiler_abstraction.h"
    #include "nrf.h"
    #include "boards.h"
    #include "sdk_config.h"
    #include "nrf_power.h"
    #include "nrf_delay.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_dfu.h"
    #include "nrf_error.h"
    #include "nrf_dfu_settings.h"
    #include "nrf_dfu_utils.h"
    #include "nrf_bootloader_wdt.h"
    #include "nrf_bootloader_info.h"
    #include "nrf_bootloader_app_start.h"
    #include "nrf_bootloader_fw_activation.h"
    #include "nrf_bootloader_dfu_timers.h"
    #include "app_scheduler.h"
    #include "app_timer.h"
    
    static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
    
    #define SCHED_QUEUE_SIZE      32          /**< Maximum number of events in the scheduler queue. */
    #define SCHED_EVENT_DATA_SIZE MAX(NRF_DFU_SCHED_EVENT_DATA_SIZE, APP_TIMER_SCHED_EVENT_DATA_SIZE) /**< Maximum app_scheduler event size. */
    
    #if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON)    && \
          defined(NRF_BL_DFU_ENTER_METHOD_PINRESET)  && \
          defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET)  && \
          defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS))
        #error Configuration file is missing flags. Update sdk_config.h.
    #endif
    
    STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) || (NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0),
                 "NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 to indicate that it is disabled.");
    
    #if defined(NRF_LOG_BACKEND_FLASH_START_PAGE)
    STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0, 
        "If nrf_log flash backend is used it cannot use space after code because it would collide with settings page.");
    #endif
    
    /**@brief Weak implemenation of nrf_dfu_init
     *
     * @note   This function will be overridden if nrf_dfu.c is
     *         compiled and linked with the project
     */
     #if (__LINT__ != 1)
    __WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)
    {
        NRF_LOG_DEBUG("in weak nrf_dfu_init");
        return NRF_SUCCESS;
    }
    #endif
    
    
    /**@brief Weak implementation of nrf_dfu_init
     *
     * @note    This function must be overridden in application if
     *          user-specific initialization is needed.
     */
    __WEAK uint32_t nrf_dfu_init_user(void)
    {
        NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
        return NRF_SUCCESS;
    }
    
    
    static void bootloader_reset(void)
    {
        NRF_LOG_DEBUG("Resetting bootloader.");
    
        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
    
        NVIC_SystemReset();
    }
    
    
    static void inactivity_timeout(void)
    {
        NRF_LOG_INFO("Inactivity timeout.");
        bootloader_reset();
    }
    
    
    /**@brief Function for handling DFU events.
     */
    static void dfu_observer(nrf_dfu_evt_type_t evt_type)
    {
        switch (evt_type)
        {
            case NRF_DFU_EVT_DFU_STARTED:
            case NRF_DFU_EVT_OBJECT_RECEIVED:
                nrf_bootloader_dfu_inactivity_timer_restart(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS, inactivity_timeout);
                break;
            case NRF_DFU_EVT_DFU_COMPLETED:
            case NRF_DFU_EVT_DFU_ABORTED:
                bootloader_reset();
                break;
            default:
                break;
        }
    
        if (m_user_observer)
        {
            m_user_observer(evt_type);
        }
    }
    
    
    /**@brief Function for initializing the event scheduler.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    
    /**@brief Suspend the CPU until an interrupt occurs.
     */
    static void wait_for_event(void)
    {
    #ifdef BLE_STACK_SUPPORT_REQD
        (void)sd_app_evt_wait();
    #else
        // Wait for an event.
        __WFE();
        // Clear the internal event register.
        __SEV();
        __WFE();
    #endif
    }
    
    
    /**@brief Continually sleep and process tasks whenever woken.
     */
    static void loop_forever(void)
    {
        while (true)
        {
            //feed the watchdog if enabled.
       //     nrf_bootloader_wdt_feed();
    
            app_sched_execute();
    
            if (!NRF_LOG_PROCESS())
            {
    //            wait_for_event();
            }
        }
    }
    
    /**@brief Function for initializing button used to enter DFU mode.
     */
    static void dfu_enter_button_init(void)
    {
        nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN,
                                 BUTTON_PULL,
                                 NRF_GPIO_PIN_SENSE_LOW);
    }
    
    
    static bool crc_on_valid_app_required(void)
    {
        bool ret = true;
        if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET &&
            (nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK))
        {
            nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK);
            ret = false;
        }
        else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 &&
                (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC))
        {
            nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC);
            ret = false;
        }
        else
        {
        }
    
        return ret;
    }
    
    
    /**@brief Function for clearing all DFU enter flags that
     *        preserve state during reset.
     *
     * @details This is used to make sure that each of these flags
     *          is checked only once after reset.
     */
    static void dfu_enter_flags_clear(void)
    {
        if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
           (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
        {
            // Clear RESETPIN flag.
            NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
           (nrf_power_gpregret_get() & BOOTLOADER_DFU_START))
        {
            // Clear DFU mark in GPREGRET register.
            nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START);
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
           (s_dfu_settings.enter_buttonless_dfu == 1))
        {
            // Clear DFU flag in flash settings.
            s_dfu_settings.enter_buttonless_dfu = 0;
            APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
        }
    }
    
    
    /**@brief Function for checking whether to enter DFU mode or not.
     */
    static bool dfu_enter_check(void)
    {
        if (!nrf_dfu_app_is_valid(crc_on_valid_app_required()))
        {
            NRF_LOG_DEBUG("DFU mode because app is not valid.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
           (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0))
        {
            NRF_LOG_DEBUG("DFU mode requested via button.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
           (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
        {
            NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
           (nrf_power_gpregret_get() & BOOTLOADER_DFU_START))
        {
            NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
            return true;
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
           (s_dfu_settings.enter_buttonless_dfu == 1))
        {
            NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
            return true;
        }
    
        return false;
    }
    
    static void LED_1_handler(void)
    {
        nrf_gpio_pin_toggle(20);
    }
    static void LED_2_handler(void)
    {
        nrf_gpio_pin_toggle(19);
    //    wdt_feed();
    }
    
    
    void WatchDogInit(uint8_t time_s)
    {
    	NRF_WDT->CONFIG =  	(WDT_CONFIG_SLEEP_Run << WDT_CONFIG_SLEEP_Pos); 
    								  
    	NRF_WDT->CRV = (32768 * time_s)-1; 	 
    	NRF_WDT->RREN = WDT_RREN_RR0_Msk; 									
    	
                        
        NRF_WDT->INTENSET=WDT_INTENSET_TIMEOUT_Msk;									
    	                 
                                    sd_nvic_ClearPendingIRQ(WDT_IRQn);													
    	sd_nvic_SetPriority				(WDT_IRQn, APP_IRQ_PRIORITY_HIGH);		
    	sd_nvic_EnableIRQ	 (WDT_IRQn);													
    	NRF_WDT->TASKS_START = 1; // Watchdog start
    }
    
    ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
    {
        NRF_LOG_DEBUG("In nrf_bootloader_init");
    
        uint32_t                              ret_val;
        nrf_bootloader_fw_activation_result_t activation_result;
        uint32_t                              initial_timeout;
        bool                                  dfu_enter = false;
    
        m_user_observer = observer;
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTON)
        {
            dfu_enter_button_init();
        }
    
        ret_val = nrf_dfu_settings_init(false);
        if (ret_val != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    
        // Check if an update needs to be activated and activate it.
        activation_result = nrf_bootloader_fw_activate();
    
        switch (activation_result)
        {
            case ACTIVATION_NONE:
                initial_timeout = NRF_BL_DFU_INACTIVITY_TIMEOUT_MS;
                dfu_enter       = dfu_enter_check();
                break;
    
            case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
                initial_timeout = NRF_BL_DFU_CONTINUATION_TIMEOUT_MS;
                dfu_enter       = true;
                break;
    
            case ACTIVATION_SUCCESS:
                bootloader_reset();
                NRF_LOG_ERROR("Should never come here: After bootloader_reset()");
                return NRF_ERROR_INTERNAL; // Should not reach this.
    
            case ACTIVATION_ERROR:
            default:
                return NRF_ERROR_INTERNAL;
        }
    
        if (dfu_enter)
        {   
            
            WatchDogInit(7);
            nrf_bootloader_wdt_init();
           
            scheduler_init();
    
            // Clear all DFU stop flags.
            dfu_enter_flags_clear();
     
    
            // Call user-defined init function if implemented
            ret_val = nrf_dfu_init_user();
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
            nrf_bootloader_dfu_inactivity_timer_restart(10000, LED_1_handler);
            ret_val = nrf_dfu_init(dfu_observer);
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
        
            NRF_LOG_DEBUG("Enter main loop");
            loop_forever(); // This function will never return.
            NRF_LOG_ERROR("Should never come here: After looping forever.");
        }
        else
        {
            // Erase additional data like peer data or advertisement name
            ret_val = nrf_dfu_settings_additional_erase();
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
    
            nrf_bootloader_app_start();
            NRF_LOG_ERROR("Should never come here: After nrf_bootloader_app_start()");
        }
    
        // Should not be reached.
        return NRF_ERROR_INTERNAL;
    }
    

  • Hmm, yeah, not sure what's up. I will try out your changed nrf_bootloader.c on my hardware, with my config, with my version of gcc, etc.

    For now, I'm happy with my solution to use nrf_drv_timer in main.c, as it co-exists side by side with the existing code in the bootloader library (which fails to work for me), so if it ends up being a config issue, or compiler issue, or bug in my custom hardware, it would be easy to remove.

  • I have the same problem: Serial bootloader, and when the watchdog is enabled in my app the timers fail in the same way (it seems like all timers in the bootloader are never triggered) and the WDT is not fed. Unfortunately your workaround doesn't work for me either...

    Did you use the SoftDevice or MBR?

  • Ok sorry my mistake... the workaround works, after setting NRFX_TIMER_DEFAULT_CONFIG_FREQUENCY right...

Related