This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

when set NRF_LOG_DEFAULT_LEVEL as 1 in sdk_config.h, OTA failed

I am using nRF52840 development software based on ble_app_uart_c, and I found that when I set NRF_LOG_DEFAULT_LEVEL as 1, if I download the software by Segger, the device worked well.  If I updated the software by OTA, the devcie cannot start.  If I set NRF_LOG_DEFAULT_LEVEL  as 3, updating the software by OTA, the device worked well.

Parents
  • When NRF_LOG_DEFAULT_LEVEL set as 1, the compiled app uploaded to the device by OTA, the device didn't get start. I don't know how to catch the logs.

  • Hi,

    The example should print out the logs over RTT. Use J-link RTT viewer to view the logs.

    regards

    Jared 

  • Hi,

    The error logs show following:

    <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Discovery complete.
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:09 2034
    00>
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:09 2034
    00>
    00>
    00> <info> app: Disconnected.
    00>
    00> <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Discovery complete.
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:29 2034
    00>
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:29 2034
    00>
    00>
    00> <info> app: Disconnected.
    00>
    00> <info> app: Disconnected.
    00>
    00> <info> app: ATT MTU exchange completed.
    00>
    00> <info> app: Discovery complete.
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:16 2034
    00>
    00> <info> app: Inside main
    00>
    00> <debug> app: In nrf_bootloader_init
    00>
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00>
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00>
    00> <debug> nrf_dfu_settings: Using settings page.
    00>
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00>
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00>
    00> <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    00>
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00>
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00>
    00> <debug> app: Valid App
    00>
    00> <debug> app: Enter nrf_dfu_app_continue
    00>
    00> <error> app: Received a fault! id: 0x00004002, pc: 0x00000000, info: 0x2003FF70
    00>
    00> <info> app: Time queried. Returned: Sun Mar 05 00:07:16 2034
    00>

  • Hi,

    It seems like you're hitting an error inside app_activate(). 

    Can you use the bootloader_debug project instead? It has the hardfault library already enabled, which means that the log will be more verbose, which helps us pinpoint where the issue is.  Can you use that project and see if the log specifies exactly where it faults?

    regards

    Jared 

  • Hi Cynthia, 

    I'm taking over the case from Jared as it's more of a DFU case  . 

    Could you give me more information about your SDK version ? Also the board/IC version. Are you testing on a DK ? 

    If you try doing DFU with an unmodified bootloader do you see the same issue ? 

    Also could you you explain a little bit about the log, I can find that there are quite a lot of WDT feed before the actual activity in main. Have you made sure the WDT is fed when the bootloader started ? 

    From what I can see in the log, the assert happened inside app_activate()  , most likely inside image_copy() function. 

    I would suggest to use the _debug version of the bootloader and put a breakpoint inside app_activate() and step through the code. 

Reply
  • Hi Cynthia, 

    I'm taking over the case from Jared as it's more of a DFU case  . 

    Could you give me more information about your SDK version ? Also the board/IC version. Are you testing on a DK ? 

    If you try doing DFU with an unmodified bootloader do you see the same issue ? 

    Also could you you explain a little bit about the log, I can find that there are quite a lot of WDT feed before the actual activity in main. Have you made sure the WDT is fed when the bootloader started ? 

    From what I can see in the log, the assert happened inside app_activate()  , most likely inside image_copy() function. 

    I would suggest to use the _debug version of the bootloader and put a breakpoint inside app_activate() and step through the code. 

