返回首页

Watchdog (看门狗) 学习笔记

本笔记学习 Zephyr 的 Watchdog 驱动,用于系统监控和自动复位。


示例路径

zephyr/samples/drivers/watchdog/src/main.c

核心概念

看门狗定时器 (WDT)

工作原理

启动看门狗
    ↓
设置超时时间
    ↓
周期性喂狗 (wdt_feed) ←──┐
    ↓                    │
超时? ──── 否 ──────────┘
    │
    是
    ↓
系统复位

核心 API

头文件

#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,
};

窗口模式下:


nRF54L15 设备树配置

/ {
    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...

然后系统复位。


应用场景

  1. 系统监控: 检测程序跑飞
  2. 死锁恢复: 自动复位恢复
  3. 关键任务: 确保系统持续运行
  4. 安全系统: 检测异常并恢复

注意事项

  1. 喂狗间隔: 必须小于超时时间
  2. 调试影响: 使用 WDT_OPT_PAUSE_HALTED_BY_DBG 方便调试
  3. 回调限制: Nordic 平台回调时间极短
  4. 多通道: 某些硬件支持多个看门狗通道

最佳实践

// 在主循环中喂狗
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*