本笔记学习 Zephyr 的 Watchdog 驱动,用于系统监控和自动复位。
zephyr/samples/drivers/watchdog/src/main.c
启动看门狗
↓
设置超时时间
↓
周期性喂狗 (wdt_feed) ←──┐
↓ │
超时? ──── 否 ──────────┘
│
是
↓
系统复位
#include <zephyr/drivers/watchdog.h>
const struct device *const wdt = DEVICE_DT_GET(DT_ALIAS(watchdog0));
if (!device_is_ready(wdt)) {
printk("Watchdog device not ready\n");
return;
}
struct wdt_timeout_cfg {
struct {
uint32_t min; // 最小窗口(可选)
uint32_t max; // 最大窗口(超时时间)
} window;
wdt_callback_t callback; // 回调函数(可选)
uint32_t flags; // 标志位
};
| 标志 | 说明 |
|---|---|
WDT_FLAG_RESET_SOC | 复位整个 SoC |
WDT_FLAG_RESET_CPU | 仅复位 CPU |
WDT_FLAG_RESET_NONE | 不复位(仅回调) |
struct wdt_timeout_cfg wdt_config = {
.flags = WDT_FLAG_RESET_SOC,
.window.min = 0,
.window.max = 1000, // 1000ms 超时
.callback = NULL,
};
int wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
if (wdt_channel_id < 0) {
printk("Watchdog install error\n");
return;
}
int err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
if (err < 0) {
printk("Watchdog setup error\n");
return;
}
| 选项 | 说明 |
|---|---|
WDT_OPT_PAUSE_HALTED_BY_DBG | 调试时暂停 |
WDT_OPT_NO_OPTION | 无选项 |
wdt_feed(wdt, wdt_channel_id);
必须在超时时间内周期性调用,否则系统复位。
static void wdt_callback(const struct device *wdt_dev, int channel_id)
{
static bool handled = false;
if (handled) {
return;
}
// 在复位前执行紧急操作
printk("Watchdog timeout! Preparing for reset...\n");
// 可选:喂狗延长复位时间
wdt_feed(wdt_dev, channel_id);
handled = true;
}
struct wdt_timeout_cfg wdt_config = {
.flags = WDT_FLAG_RESET_SOC,
.window.max = 1000,
.callback = wdt_callback, // 设置回调
};
⚠️ Nordic nRF 系列:回调时间仅 61.2μs,几乎无法执行有用操作。
#include <zephyr/kernel.h>
#include <zephyr/drivers/watchdog.h>
#define WDT_MAX_WINDOW 1000U // 1 秒
#define WDT_FEED_TRIES 5
int main(void)
{
const struct device *const wdt = DEVICE_DT_GET(DT_ALIAS(watchdog0));
int wdt_channel_id;
// 检查设备
if (!device_is_ready(wdt)) {
printk("Watchdog device not ready\n");
return 0;
}
// 配置超时
struct wdt_timeout_cfg wdt_config = {
.flags = WDT_FLAG_RESET_SOC,
.window.min = 0,
.window.max = WDT_MAX_WINDOW,
.callback = NULL,
};
wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
if (wdt_channel_id < 0) {
printk("Watchdog install error\n");
return 0;
}
// 启动看门狗
int err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
if (err < 0) {
printk("Watchdog setup error\n");
return 0;
}
// 喂狗循环
printk("Feeding watchdog %d times...\n", WDT_FEED_TRIES);
for (int i = 0; i < WDT_FEED_TRIES; i++) {
printk("Feeding %d\n", i + 1);
wdt_feed(wdt, wdt_channel_id);
k_sleep(K_MSEC(500)); // 500ms 间隔
}
// 停止喂狗,等待复位
printk("Waiting for reset...\n");
while (1) {
k_yield();
}
return 0;
}
某些硬件支持窗口模式:
struct wdt_timeout_cfg wdt_config = {
.window.min = 200, // 最早 200ms 后才能喂狗
.window.max = 1000, // 最晚 1000ms 内必须喂狗
.flags = WDT_FLAG_RESET_SOC,
};
窗口模式下:
min 时间前喂狗会立即复位max 时间未喂狗会复位/ {
aliases {
watchdog0 = &wdt0;
};
};
&wdt0 {
status = "okay";
};
cd /home/wangpei/ncs-sdk
west build -p -b nrf54l15dk/nrf54l15/cpuapp zephyr/samples/drivers/watchdog
west flash
Watchdog sample application
Feeding watchdog 5 times
Feeding watchdog...
Feeding watchdog...
Feeding watchdog...
Feeding watchdog...
Feeding watchdog...
Waiting for reset...
然后系统复位。
WDT_OPT_PAUSE_HALTED_BY_DBG 方便调试// 在主循环中喂狗
while (1) {
// 执行任务...
wdt_feed(wdt, wdt_channel_id); // 任务完成后喂狗
}
// 或在独立线程中喂狗
void wdt_thread(void *arg)
{
while (1) {
wdt_feed(wdt, wdt_channel_id);
k_sleep(K_MSEC(500)); // 小于超时时间
}
}
*小白 🤖 - 2026-03-16*