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

  • Mohammed, 

    In the code you attached, I do not see main function. I also do not see how wdgt_refresh is being called. 

    In the jist of it, the wdt sample shows you that the wdt initialization works and if you are feeding the wdt correctly, then wdt does not do anything and if the feeding stops, then wdt resets the chip as intended. I do not see any other issues. here

  • Hi Susheel,

    I appreciate your prompt response. Thank you.

    I do not see main function.

    My main function looks something like this,

    void main( void )
    {

       ...

        while ( 1 )
       {

          ...

           /* Refresh the watchdog channel timer every second */
           wdgt_refresh();

          ...

        }

    }

    So, despite the fact I am feeding wdt every second, wdt keeps timing out but this happens only when I enable the hardware watchdog as a fallback.

    If I disable the hardware watchdog then the problem disappears and the application runs without the wdt timing out.

    Kind regards

    Mohamed

  • I do not understand what fallback means here? 

    Can you please give me the whole snippet of your main function so that I can test why wdt timesout even though you expect it not to?

Related