1 /*
2 * Copyright (c) 2015 Intel Corporation
3 * Copyright (c) 2018 Nordic Semiconductor
4 * Copyright (c) 2019 Centaur Analytics, Inc
5 * Copyright 2023 NXP
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/watchdog.h>
13 #include <zephyr/sys/printk.h>
14 #include <stdbool.h>
15
16 #define WDT_FEED_TRIES 5
17
18 /*
19 * To use this sample the devicetree's /aliases must have a 'watchdog0' property.
20 */
21 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
22 #define WDT_MAX_WINDOW 100U
23 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
24 /* Nordic supports a callback, but it has 61.2 us to complete before
25 * the reset occurs, which is too short for this sample to do anything
26 * useful. Explicitly disallow use of the callback.
27 */
28 #define WDT_ALLOW_CALLBACK 0
29 #elif DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_watchdog)
30 #define WDT_ALLOW_CALLBACK 0
31 #elif DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_wwdgt)
32 #define WDT_MAX_WINDOW 24U
33 #define WDT_MIN_WINDOW 18U
34 #define WDG_FEED_INTERVAL 12U
35 #elif DT_HAS_COMPAT_STATUS_OKAY(intel_tco_wdt)
36 #define WDT_ALLOW_CALLBACK 0
37 #define WDT_MAX_WINDOW 3000U
38 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_fs26_wdog)
39 #define WDT_MAX_WINDOW 1024U
40 #define WDT_MIN_WINDOW 320U
41 #define WDT_OPT 0
42 #define WDG_FEED_INTERVAL (WDT_MIN_WINDOW + ((WDT_MAX_WINDOW - WDT_MIN_WINDOW) / 4))
43 #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_wdt)
44 #define WDT_ALLOW_CALLBACK 0
45 #elif DT_HAS_COMPAT_STATUS_OKAY(wch_iwdg)
46 #define WDT_ALLOW_CALLBACK 0
47 #define WDT_OPT 0
48 #elif DT_HAS_COMPAT_STATUS_OKAY(sifli_sf32lb_wdt)
49 #define WDT_ALLOW_CALLBACK 0
50 #define WDT_OPT 0
51 #endif
52
53 #ifndef WDT_ALLOW_CALLBACK
54 #define WDT_ALLOW_CALLBACK 1
55 #endif
56
57 #ifndef WDT_MAX_WINDOW
58 #define WDT_MAX_WINDOW 1000U
59 #endif
60
61 #ifndef WDT_MIN_WINDOW
62 #define WDT_MIN_WINDOW 0U
63 #endif
64
65 #ifndef WDG_FEED_INTERVAL
66 #define WDG_FEED_INTERVAL 50U
67 #endif
68
69 #ifndef WDT_OPT
70 #define WDT_OPT WDT_OPT_PAUSE_HALTED_BY_DBG
71 #endif
72
73 #if WDT_ALLOW_CALLBACK
wdt_callback(const struct device * wdt_dev,int channel_id)74 static void wdt_callback(const struct device *wdt_dev, int channel_id)
75 {
76 static bool handled_event;
77
78 if (handled_event) {
79 return;
80 }
81
82 wdt_feed(wdt_dev, channel_id);
83
84 printk("Handled things..ready to reset\n");
85 handled_event = true;
86 }
87 #endif /* WDT_ALLOW_CALLBACK */
88
main(void)89 int main(void)
90 {
91 int err;
92 int wdt_channel_id;
93 const struct device *const wdt = DEVICE_DT_GET(DT_ALIAS(watchdog0));
94
95 printk("Watchdog sample application\n");
96
97 if (!device_is_ready(wdt)) {
98 printk("%s: device not ready.\n", wdt->name);
99 return 0;
100 }
101
102 struct wdt_timeout_cfg wdt_config = {
103 /* Reset SoC when watchdog timer expires. */
104 .flags = WDT_FLAG_RESET_SOC,
105
106 /* Expire watchdog after max window */
107 .window.min = WDT_MIN_WINDOW,
108 .window.max = WDT_MAX_WINDOW,
109 };
110
111 #if WDT_ALLOW_CALLBACK
112 /* Set up watchdog callback. */
113 wdt_config.callback = wdt_callback;
114
115 printk("Attempting to test pre-reset callback\n");
116 #else /* WDT_ALLOW_CALLBACK */
117 printk("Callback in RESET_SOC disabled for this platform\n");
118 #endif /* WDT_ALLOW_CALLBACK */
119
120 wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
121 if (wdt_channel_id == -ENOTSUP) {
122 /* IWDG driver for STM32 doesn't support callback */
123 printk("Callback support rejected, continuing anyway\n");
124 wdt_config.callback = NULL;
125 wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
126 }
127 if (wdt_channel_id < 0) {
128 printk("Watchdog install error\n");
129 return 0;
130 }
131
132 err = wdt_setup(wdt, WDT_OPT);
133 if (err < 0) {
134 printk("Watchdog setup error\n");
135 return 0;
136 }
137
138 #if WDT_MIN_WINDOW != 0
139 /* Wait opening window. */
140 k_msleep(WDT_MIN_WINDOW);
141 #endif
142 /* Feeding watchdog. */
143 printk("Feeding watchdog %d times\n", WDT_FEED_TRIES);
144 for (int i = 0; i < WDT_FEED_TRIES; ++i) {
145 printk("Feeding watchdog...\n");
146 wdt_feed(wdt, wdt_channel_id);
147 k_sleep(K_MSEC(WDG_FEED_INTERVAL));
148 }
149
150 /* Waiting for the SoC reset. */
151 printk("Waiting for reset...\n");
152 while (1) {
153 k_yield();
154 }
155 return 0;
156 }
157