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
  • Hi,

    You write that you tried a long timeout. How long was that? What happens if you use a much longer timeout? Also, how do you use it? how many tasks, and have you verified that it is the task WDT that causes the reset, and not some other error (for instance by registering a task WDT callback and setting a breakpoint there)?

  • 200s (normally 20s) changing the timeout has no impact on when the reset occurs.

    I have added a task watchdog for each thread, feeding it regulary with half the frequence of the timeout period.

    I use it on 7 threads, but have also tried with just 1.

    I have a WDT callback which does not get triggered. It is a zephyr hard fault that causes the reboot.

    I don't think it is a wdt reset, but the use of a task wdt that causes the flash erase function to reset the system.

  • Hi,

    I see. Can you enable logging (if not allready) and show what is printed when the fault occurs, before the reset? Can you share a minimal example that reproduce the issue on a DK?

  • /*
     * 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.

Reply Children
No Data
Related