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

BLE DFU WDT SDK15.2 bug?

Hi all

nrf52840 Development board,sdk is nRF5_SDK_15.2.0_9412b96,PC is windows 10 .My testing master device is cell phone(Huawei HTC and so on,android system),and using "nrf toolbox" APP.

I added watchdog  function in my application,and then when I test the ble dfu ,I found that  the watchdog feeding in the bootloader did not happen during app FW activation.

nrf_bootloader_wdt_feed_timer_start(reduced_timeout_ticks, wdt_feed_timer_handler);

wdt_feed_timer_handler is not called any time.Is this an SDK bug?

Thanks,

mijiale

The log as follosw:

Parents
  • Hi ,

    the WDT is started in the nrf_bootloader_init() function if dfu_enter is true. 

    void nrf_bootloader_wdt_init(void)
    {
        static bool initialized = false;
    
        if (initialized)
        {
            return;
        }
    
        if (nrf_wdt_started())
        {
            uint32_t wdt_ticks = nrf_wdt_reload_value_get();
    
            NRF_LOG_INFO("WDT enabled CRV:%d ticks", wdt_ticks);
    
            //wdt_ticks must be reduced to feed the watchdog before the timeout.
            uint32_t reduced_timeout_ticks = MAX((int32_t)wdt_ticks - MAX_FLASH_OP_TIME_TICKS,
                                                 NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
    
            /* initial watchdog feed */
            wdt_feed();
    
            NRF_LOG_INFO("Starting a timer (%d ticks) for feeding watchdog.", reduced_timeout_ticks);
            nrf_bootloader_wdt_feed_timer_start(reduced_timeout_ticks, wdt_feed_timer_handler);
    
            NVIC_EnableIRQ(WDT_IRQn);
        }
        else
        {
            NRF_LOG_INFO("WDT is not enabled");
        }
    
        initialized = true;
    }
    

    The WDT is also started prior to initiating any image_copy operation

    static uint32_t image_copy(uint32_t dst_addr,
                               uint32_t src_addr,
                               uint32_t size,
                               uint32_t progress_update_step)
    {
        if (src_addr == dst_addr)
        {
            NRF_LOG_DEBUG("No copy needed src_addr: 0x%x, dst_addr: 0x%x", src_addr, dst_addr);
            return NRF_SUCCESS;
        }
    
        ASSERT(src_addr >= dst_addr);
        ASSERT(progress_update_step > 0);
        ASSERT((dst_addr % CODE_PAGE_SIZE) == 0);
    
        uint32_t max_safe_progress_upd_step = (src_addr - dst_addr)/CODE_PAGE_SIZE;
        ASSERT(max_safe_progress_upd_step > 0);
    
        uint32_t ret_val = NRF_SUCCESS;
        uint32_t pages_left = CEIL_DIV(size, CODE_PAGE_SIZE);
    
        //Firmware copying is time consuming operation thus watchdog handling is started
        nrf_bootloader_wdt_init();
    
        progress_update_step = MIN(progress_update_step, max_safe_progress_upd_step);
    
        while (size > 0)
        {
            uint32_t pages;
            uint32_t bytes;
            if (pages_left <= progress_update_step)
            {
                pages = pages_left;
                bytes = size;
            }
            else
            {
                pages = progress_update_step;
                bytes = progress_update_step * CODE_PAGE_SIZE;
            }
            // Erase the target pages
            ret_val = nrf_dfu_flash_erase(dst_addr, pages, NULL);
            if (ret_val != NRF_SUCCESS)
            {
                return ret_val;
            }
    
            // Flash one page
            NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
            ret_val = nrf_dfu_flash_store(dst_addr,
                                          (uint32_t *)src_addr,
                                          ALIGN_NUM(sizeof(uint32_t), bytes),
                                          NULL);
            if (ret_val != NRF_SUCCESS)
            {
                return ret_val;
            }
    
            pages_left  -= pages;
            size        -= bytes;
            dst_addr    += bytes;
            src_addr    += bytes;
            s_dfu_settings.write_offset += bytes;
    
            //store progress in flash on every successful chunk write
            ret_val = nrf_dfu_settings_write_and_backup(NULL);
            if (ret_val != NRF_SUCCESS)
            {
                NRF_LOG_ERROR("Failed to write image copying progress to settings page.");
                return ret_val;
            }
        }
    
        return ret_val;
    }

    The image_copy() function is used by app_activate()

    static uint32_t app_activate(void)
    {
        // This function is only in use when new app is present in Bank 1
        uint32_t const image_size  = s_dfu_settings.bank_1.image_size;
    
        uint32_t src_addr    = s_dfu_settings.progress.update_start_address;
        uint32_t ret_val     = NRF_SUCCESS;
        uint32_t target_addr = nrf_dfu_bank0_start_addr() + s_dfu_settings.write_offset;
        uint32_t length_left = (image_size - s_dfu_settings.write_offset);
        uint32_t crc;
    
        NRF_LOG_DEBUG("Enter nrf_dfu_app_continue");
    
        src_addr += s_dfu_settings.write_offset;
    
        if (src_addr == target_addr)
        {
            length_left = 0;
        }
    
        ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP);
        if (ret_val != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed to copy firmware.");
            return ret_val;
        }
    
        // Check the CRC of the copied data. Enable if so.
        crc = crc32_compute((uint8_t*)nrf_dfu_bank0_start_addr(), image_size, NULL);
    
        if (crc == s_dfu_settings.bank_1.image_crc)
        {
            NRF_LOG_DEBUG("Setting app as valid");
            s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_VALID_APP;
            s_dfu_settings.bank_0.image_crc = crc;
            s_dfu_settings.bank_0.image_size = image_size;
        }
        else
        {
            NRF_LOG_ERROR("CRC computation failed for copied app: "
                          "src crc: 0x%08x, res crc: 0x%08x",
                          s_dfu_settings.bank_1.image_crc,
                          crc);
        }
    
        return ret_val;
    }

    So the WDT should fire during the Application activation phase. The log you attached does not seem to be in the case, can you attach it again? Is the DFU update failing or does it go through with no errors or issues? If it is very small application then it could be that its written to flash before the WDT timer fires?

    Best regards

    Bjørn

  • wdt_feed_timer_handler() function is not called, This causes timeout for timer to reset the device

  • The "started..." will display two times, first is calling nrf_bootloader_wdt_init(1),second is calling nrf_bootloader_wdt_init(2) which is called in image_copy() function 

  • This phenomenon is not easy to see, because it occurs in the process of firmware activation. There will be a watchdog-induced reset and the firmware will continue to be activated after the restart. The upgrade will still succeed, but the reset caused by the watchdog is equivalent to the hardware reset. The watchdog is closed after restarting, so the firmware activation is actually done without the watchdog. This can lead to a period of time during an upgrade when the watchdog is closed, and an additional watchdog-induced reset process.

  • Which WDT interval have you configured in the application?

    mijiale said:
    The "started..." will display two times, first is calling nrf_bootloader_wdt_init(1),second is calling nrf_bootloader_wdt_init(2) which is called in image_copy() function 

    When entering the bootloader from the application nrf_bootloader_wdt_init() will be called in nrf_bootloader_init() and the WDT feed timer will be started if the WDT was active in the application. Then the DFU transfer will be performed and after the the firmware image has been transferred to the nRF52 device, the device will reset before activating the new firmware image.

    The WDT will not be reset during this Soft reset( NVIC_SystemReset())

    Upon entering main() after this reset, nrf_bootloader_init() will be called and nrf_bootloader_fw_activate() will be called, which in turn calls app_activate(), which calls image_copy(). So after the Soft reset you should only see that nrf_bootloader_wdt_init() is called once, i.e. in image_copy()

  • Hi

    The interval is 2 sec.There is any problem for my wdt.

    I'm sure this is a sdk bug for the problem.

    problem code as follow

    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);
    				//nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_2);
            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;
        }
    }
    at present,Code works properly when I get rid of judgment

    if (!nrf_clock_lf_is_running())

    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);
    				//nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_2);
            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;
        }
    }

  • : During the DFU process the bootloader may perform one or more SoftResets, i.e. call either  NVIC_SystemReset() or sd_nvic_SystemReset(). The WDT will _not_ be reset during a SoftReset, see Reset behavior

    If the WDT causes the reset during the DFU process, then yes, then the WDT will not be running after the reset unless explicitly started by the bootloader.  However, the WDT should not timeout during the DFU process in the first place. Could it be that the WDT interval is to thight? Do you see an improvement when setting the WDT timeout interval to 4?

    Best regards

    Bjørn

Reply
  • : During the DFU process the bootloader may perform one or more SoftResets, i.e. call either  NVIC_SystemReset() or sd_nvic_SystemReset(). The WDT will _not_ be reset during a SoftReset, see Reset behavior

    If the WDT causes the reset during the DFU process, then yes, then the WDT will not be running after the reset unless explicitly started by the bootloader.  However, the WDT should not timeout during the DFU process in the first place. Could it be that the WDT interval is to thight? Do you see an improvement when setting the WDT timeout interval to 4?

    Best regards

    Bjørn

Children
No Data
Related