How to add a fallback Hardware watchdog to a device tree/overlay file

Hello,

I am using the task watchdog sample to test the task watchdog subsystem. It is working fine.

I would like to use a hardware watchdog as a fallback; for this I need to define it in the devicetree or an overlay file.

How can I do either of the above?

I am using the following hardware/build environment,

- A proprietary board built around the nRF52833 SoC
- SEGGER Embedded Studio for ARM
  Release 5.60  Build 2021081102.47262
  Nordic Edition
  Windows x64
- Zephyr OS build v2.6.99-ncs1
- SDK 1.7.0
Thank you.
Kind regards
Mohamed
Parents
  • Hi Mohamed,

    I would like to use a hardware watchdog as a fallback; for this I need to define it in the devicetree or an overlay file.

    How can I do either of the above?

    It seems like you said that the task watchdog sample that you tested is working fine. What do you mean by "either of the above"?

    I would like to use a hardware watchdog as a fallback; for this I need to define it in the devicetree or an overlay file.

    In the nRF Connect SDK and in the below file v2.5.0 zephyr\tests\drivers\watchdog\wdt_basic_api\boards\nrf52840dk_nrf52840_counter.overlay

    you can see how watchdog is defined in the overlay file. You can enable the watchdog by changing the 

    status = "okay"; inside the &wdt0 node

  • #include <drivers/watchdog.h>
    #include <sys/reboot.h>
    #include <task_wdt/task_wdt.h>
    #include <logging/log.h>
    #include <stdio.h>
    
    #include "../../include/compiler.h"
    #include "../../include/system.h"
    #include "../../include/wdgt.h"
    #include "../../include/event_handler.h"
    
    LOG_MODULE_REGISTER(wdgt, LOG_LEVEL_INF);
    
    /*
     * 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)
    //#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
    
    /* According to the comment in the sample example at
     * https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/drivers/watchdog/src/main.c
     * Nordic supports a callback, but it has 61.2 us to complete before
     * the reset occurs, which is too short for this sample to do anything
     * useful. Explicitly disallow use of the callback.
     */
    #define WDT_ALLOW_CALLBACK 1
    #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
    
    
    /*
     *****************************************************************************************************************************************************
     *  !GLOBAL VARIABLES
     *****************************************************************************************************************************************************
     */
    int             task_wdt_id;
    
    
    #if WDT_ALLOW_CALLBACK
    /**************************************************************************
     * Watchdog timeout callback function.
     *
     **************************************************************************
     */
    static task_wdt_callback_t task_wdt_callback(int channel_id, void *user_data)
    {
        LOG_DBG( "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.
         */
    
    //  printf( "Resetting device...\n" );
        LOG_WRN("Resetting device...");
    
        sys_reboot(SYS_REBOOT_COLD);
    
        return 0;
    }
    #endif /* WDT_ALLOW_CALLBACK */
    
    
    /**************************************************************************
     * Sets up necessary kernel timers and the hardware watchdog, if desired
     * as fallback).
     *
     * Note, It has to be called before wdgt_refresh().
     *
     **************************************************************************
     */
    void wdgt_init( void )
    {
    #ifdef WDT_NODE
        const struct device *hw_wdt_dev = DEVICE_DT_GET(WDT_NODE);
    #else
        const struct device *hw_wdt_dev = NULL;
    #endif
        int result;
    
        LOG_DBG( "Watchdog Init" );
    
        if ( !device_is_ready( hw_wdt_dev ) )
        {
            LOG_WRN( "Hardware watchdog %s is NOT ready - ignored.", hw_wdt_dev->name );
    
            hw_wdt_dev = NULL;
        }
        else
        {
            LOG_INF( "Hardware watchdog %s is ready.", hw_wdt_dev->name );
        }
    
    
        result = task_wdt_init( hw_wdt_dev );
        if ( result )
        {
            LOG_ERR( "%i - Hardware watchdog not supported. ", result );
        }
    
        /* passing NULL instead of callback to trigger system reset */
    #if WDT_ALLOW_CALLBACK
        task_wdt_id = task_wdt_add(15000U, (task_wdt_callback_t)task_wdt_callback, NULL);
    #else
        task_wdt_id = task_wdt_add( 30000U, NULL, NULL );
    #endif
    
        if ( task_wdt_id >= 0 )
        {
            LOG_INF( "Watchdog Timeout OK - %i.", task_wdt_id );
        }
        else
        {
            LOG_ERR( "Watchdog Timeout Error - %i.", task_wdt_id );
        }
    }
    
    
    /**************************************************************************
     * Refresh the watchdog peripheral to prevent timeout.
     *
     **************************************************************************
     */
    void wdgt_refresh( void )
    {
            LOG_DBG( "Application still alive..." );
    
            task_wdt_feed( task_wdt_id );
    }
    
    Thank you Susheel.

    You can enable the watchdog by changing the 

    status = "okay"; inside the &wdt0 node

    I can already see in my build folder a .dts file under zephyr\zephyr.dts, where the watchdog status is already set to "okay". See below.

    ...[snip]

    wdt: wdt0: watchdog@40010000 {
    compatible = "nordic,nrf-watchdog";
    reg = < 0x40010000 0x1000 >;
    interrupts = < 0x10 0x1 >;
    status = "okay";
    label = "WDT";
    };

    [snip]...

    So, I added these macros (taken from one of Nordic's examples) to my code,

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

    Unfortunately, when I ran my code, the watchdog timer keeps timing out causing the application to keep rebooting.

    However, if I don't enable the hardware watchdog as fallback but instead use only the task watchdog then the app runs fine and reboots only when expected to reboot i.e. when I deliberately stop refreshing the watchdog timer.

    *** Booting Zephyr OS build v2.6.99-ncs1 ***
    [00:00:00.000,213] <inf> main: Booting-up time [0 s]
    ....

    *** Booting Zephyr OS build v2.6.99-ncs1 ***
    [00:00:00.000,213] <inf> main: Booting-up time [0 s]
    ...

    *** Booting Zephyr OS build v2.6.99-ncs1 ***
    [00:00:00.000,213] <inf> main: Booting-up time [0 s]
    ...

    Please tell what I am doing wrong.

    Kind regards

    Mohamed

  • Hi Maria,

    Thank you for letting me know.

    Kind regards

    Mohamed

  • Thanks for waiting Mohamed, Happy New Year. I am just back from the holidays and wondering if you still have this issue or have you found the way to fix it?

    Learner said:
    Is it because I am refreshing the task watchdog timer every second?

    That could be.

    Learner said:
    I am printing the reset reason in my callback function task_wdt_callback_t task_wdt_callback() expecting it to be 2 since it was caused by a task watchdog timeout, instead I am getting reason = 0.
    printf( "Reas = %u\n", NRF_POWER->RESETREAS );

    That is strange. Can you please give me your project for me to reproduce and debug this? Maybe the reset reason is cleared somewhere else in the code?

  • Hi Susheel,

    Happy new year to you too.

    Learner said:
    I am printing the reset reason in my callback function task_wdt_callback_t task_wdt_callback() expecting it to be 2 since it was caused by a task watchdog timeout, instead I am getting reason = 0.
    printf( "Reas = %u\n", NRF_POWER->RESETREAS );

    1- Actually things have moved on now and I am getting this reset reason SYSTEM_RESET_SOFTWARE (0x4). Maybe I should have added that once the task watchdog times out I am calling the function sys_reboot(SYS_REBOOT_COLD) from the task_wdt_callback() function. I think this is why I am getting the software reset reason.

    2- What is the difference between the hardware watchdog and the task watchdog?

    CONFIG_WATCHDOG=y versus CONFIG_TASK_WDT=y

    Finally, when I try to write to flash in the callback function task_wdt_callback(), nvs_write() is returning the error ECANCELED (140) meaning the write operation has been cancelled. Is it because, as stated in the task_wdt example comments, the callback has only 61.2 us to complete before the reset occurs and writing to flash is taking longer than this?

    3- Please answer the question above. I need to store in flash this watchdog reset event but I am not sure how I can do it without running out of time before the actual reset occurs. Is there a way of delaying the task_watchdog reset until I finish tidying up?

    Kind regards

    Mohamed

  • Learner said:

    2- What is the difference between the hardware watchdog and the task watchdog?

    CONFIG_WATCHDOG=y versus CONFIG_TASK_WDT=y

    You need CONFIG_WATCHDOG to use watchdog_api this inturn uses nrfx drivers.

    CONFIG_TASK_WDT is a firmware feature on top of the above watchdog which provides multiple channel usage of watchdog feature instead of the normal (only one) in most of the hardware watchdog.

    Learner said:
    Please answer the question above. I need to store in flash this watchdog reset event but I am not sure how I can do it without running out of time before the actual reset occurs. Is there a way of delaying the task_watchdog reset until I finish tidying up?

    You need to save the data in RAM and not flash if you have to write more than a word in the wdt_callback. This topic is covered and discussed in this thread

  • Hi Susheel,

    You need to save the data in RAM and not flash if you have to write more than a word in the wdt_callback. This topic is covered and discussed in this thread

    I cannot find the file flash_placement.xml where the line containing .non_init is mentioned.

    Is there another equivalent file?

    Plus, according to Einar Thorsrud,

    "(Also, the degree of which RAM content persists may depend on several other factors as well, and this is using the IC out of specification, so you can never be guaranteed that RAM data is retained after a reset.)".

    Kind regards

    Mohamed

Reply
  • Hi Susheel,

    You need to save the data in RAM and not flash if you have to write more than a word in the wdt_callback. This topic is covered and discussed in this thread

    I cannot find the file flash_placement.xml where the line containing .non_init is mentioned.

    Is there another equivalent file?

    Plus, according to Einar Thorsrud,

    "(Also, the degree of which RAM content persists may depend on several other factors as well, and this is using the IC out of specification, so you can never be guaranteed that RAM data is retained after a reset.)".

    Kind regards

    Mohamed

Children
No Data
Related