1 /*
2 * Copyright (c) 2020 Libre Solar Technologies GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/watchdog.h>
10 #include <zephyr/sys/reboot.h>
11 #include <zephyr/task_wdt/task_wdt.h>
12 #include <zephyr/sys/printk.h>
13 #include <stdbool.h>
14
15 /*
16 * To use this sample, either the devicetree's /aliases must have a
17 * 'watchdog0' property, or one of the following watchdog compatibles
18 * must have an enabled node.
19 *
20 * If the devicetree has a watchdog node, we get the watchdog device
21 * from there. Otherwise, the task watchdog will be used without a
22 * hardware watchdog fallback.
23 */
24 #if DT_NODE_HAS_STATUS(DT_ALIAS(watchdog0), okay)
25 #define WDT_NODE DT_ALIAS(watchdog0)
26 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
27 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_window_watchdog)
28 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_watchdog)
29 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_watchdog)
30 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
31 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_nrf_wdt)
32 #elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_watchdog)
33 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(espressif_esp32_watchdog)
34 #elif DT_HAS_COMPAT_STATUS_OKAY(silabs_gecko_wdog)
35 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(silabs_gecko_wdog)
36 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_wdog32)
37 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_kinetis_wdog32)
38 #elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_watchdog)
39 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(microchip_xec_watchdog)
40 #else
41 #define WDT_NODE DT_INVALID_NODE
42 #endif
43
task_wdt_callback(int channel_id,void * user_data)44 static void task_wdt_callback(int channel_id, void *user_data)
45 {
46 printk("Task watchdog channel %d callback, thread: %s\n",
47 channel_id, k_thread_name_get((k_tid_t)user_data));
48
49 /*
50 * If the issue could be resolved, call task_wdt_feed(channel_id) here
51 * to continue operation.
52 *
53 * Otherwise we can perform some cleanup and reset the device.
54 */
55
56 printk("Resetting device...\n");
57
58 sys_reboot(SYS_REBOOT_COLD);
59 }
60
main(void)61 int main(void)
62 {
63 int ret;
64 const struct device *const hw_wdt_dev = DEVICE_DT_GET_OR_NULL(WDT_NODE);
65
66 printk("Task watchdog sample application.\n");
67
68 if (!device_is_ready(hw_wdt_dev)) {
69 printk("Hardware watchdog not ready; ignoring it.\n");
70 }
71
72 ret = task_wdt_init(hw_wdt_dev);
73 if (ret != 0) {
74 printk("task wdt init failure: %d\n", ret);
75 return 0;
76 }
77
78
79 /* passing NULL instead of callback to trigger system reset */
80 int task_wdt_id = task_wdt_add(1100U, NULL, NULL);
81
82 while (true) {
83 printk("Main thread still alive...\n");
84 task_wdt_feed(task_wdt_id);
85 k_sleep(K_MSEC(1000));
86 }
87 return 0;
88 }
89
90 /*
91 * This high-priority thread needs a tight timing
92 */
control_thread(void)93 void control_thread(void)
94 {
95 int task_wdt_id;
96 int count = 0;
97
98 printk("Control thread started.\n");
99
100 /*
101 * Add a new task watchdog channel with custom callback function and
102 * the current thread ID as user data.
103 */
104 task_wdt_id = task_wdt_add(100U, task_wdt_callback,
105 (void *)k_current_get());
106
107 while (true) {
108 if (count == 50) {
109 printk("Control thread getting stuck...\n");
110 k_sleep(K_FOREVER);
111 }
112
113 task_wdt_feed(task_wdt_id);
114 k_sleep(K_MSEC(50));
115 count++;
116 }
117 }
118
119 K_THREAD_DEFINE(control, 1024, control_thread, NULL, NULL, NULL, -1, 0, 1000);
120