在嵌入式系统开发中,看门狗(Watchdog)是一个至关重要的安全机制。当系统因软件故障或硬件异常导致主程序"卡死"时,看门狗能够自动触发系统复位,使设备从异常状态中恢复。本文将详细介绍在RK3568开发板上移植和测试Linux 4.14内核看门狗驱动的完整流程。
RK3568是瑞芯微推出的一款高性能嵌入式处理器,广泛应用于工业控制、智能设备等领域。在开始移植前,我们需要确保开发环境配置正确。
首先获取适用于RK3568的Linux 4.14内核源码,通常可以从芯片厂商提供的SDK中获取。解压后进入内核目录:
bash复制tar -xvf linux-4.14.tar.gz
cd linux-4.14
接下来配置内核,确保看门狗相关选项已启用:
bash复制make ARCH=arm64 menuconfig
在配置界面中,需要关注以下关键选项:
code复制Device Drivers --->
[*] Watchdog Timer Support --->
<*> DW Watchdog
[*] Disable watchdog shutdown on close
[*] Update boot-enabled watchdog until userspace takes over
这些选项分别对应:
CONFIG_WATCHDOG:启用看门狗子系统CONFIG_DW_WDT:启用DesignWare看门狗驱动(RK3568使用的看门狗类型)CONFIG_WATCHDOG_NOWAYOUT:禁止通过关闭设备文件来停止看门狗CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED:处理启动时已启用的看门狗配置完成后保存退出,编译内核:
bash复制make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8
编译完成后,将生成的arch/arm64/boot/Image和对应的设备树文件部署到开发板。
RK3568的看门狗控制器需要通过设备树进行配置。在设备树源文件(通常位于arch/arm64/boot/dts/rockchip/rk3568.dtsi)中添加或修改看门狗节点:
dts复制watchdog: watchdog@fe600000 {
compatible = "snps,dw-wdt";
reg = <0x0 0xfe600000 0x0 0x100>;
clocks = <&cru PCLK_WDT>;
interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
status = "okay";
};
关键参数说明:
compatible:必须设置为"snps,dw-wdt"以匹配驱动reg:看门狗控制器的寄存器地址和大小clocks:看门狗的时钟源interrupts:看门狗中断号status:设置为"okay"启用设备配置完成后,重新编译设备树并更新到开发板:
bash复制make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
内核启动后,可以通过以下命令检查看门狗驱动是否成功加载:
bash复制dmesg | grep watchdog
正常情况应该能看到类似输出:
code复制[ 2.345678] dw_wdt fe600000.watchdog: DesignWare Watchdog Timer enabled
检查设备节点是否创建成功:
bash复制ls -l /dev/watchdog*
应该能看到/dev/watchdog0或/dev/watchdog设备文件。如果没有自动创建,可以尝试手动加载驱动:
bash复制modprobe dw_wdt
查看驱动信息:
bash复制cat /sys/class/watchdog/watchdog0/identity
看门狗驱动正常工作后,我们可以通过多种方式进行测试。
最简单的测试方式是直接向设备文件写入数据:
bash复制echo 1 > /dev/watchdog0
这将启动看门狗计时器。如果不继续"喂狗",系统将在超时后重启。默认超时时间通常为60秒。
更专业的测试方式是使用watchdog工具包:
bash复制apt-get install watchdog
配置/etc/watchdog.conf:
conf复制watchdog-device = /dev/watchdog0
realtime = yes
priority = 1
interval = 10
启动服务:
bash复制systemctl start watchdog
对于需要自定义喂狗逻辑的场景,可以编写简单的C程序:
c复制#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("/dev/watchdog0", O_WRONLY);
if (fd == -1) {
perror("open watchdog");
return 1;
}
while (1) {
write(fd, "\0", 1); // 喂狗
fsync(fd);
sleep(5); // 5秒喂一次
}
close(fd);
return 0;
}
编译并运行:
bash复制gcc watchdog_test.c -o watchdog_test
./watchdog_test
看门狗的超时时间可以通过ioctl设置:
c复制#include <linux/watchdog.h>
int timeout = 30; // 30秒
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
或者在用户空间通过sysfs接口:
bash复制echo 30 > /sys/class/watchdog/watchdog0/timeout
NOWAYOUT模式确保看门狗一旦启动就无法被停止,即使关闭设备文件也不会停止看门狗。这是通过内核配置选项CONFIG_WATCHDOG_NOWAYOUT或在驱动中调用watchdog_set_nowayout()实现的。
检查当前模式:
bash复制cat /sys/class/watchdog/watchdog0/nowayout
当看门狗表现异常时,可以检查以下信息:
bash复制cat /sys/class/watchdog/watchdog0/state
bash复制cat /sys/class/watchdog/watchdog0/options
bash复制cat /sys/class/watchdog/watchdog0/timeleft
可能原因:
解决方案:
dmesg | grep watchdog/proc/devices中是否有watchdog主设备号可能原因:
解决方案:
cat /sys/kernel/debug/clk/clk_summary | grep wdt可能原因:
解决方案:
不同的应用场景需要不同的喂狗策略:
示例代码框架:
c复制void task1(void) {
// 任务代码
feed_watchdog();
}
void task2(void) {
// 任务代码
feed_watchdog();
}
void watchdog_thread(void) {
while (1) {
sleep(WATCHDOG_TIMEOUT/2);
feed_watchdog();
}
}
在多线程环境中使用看门狗需要特别注意:
将看门狗集成到系统服务中:
ini复制[Unit]
Description=Watchdog daemon
After=syslog.target network.target
[Service]
Type=simple
ExecStart=/usr/sbin/my_watchdog_daemon
Restart=always
[Install]
WantedBy=multi-user.target
bash复制systemctl enable my_watchdog_daemon
systemctl start my_watchdog_daemon
在RK3568项目开发中,我们遇到过一个典型问题:系统在高压测试时偶尔会无故重启。通过分析发现是看门狗超时导致的,但日志显示喂狗操作正常。最终发现是CPU负载过高时喂狗线程被抢占,导致喂狗不及时。解决方案是:
c复制struct sched_param param = { .sched_priority = 80 };
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
另一个实用技巧是在系统崩溃前保存关键信息。通过配置看门狗的pretimeout功能,可以在系统复位前触发中断,执行紧急保存操作:
c复制// 设置pretimeout为超时前5秒
int pretimeout = 5;
ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
// 注册pretimeout处理函数
signal(SIGALRM, pretimeout_handler);
这些实战经验表明,正确配置和使用看门狗不仅能提高系统可靠性,还能帮助诊断复杂的系统问题。