samples: subsys: task_wdt: add sample application

The sample demonstrates how to use the task watchdog in different
threads.

Signed-off-by: Martin Jäger <martin@libre.solar>
This commit is contained in:
Martin Jäger 2020-11-25 17:39:28 +01:00 committed by Carles Cufí
commit 2857c2e984
5 changed files with 199 additions and 0 deletions

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(task_wdt)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,48 @@
.. _task_wdt_sample:
Task Watchdog Sample
####################
Overview
********
This sample allows to test the task watchdog subsystem.
Building and Running
********************
It should be possible to build and run the task watchdog sample on almost any
board. If a hardware watchdog is defined in the devicetree, it is used as a
fallback. Otherwise the task watchdog will run independently.
Building and Running for ST Nucleo L073RZ
=========================================
The sample can be built and executed for the
:ref:`nucleo_l073rz_board` as follows:
.. zephyr-app-commands::
:zephyr-app: samples/subsys/task_wdt
:board: nucleo_l073rz
:goals: build flash
:compact:
For other boards just replace the board name.
Sample output
=============
The following output is printed and continuously repeated (after each
reset):
.. code-block:: console
Task watchdog sample application.
Main thread still alive...
Control thread started.
Main thread still alive...
Main thread still alive...
Main thread still alive...
Control thread getting stuck...
Main thread still alive...
Task watchdog channel 1 callback, thread: control
Resetting device...

View file

@ -0,0 +1,10 @@
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=50
CONFIG_THREAD_NAME=y

View file

@ -0,0 +1,20 @@
sample:
name: Task Watchdog Subsytem Sample
tests:
sample.subsys.task_wdt:
tags: subsys
harness: console
harness_config:
type: multi_line
ordered: true
regex:
- "Task watchdog sample application."
- "Control thread started."
- "Main thread still alive..."
- "Control thread getting stuck..."
- "Task watchdog channel 1 callback, thread: control"
- "Resetting device...(.*)"
- "Task watchdog sample application."
depends_on: watchdog
integration_platforms:
- nucleo_g474re

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2020 Libre Solar Technologies GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <drivers/watchdog.h>
#include <power/reboot.h>
#include <task_wdt/task_wdt.h>
#include <sys/printk.h>
#include <stdbool.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 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_INST(0, st_stm32_window_watchdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_watchdog)
#define WDT_NODE DT_INST(0, st_stm32_watchdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_watchdog)
#define WDT_NODE DT_INST(0, nordic_nrf_watchdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_watchdog)
#define WDT_NODE DT_INST(0, espressif_esp32_watchdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(silabs_gecko_wdog)
#define WDT_NODE DT_INST(0, silabs_gecko_wdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_wdog32)
#define WDT_NODE DT_INST(0, nxp_kinetis_wdog32)
#elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_watchdog)
#define WDT_NODE DT_INST(0, microchip_xec_watchdog)
#endif
/*
* If the devicetree has a watchdog node, get its label property. Otherwise
* the task watchdog will be used without a hardware watchdog fallback.
*/
#ifdef WDT_NODE
#define WDT_DEV_NAME DT_LABEL(WDT_NODE)
#endif
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_DEV_NAME
const struct device *hw_wdt_dev = device_get_binding(WDT_DEV_NAME);
#else
const struct device *hw_wdt_dev = NULL;
#endif
printk("Task watchdog sample application.\n");
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");
/*
* Add a new task watchdog channel with custom callback function and
* the current thread ID as user data.
*/
task_wdt_id = task_wdt_add(100U, 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, -1, 0, 1000);