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_OKAY(DT_ALIAS(watchdog0))
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_wdog32)
37 #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_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 ret = task_wdt_init(NULL);
71 } else {
72 ret = task_wdt_init(hw_wdt_dev);
73 }
74
75 if (ret != 0) {
76 printk("task wdt init failure: %d\n", ret);
77 return 0;
78 }
79
80
81 /* passing NULL instead of callback to trigger system reset */
82 int task_wdt_id = task_wdt_add(1100U, NULL, NULL);
83
84 while (true) {
85 printk("Main thread still alive...\n");
86 task_wdt_feed(task_wdt_id);
87 k_sleep(K_MSEC(1000));
88 }
89 return 0;
90 }
91
92 /*
93 * This high-priority thread needs a tight timing
94 */
control_thread(void)95 void control_thread(void)
96 {
97 int task_wdt_id;
98 int count = 0;
99
100 printk("Control thread started.\n");
101
102 /*
103 * Add a new task watchdog channel with custom callback function and
104 * the current thread ID as user data.
105 */
106 task_wdt_id = task_wdt_add(100U, task_wdt_callback,
107 (void *)k_current_get());
108
109 while (true) {
110 if (count == 50) {
111 printk("Control thread getting stuck...\n");
112 k_sleep(K_FOREVER);
113 }
114
115 task_wdt_feed(task_wdt_id);
116 k_sleep(K_MSEC(50));
117 count++;
118 }
119 }
120
121 K_THREAD_DEFINE(control, 1024, control_thread, NULL, NULL, NULL, -1, 0, 1000);
122