Children
  • Hi Hung,

    Thanks for your reply.

    1. I'm developing bootloader on  pca10056_s140_ble_debug. I'm using SDK16 + nRF52840. PCA10056+s140. I'm testing  on our borad.

    2. I did DFU with SDK bootloader only changing NRF_DFU_BLE_ADV_NAME, I didn't see the same issue.

    3. There is a extern WDT on our board. Initialy I want to add a app timer to feed the extern WDT and control a green LED and a blue LED to flash in cycle, but it failed. So I open inner wdt , and added code in wdt_feed()  function of nrf_bootloader_wdt.c to feed  extern wdt and control the two LED flash.

    Could you give me any advice about how to add an app timer ?

    Thanks in advance.

  • Hi Cynthia, 

    At point 2, you meant if you test with unmodified bootloader example you don't see the issue and you can complete the DFU update without any issue ? 

    Which modification did you add to the bootloader besides the external WDT handling ? If you remove the external WDT handling would it work ? 

    Regarding the app timer, the bootloader has its own timer library called nrf_bootloader_dfu_timers.c You can find how the mp_wdt_feed and mp_inactivity is defined in the file. You can add your own timer in by modifying m_timers[]. Note that each timer occupy one CC register and with nRF52840 you have max 4 CC registers.

  • OriginBootloader_LOG_LEVE_1-J-Link RTT Viewer_logs.logoriginBootloader-loglevel-1-Log 2022-03-22 14_45_30.txtUSERBootloader_LOG_LEVE_1-J-Link RTT Viewer_logs.loguserbootloader-loglevel-1-Log 2022-03-22 14_48_57.txt

    Hi Hung,

    I added timer in nrf_bootloader_dfu_timers.c, after DFU, the device can't start.  The failed log file show in USERBootloader- . This test's done with my bootloader.  The successful log file show in orginBootloader-. This test's done with sdk bootloader only ADV name is changed.

  • Hi Cynthia, 
    Could you provide us the userbootloader code that we can test here ? 

    Could you please clarify: 

    - If you only change the advertising name (nothing else) the original bootloader works ? 

    - If you add a timer in nrf_bootloader_dfu_timers the bootloader stopped working ? 

    If it's the case please provide the code you added to the nrf_bootloader_dfu_timers ()

    Have you tried to step in the code in image_copy() and checked what's wrong ? 

  • /**
     * 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.
     *
     */
    #include "nrf_bootloader.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 "nrf_dfu_validation.h"
    
    
    #define EXTERN_WATCHDOG_PIN   NRF_GPIO_PIN_MAP(0,29)
    #define BLUE_LED    NRF_GPIO_PIN_MAP(0,9)      //LED_PERSON
    #define GREEN_LED   NRF_GPIO_PIN_MAP(0,10)
    #define USER_TIMER_TIMEOUT_MS   100  //1200
    extern void nrf_user_timer_start(uint32_t timeout_ticks, nrf_bootloader_dfu_timeout_callback_t callback);
    
    void led_extWatchDog_pin_init()
    {
        ret_code_t err_code;
        // Extern WatchDog pin init
    
        nrf_gpio_cfg_output(EXTERN_WATCHDOG_PIN); 
        nrf_gpio_pin_write(EXTERN_WATCHDOG_PIN,0);
    
        // Blue led init
        nrf_gpio_cfg_output(BLUE_LED); 
        nrf_gpio_pin_write(BLUE_LED,0);
     
        // Green led init
        nrf_gpio_cfg_output(GREEN_LED); 
        nrf_gpio_pin_write(GREEN_LED,1);
        
    }
    
    static void user_timer_handler(void)
    {
        static uint8_t counter =0;
    
        nrf_gpio_pin_toggle(EXTERN_WATCHDOG_PIN);
    
        counter++;
        if(counter >= 10)
        {
            nrf_gpio_pin_toggle(BLUE_LED);  
        	nrf_gpio_pin_toggle(GREEN_LED);  
            counter = 0;
        }
    }
    
    
    static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
    static volatile bool m_flash_write_done;
    
    #define SCHED_QUEUE_SIZE      32          /**< Maximum number of events in the scheduler queue. */
    #define SCHED_EVENT_DATA_SIZE NRF_DFU_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)&& \
          defined(NRF_BL_RESET_DELAY_MS)             && \
          defined(NRF_BL_DEBUG_PORT_DISABLE))
        #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 flash_write_callback(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        m_flash_write_done = true;
    }
    
    
    static void do_reset(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
    
        NRF_LOG_FINAL_FLUSH();
    
        nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
    
        NVIC_SystemReset();
    }
    
    
    static void bootloader_reset(bool do_backup)
    {
        NRF_LOG_DEBUG("Resetting bootloader.");
    
        if (do_backup)
        {
            m_flash_write_done = false;
            nrf_dfu_settings_backup(do_reset);
        }
        else
        {
            do_reset(NULL);
        }
    }
    
    
    static void inactivity_timeout(void)
    {
        NRF_LOG_INFO("Inactivity timeout.");
        bootloader_reset(true);
    }
    
    
    /**@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_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
                            inactivity_timeout);
                break;
            case NRF_DFU_EVT_DFU_COMPLETED:
            case NRF_DFU_EVT_DFU_ABORTED:
                bootloader_reset(true);
                break;
            case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
                // Reset the internal state of the DFU settings to the last stored state.
                nrf_dfu_settings_reinit();
                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)
    {
    #if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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_GPREGRET2_MASK) == BOOTLOADER_DFU_GPREGRET2)
                && (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_BIT_MASK))
        {
            nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC);
            ret = false;
        }
        else
        {
        }
    
        return ret;
    }
    
    
    
    static bool boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len, bool do_crc)
    {
        if (!do_crc && (p_validation->type == VALIDATE_CRC))
        {
            return true;
        }
        return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
    }
    
    
    /** @brief Function for checking if the main application is valid.
     *
     * @details     This function checks if there is a valid application
     *              located at Bank 0.
     *
     * @param[in]   do_crc Perform CRC check on application. Only CRC checks
                           can be skipped. For other boot validation types,
                           this parameter is ignored.
     *
     * @retval  true  If a valid application has been detected.
     * @retval  false If there is no valid application.
     */
    static bool app_is_valid(bool do_crc)
    {
        if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)
        {
            NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
            return false;
        }
        else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
            (s_dfu_settings.boot_validation_app.type != VALIDATE_ECDSA_P256_SHA256))
        {
            NRF_LOG_WARNING("Boot validation failed. The boot validation of the app must be a signature check.");
            return false;
        }
        else if (SD_PRESENT && !boot_validate(&s_dfu_settings.boot_validation_softdevice, MBR_SIZE, s_dfu_settings.sd_size, do_crc))
        {
            NRF_LOG_WARNING("Boot validation failed. SoftDevice is present but invalid.");
            return false;
        }
        else if (!boot_validate(&s_dfu_settings.boot_validation_app, nrf_dfu_bank0_start_addr(), s_dfu_settings.bank_0.image_size, do_crc))
        {
            NRF_LOG_WARNING("Boot validation failed. App is invalid.");
            return false;
        }
        // The bootloader itself is not checked, since a self-check of this kind gives little to no benefit
        // compared to the cost incurred on each bootup.
    
        NRF_LOG_DEBUG("App is valid");
        return true;
    }
    
    
    
    /**@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_GPREGRET_MASK) == BOOTLOADER_DFU_GPREGRET)
                && (nrf_power_gpregret_get() & BOOTLOADER_DFU_START_BIT_MASK))
        {
            // 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 (!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;
    }
    
    
    #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
    static void postvalidate(void)
    {
        NRF_LOG_INFO("Postvalidating update after reset.");
        nrf_dfu_validation_init();
    
        if (nrf_dfu_validation_init_cmd_present())
        {
            uint32_t firmware_start_addr;
            uint32_t firmware_size;
    
            // Execute a previously received init packed. Subsequent executes will have no effect.
            if (nrf_dfu_validation_init_cmd_execute(&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
            {
                if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS)
                {
                    if (nrf_dfu_validation_activation_prepare(firmware_start_addr, firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
                    {
                        NRF_LOG_INFO("Postvalidation successful.");
                    }
                }
            }
        }
    
        s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
        UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
    }
    #endif
    
    
    ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
    {
        NRF_LOG_DEBUG("In nrf_bootloader_init");
    
        ret_code_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_DEBUG_PORT_DISABLE)
        {
            nrf_bootloader_debug_port_disable();
        }
    
        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;
        }
    
        #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
        // Postvalidate if DFU has signaled that update is ready.
        if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
        {
            postvalidate();
        }
        #endif
    
        // 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_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
                dfu_enter       = dfu_enter_check();
                break;
    
            case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
                initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
                dfu_enter       = true;
                break;
    
            case ACTIVATION_SUCCESS:
                bootloader_reset(true);
                NRF_LOG_ERROR("Unreachable");
                return NRF_ERROR_INTERNAL; // Should not reach this.
    
            case ACTIVATION_ERROR:
            default:
                return NRF_ERROR_INTERNAL;
        }
    
        if (dfu_enter)
        {
            nrf_bootloader_wdt_init();
            scheduler_init();
            dfu_enter_flags_clear();
    #if 1       // Cynthia added
    
        led_extWatchDog_pin_init();
        nrf_user_timer_start(NRF_BOOTLOADER_MS_TO_TICKS(USER_TIMER_TIMEOUT_MS),user_timer_handler);
    
    #endif
            // 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(initial_timeout, inactivity_timeout);
    
            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("Unreachable");
        }
        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;
            }
    
            m_flash_write_done = false;
            nrf_dfu_settings_backup(flash_write_callback);
            ASSERT(m_flash_write_done);
    
            nrf_bootloader_app_start();
            NRF_LOG_ERROR("Unreachable");
        }
    
        // Should not be reached.
        return NRF_ERROR_INTERNAL;
    }
    
    /**
     * Copyright (c) 2018 - 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.
     *
     */
    #include "nrf_bootloader_dfu_timers.h"
    
    #include <stdint.h>
    #include <stdbool.h>
    #include <nrfx.h>
    #include "nrf_clock.h"
    #include "nrf_rtc.h"
    #include "nrf_delay.h"
    #include "nrf_log.h"
    
    
    #define RTC_PRESCALER       (0)              //!< The value provided to the RTC as the prescaler. 0 corresponds to one tick per clock cycle of the LFCLK (32768 ticks/s).
    #define RTC_WRAP_TICKS      ((1 << 24) - 1)  //!< The largest possible value in the RTC counter register.
    #define MAX_TIMEOUT_TICKS   (RTC_WRAP_TICKS) //!< The longest fire timeout allowed. Longer timeouts are handled by multiple firings.
    
    typedef struct
    {
        nrf_bootloader_dfu_timeout_callback_t callback;         //!< Callback that is called when this timer times out.
        uint32_t                              timeout;          //!< The number of ticks from the next firing until the actual timeout. This value will be different from 0 if the original timeout was longer than MAX_TIMEOUT_TICKS, so multiple firings were needed.
        uint32_t                              repeated_timeout; //!< If different from 0, this timer will be reactivated with this value after timing out.
        uint8_t                               cc_channel;       //!< Which CC register this timer uses.
    } dfu_timer_t;
    
    // Cynthia modified
    dfu_timer_t   m_timers[3] = {{.cc_channel = 0}, {.cc_channel = 1},{.cc_channel = 2}}; //!< The timers used by this module.
    dfu_timer_t * mp_inactivity = &m_timers[0];                         //!< Direct pointer to the inactivity timer, for convenience and readability.
    dfu_timer_t * mp_wdt_feed   = &m_timers[1];                         //!< Direct pointer to the wdt feed timer, for convenience and readability.
    dfu_timer_t * user_led_extWDT_feed = &m_timers[2];        // Direct pointer to the led and ext WDT feed timer.  Cynthia added
    uint32_t      m_counter_loops = 0;                                  //!< The number of times the RTC counter register has overflowed (wrapped around) since the RTC was started.
    
    #if RTC_COUNT > 2
    #define RTC_INSTANCE   2
    #define RTC_STRUCT     NRF_RTC2
    #define RTC_IRQHandler RTC2_IRQHandler
    #define RTC_IRQn       RTC2_IRQn
    #define RTC_CC_COUNT   NRF_RTC_CC_CHANNEL_COUNT(2))
    #elif RTC_COUNT > 1
    #define RTC_INSTANCE   1
    #define RTC_STRUCT     NRF_RTC1
    #define RTC_IRQHandler RTC1_IRQHandler
    #define RTC_IRQn       RTC1_IRQn
    #define RTC_CC_COUNT   NRF_RTC_CC_CHANNEL_COUNT(1))
    #else
    #error Not enough RTC instances.
    #endif
    
    /**@brief Function for initializing the timer if it is not already initialized.
     */
    static void timer_init(void)
    {
        static bool m_timer_initialized;
    
        if (!m_timer_initialized)
        {
            if (!nrf_clock_lf_is_running())
            {
                nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
            }
    
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
            NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
            NRFX_IRQ_ENABLE(RTC_IRQn);
            nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
            nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
            nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);
    
            m_timer_initialized = true;
        }
    }
    
    /**@brief Function for scheduling an RTC compare event.
     *
     * @param[in] cc_channel  Which of the RTC compare registers to use.
     * @param[in] cc_value    The ticks value at which to receive the event.
     */
    static void rtc_update(uint32_t cc_channel, uint32_t cc_value)
    {
        ASSERT(cc_channel < NRF_RTC_CC_CHANNEL_COUNT(RTC_INSTANCE));
    
        nrf_rtc_cc_set(RTC_STRUCT, cc_channel, cc_value);
        nrf_delay_us(31);
        nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(cc_channel));
        nrf_rtc_int_enable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(cc_channel));
    }
    
    
    /**@brief Function for activating a timer, so that it will be fired.
     *
     * This can happen multiple times before the actual timeout happens if the timeout is longer than
     * @ref MAX_TIMEOUT_TICKS.
     *
     * @param[in] p_timer        The timer to activate.
     * @param[in] timeout_ticks  The number of ticks until the timeout.
     *
     * @retval true   If the timer was activated.
     * @retval false  If the timer is already active.
     */
    static void timer_activate(dfu_timer_t * p_timer, uint32_t timeout_ticks)
    {
        NRF_LOG_DEBUG("timer_activate (0x%x)", p_timer);
    
        ASSERT(timeout_ticks <= MAX_TIMEOUT_TICKS);
        ASSERT(timeout_ticks >= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
        uint32_t next_timeout_ticks = MIN(timeout_ticks, MAX_TIMEOUT_TICKS);
        uint32_t cc_value = RTC_WRAP(next_timeout_ticks + nrf_rtc_counter_get(RTC_STRUCT));
        p_timer->timeout  = timeout_ticks - next_timeout_ticks;
    
        if ((p_timer->timeout > 0) && (p_timer->timeout < NRF_BOOTLOADER_MIN_TIMEOUT_TICKS))
        {
            p_timer->timeout += NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
            cc_value         -= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
        }
    
        rtc_update(p_timer->cc_channel, cc_value);
    }
    
    
    /**@brief Function for deactivating a timer, so that it will not fire.
     *
     * @param[in] p_timer  The timer to deactivate.
     *
     * @retval true   If the timer was deactivated.
     * @retval false  If the timer is already inactive.
     */
    static void timer_stop(dfu_timer_t * p_timer)
    {
        NRF_LOG_DEBUG("timer_stop (0x%x)", p_timer);
        nrf_rtc_int_disable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(p_timer->cc_channel));
    }
    
    
    /**@brief Function for firing a timer.
     *
     * This can happen multiple times before the actual timeout happens if the timeout is longer than
     * @ref MAX_TIMEOUT_TICKS.
     * This function reactivates the timer if the timer is repeating, or if the timer has not yet
     * timed out. It then calls the callback if the timer (repeating or not) has timed out.
     *
     * @param[in] p_timer  The timer to fire.
     */
    static void timer_fire(dfu_timer_t * p_timer)
    {
        NRF_LOG_DEBUG("timer_fire (0x%x)", p_timer);
    
        if (p_timer->timeout != 0)
        {
            // The timer has not yet timed out.
            timer_activate(p_timer, p_timer->timeout);
            return;
        }
    
        if (p_timer->repeated_timeout != 0)
        {
            timer_activate(p_timer, p_timer->repeated_timeout);
        }
    
        if (p_timer->callback != NULL)
        {
            p_timer->callback();
        }
    }
    
    
    /**@brief Function for requesting a timeout.
     *
     * The timer will time out @p timeout_ticks ticks from now. When it times out, @p callback
     * will be called, and if @p p_timer->repeated_timeout is not 0, a new timeout will be scheduled.
     *
     * @param[in] p_timer        The timer to start.
     * @param[in] timeout_ticks  The number of ticks until the timeout.
     * @param[in] callback       The callback to call when the timer times out.
     */
    static void timer_start(dfu_timer_t *                         p_timer,
                            uint32_t                              timeout_ticks,
                            nrf_bootloader_dfu_timeout_callback_t callback)
    {
        timer_init(); // Initialize if needed.
        p_timer->callback = callback;
        timer_activate(p_timer, timeout_ticks);
    }
    
    
    /**@brief Interrupt handler for the RTC (Real Time Clock) used for the DFU timers.
     */
    void RTC_IRQHandler(void)
    {
        if (nrf_rtc_event_pending(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW))
        {
            m_counter_loops++;
            nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW);
        }
    
        for (uint32_t channel = 0; channel < 3; channel++)      // Cynthia modified  for (uint32_t channel = 0; channel < 2; channel++)
        {
            if (nrf_rtc_event_pending(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel)))
            {
                nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel));
                timer_stop(&m_timers[channel]);
                timer_fire(&m_timers[channel]);
            }
        }
    }
    
    
    void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t                              timeout_ticks,
                                                     nrf_bootloader_dfu_timeout_callback_t callback)
    {
        timer_stop(mp_inactivity);
        if (timeout_ticks != 0)
        {
            timer_start(mp_inactivity, timeout_ticks, callback);
        }
    }
    
    
    void nrf_bootloader_wdt_feed_timer_start(uint32_t                              timeout_ticks,
                                             nrf_bootloader_dfu_timeout_callback_t callback)
    {
        mp_wdt_feed->repeated_timeout = timeout_ticks;
        timer_start(mp_wdt_feed, timeout_ticks, callback);
    }
    
    void nrf_user_timer_start(uint32_t timeout_ticks, nrf_bootloader_dfu_timeout_callback_t callback)
    {
        user_led_extWDT_feed->repeated_timeout = timeout_ticks;
        timer_start(user_led_extWDT_feed, timeout_ticks, callback);
    }
    
    uint32_t nrf_bootloader_dfu_timer_counter_get(void)
    {
        return nrf_rtc_counter_get(RTC_STRUCT) + (m_counter_loops << 24);
    }
    

    Hi Hung,

    - I changed orginal bootloader's advertising name and NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF_ENABLED's value as 0 , It works .

    -  I added app timer based on original bootloader. I  changed nrf_bootloader.c and nrf_bootloader_dfu_timers.c as shown in attachment. 

    If I remove the external watchdog from the board, I dfu the app with user bootloader,It works. It seems also  have to do something with the external watchdog.

Related