DFU target library and task WDT not work together

Hi,

I work on a project that uses the dfu target library for firmware updates. This has been working flawless until I added task watchdogs.

The problem that I see is that after a task wdt has been added, the dfu_target_mcuboot_write causes the zephyr system to reboot. Through debugging I see that it happens when the first page in flash is erased. If i disable the task wdt add function, I see no problems.

More information:

  • I have tried to use a long timeout and regularly feed the watchdog to ensure that it is not the reason why the reboot occur.
  • I have tried to call the task wdt delete function before the dfu_target_mcuboot_write function but this still reboots the system.
  • SDK 1.8.0 
Parents Reply Children
  • /*
     * Copyright (c) 2020 Libre Solar Technologies GmbH
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <drivers/watchdog.h>
    #include <sys/reboot.h>
    #include <task_wdt/task_wdt.h>
    #include <sys/printk.h>
    #include <stdbool.h>
    #include <dfu/dfu_target_mcuboot.h>
    
    /*
     * To use this sample, either the devicetree's /aliases must have a
     * 'watchdog0' property, or one of the following watchdog compatibles
     * must have an enabled node.
     *
     * If the devicetree has a watchdog node, we get the watchdog device
     * from there. Otherwise, the task watchdog will be used without a
     * hardware watchdog fallback.
     */
    #if DT_NODE_HAS_STATUS(DT_ALIAS(watchdog0), okay)
    #define WDT_NODE DT_ALIAS(watchdog0)
    #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_window_watchdog)
    #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_watchdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_watchdog)
    #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_watchdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_nrf_watchdog)
    #elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_watchdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(espressif_esp32_watchdog)
    #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_gecko_wdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(silabs_gecko_wdog)
    #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_wdog32)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_kinetis_wdog32)
    #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_watchdog)
    #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(microchip_xec_watchdog)
    #endif
    
    uint8_t buf[244] = {0};
    
    static void task_wdt_callback(int channel_id, void *user_data)
    {
    	printk("Task watchdog channel %d callback, thread: %s\n",
    		channel_id, k_thread_name_get((k_tid_t)user_data));
    
    	/*
    	 * If the issue could be resolved, call task_wdt_feed(channel_id) here
    	 * to continue operation.
    	 *
    	 * Otherwise we can perform some cleanup and reset the device.
    	 */
    
    	printk("Resetting device...\n");
    
    	sys_reboot(SYS_REBOOT_COLD);
    }
    
    void main(void)
    {
    #ifdef WDT_NODE
    	const struct device *hw_wdt_dev = DEVICE_DT_GET(WDT_NODE);
    #else
    	const struct device *hw_wdt_dev = NULL;
    #endif
    
    	printk("Task watchdog sample application.\n");
    
    	if (!device_is_ready(hw_wdt_dev)) {
    		printk("Hardware watchdog %s is not ready; ignoring it.\n",
    		       hw_wdt_dev->name);
    		hw_wdt_dev = NULL;
    	}
    
    	task_wdt_init(hw_wdt_dev);
    
    	/* passing NULL instead of callback to trigger system reset */
    	int task_wdt_id = task_wdt_add(1100U, NULL, NULL);
    
    	while (true) {
    		printk("Main thread still alive...\n");
    		task_wdt_feed(task_wdt_id);
    		k_sleep(K_MSEC(1000));
    	}
    }
    
    /*
     * This high-priority thread needs a tight timing
     */
    void control_thread(void)
    {
    	int task_wdt_id;
    	int count = 0;
    
    	printk("Control thread started.\n");
    
    	uint8_t imageData[244] = {5};
    
    	dfu_target_mcuboot_set_buf(buf, sizeof(buf));
    	dfu_target_mcuboot_init(10000, NULL);
    	// Works if below is removed
    	dfu_target_mcuboot_write(imageData, sizeof(imageData));
    
    	printk("We did it!\n");
    
    	while(1);
    
    	// /*
    	//  * Add a new task watchdog channel with custom callback function and
    	//  * the current thread ID as user data.
    	//  */
    	// task_wdt_id = task_wdt_add(10000U, task_wdt_callback,
    	// 	(void *)k_current_get());
    		
    
    	// while (true) {
    	// 	if (count == 50) {
    	// 		printk("Control thread getting stuck...\n");
    	// 		k_sleep(K_FOREVER);
    	// 	}
    
    	// 	task_wdt_feed(task_wdt_id);
    	// 	k_sleep(K_MSEC(50));
    	// 	count++;
    	// }
    }
    
    K_THREAD_DEFINE(control, 1024, control_thread, NULL, NULL, NULL, 5, 0, 1000);
    

  • CONFIG_LOG=y
    
    CONFIG_WATCHDOG=y
    CONFIG_WDT_LOG_LEVEL_DBG=y
    CONFIG_WDT_DISABLE_AT_BOOT=y
    
    CONFIG_TASK_WDT=y
    CONFIG_TASK_WDT_MIN_TIMEOUT=100
    
    # Ensure an MCUboot-compatible binary is generated.
    CONFIG_FLASH=y
    CONFIG_BOOTLOADER_MCUBOOT=y
    CONFIG_IMG_MANAGER=y
    CONFIG_THREAD_NAME=y
    CONFIG_DFU_TARGET=y
    CONFIG_DFU_TARGET_MCUBOOT=y
    CONFIG_STREAM_FLASH_ERASE=y

  • Thanks, I will look at it.

    In the mean time, I must admit I do not see the benefit on the task WDT on nRF HW, at lest for most projects, as the hardware WDT support multiple channels. May I ask why you are using it?

  • It was easy to implement, and at the time no example was available for the hardware wdt. Besides the task wdt allows longer time in wdt callback to save stuff like date and time to nvm.

Related