Watch Dog(看门狗)是一种监控系统软件的运行状况的手段。稳定运行的软件会在执行完特定指令后进行喂狗,若在一定周期内看门狗没有收到来软件程序的喂狗信号,则认为软件运行出现了异常,进入中断处理程序或强制系统复位,本章节通过示例介绍看门狗的基本使用方法。
启动看门狗
int wdt_setup(const struct device *dev, uint8_t options);
该函数的配置影响所有超时的全局看门狗设置,必须在wdt_install_timeout()函数调用后使用,使用看门狗功能必须调用wdt_feed()函数定期维护喂狗。
参数说明
字段 | 说明 |
---|---|
dev | 指向看门狗device的指针 |
options | 值可配置为: WDT_OPT_PAUSE_HALTED_BY_DBG:当调试器暂停CPU时暂停看门狗计时器 WDT_OPT_PAUSE_IN_SLEEP:当CPU处于睡眠状态时暂停看门狗计时器 |
feed看门狗
int wdt_feed(const struct device *dev, int channel_id);
定期feed看门狗。返回0表示成功,返回非0表示失败,具体返回值见下面所示。
参数说明
字段 | 说明 |
---|---|
dev | 指向看门狗device的指针 |
channel_id | feed的通道id |
返回值说明
返回值 | 说明 |
---|---|
0 | 成功 |
-EAGAIN | 看门狗忙碌(比如别的地方也在操作看门狗) |
-EINVAL | 没有先调用wdt_install_timeout函数去配置对应的通道 |
设置看门狗超时时间
int wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg);
此函数必须在wdt_setup()之前使用。在调用wdt_setup()之前,该函数参数的更改不会产生任何影响。返回值>0为通道id,返回值<0表示失败。
参数说明
字段 | 说明 |
---|---|
dev | 指向看门狗device的指针 |
cfg | 指向timeout配置结构体的指针 |
返回值说明
返回值 | 说明 |
---|---|
>0 | 通道id |
-EBUSY | 看门狗启动后再调用本函数则返回-EBUSY |
-ENOMEM | 无法设置超时时间 |
-ENOTSUP | 不支持设置的参数 |
-EINVAL | 设置的超时时间超出范围 |
更多API接口可以在zephyr官网Watchdog Interface API中看到。
SDK 中提供了 WatchDog 的示例。
{SDK}\.sdk\csk\samples\driver\wdt
使用看门狗中断进行喂狗。
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk\csk\samples\driver\wdt -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
烧录完成后,连接串口终端,可看到串口有对应的信息输出。
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
…
#if WDT_ALLOW_CALLBACK
static void wdt_callback(const struct device *wdt_dev, int channel_id)
{
static bool is_handled = false;
if (!is_handled) {
is_handled = !is_handled;
wdt_feed(wdt_dev, channel_id);
printk("Handled watchdog interrupt and feed the dog.System will reset after %ds.\n",
WDT_MAX_WINDOW / 1000);
} else {
printk("Handled watchdog interrupt again, wait for reset.\n");
}
}
#endif /* WDT_ALLOW_CALLBACK */
int main(void)
{
int err;
int wdt_channel_id;
const struct device *wdt;
printk("Watchdog sample application, %s %s\n", __DATE__, __TIME__);
// 从设备树获取看门狗设备并进行初始化
wdt = DEVICE_DT_GET(DT_NODELABEL(wdt));
struct wdt_timeout_cfg wdt_config = {
.flags = WDT_FLAG_RESET_SOC,
.window.min = 0,
.window.max = WDT_MAX_WINDOW,
};
#if WDT_ALLOW_CALLBACK
// 看门狗超时配置,并启用回调函数
wdt_config.callback = wdt_callback;
…
// 装载配置并获取通道ID
wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
…
// 设置看门狗实例
err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG);
…
/* Feeding watchdog. */
uint32_t count = 0;
printk("Feeding watchdog %d times\n", WDT_FEED_TRIES);
for (int i = 0; i < WDT_FEED_TRIES; ++i) {
k_msleep(1000);
printk("Waiting for feed watchdog, %ds...\n", ++count);
}
// 喂食看门狗
wdt_feed(wdt, wdt_channel_id);
/* Waiting for the SoC reset. */
count = 0;
// 不再喂狗,等待系统重置
while (1) {
k_msleep(1000);
printk("Waiting for reset, %ds...\n", ++count);
}
}