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 #endif
44
45 #ifndef WDT_ALLOW_CALLBACK
46 #define WDT_ALLOW_CALLBACK 1
47 #endif
48
49 #ifndef WDT_MAX_WINDOW
50 #define WDT_MAX_WINDOW 1000U
51 #endif
52
53 #ifndef WDT_MIN_WINDOW
54 #define WDT_MIN_WINDOW 0U
55 #endif
56
57 #ifndef WDG_FEED_INTERVAL
58 #define WDG_FEED_INTERVAL 50U
59 #endif
60
61 #ifndef WDT_OPT
62 #define WDT_OPT WDT_OPT_PAUSE_HALTED_BY_DBG
63 #endif
64
65 #if WDT_ALLOW_CALLBACK
wdt_callback(const struct device * wdt_dev,int channel_id)66 static void wdt_callback(const struct device *wdt_dev, int channel_id)
67 {
68 static bool handled_event;
69
70 if (handled_event) {
71 return;
72 }
73
74 wdt_feed(wdt_dev, channel_id);
75
76 printk("Handled things..ready to reset\n");
77 handled_event = true;
78 }
79 #endif /* WDT_ALLOW_CALLBACK */
80
main(void)81 int main(void)
82 {
83 int err;
84 int wdt_channel_id;
85 const struct device *const wdt = DEVICE_DT_GET(DT_ALIAS(watchdog0));
86
87 printk("Watchdog sample application\n");
88
89 if (!device_is_ready(wdt)) {
90 printk("%s: device not ready.\n", wdt->name);
91 return 0;
92 }
93
94 struct wdt_timeout_cfg wdt_config = {
95 /* Reset SoC when watchdog timer expires. */
96 .flags = WDT_FLAG_RESET_SOC,
97
98 /* Expire watchdog after max window */
99 .window.min = WDT_MIN_WINDOW,
100 .window.max = WDT_MAX_WINDOW,
101 };
102
103 #if WDT_ALLOW_CALLBACK
104 /* Set up watchdog callback. */
105 wdt_config.callback = wdt_callback;
106
107 printk("Attempting to test pre-reset callback\n");
108 #else /* WDT_ALLOW_CALLBACK */
109 printk("Callback in RESET_SOC disabled for this platform\n");
110 #endif /* WDT_ALLOW_CALLBACK */
111
112 wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
113 if (wdt_channel_id == -ENOTSUP) {
114 /* IWDG driver for STM32 doesn't support callback */
115 printk("Callback support rejected, continuing anyway\n");
116 wdt_config.callback = NULL;
117 wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
118 }
119 if (wdt_channel_id < 0) {
120 printk("Watchdog install error\n");
121 return 0;
122 }
123
124 err = wdt_setup(wdt, WDT_OPT);
125 if (err < 0) {
126 printk("Watchdog setup error\n");
127 return 0;
128 }
129
130 #if WDT_MIN_WINDOW != 0
131 /* Wait opening window. */
132 k_msleep(WDT_MIN_WINDOW);
133 #endif
134 /* Feeding watchdog. */
135 printk("Feeding watchdog %d times\n", WDT_FEED_TRIES);
136 for (int i = 0; i < WDT_FEED_TRIES; ++i) {
137 printk("Feeding watchdog...\n");
138 wdt_feed(wdt, wdt_channel_id);
139 k_sleep(K_MSEC(WDG_FEED_INTERVAL));
140 }
141
142 /* Waiting for the SoC reset. */
143 printk("Waiting for reset...\n");
144 while (1) {
145 k_yield();
146 }
147 return 0;
148 }
149