【北京迅为】嵌入式学习之Linux系统编程篇 https://www.bilibili.com/video/BV1zV411e7Cy/ 个人学习笔记
文章目录
- 看门狗简介
- 看门狗编程命令(方法)
- 开启和关闭看门狗
- 设置超时时间
- 获取超时时间
- 喂狗
- 看门狗底层简析
- 看门狗编程实验
看门狗简介
看门狗,又叫 watchdog,从本质上来说就是一个定时器电路,一般有一个输入和一个输出,其中输入叫做喂狗,输出一般连接到另外一个部分的复位端,一般是连接到单片机。 看门狗的功能是定期的查看芯片内部的情况,一旦发生错误就向芯片发出重启信号。看门狗命令在程序的中断中拥有最高的优先级。
——百度百科
RK3568 带有两个看门狗,一个普通看门狗和一个安全看门狗(本文将操作普通看门狗),
在 Linux 中,看门狗设备位于 /dev,名称通常为 watchdogx(x 为数字编号),如我所用的 iTOP-3568 的 /dev 目录有 watchdog 和 watchdog0,这里的 watchdog 是默认看门狗设备(其实就是 watchdog0)。
看门狗编程命令(方法)
应用层通过 ioctl() 来操作底层看门狗设备(ioctl 在之前的驱动笔记已经学习,这里不作介绍),下面是一些常用的看门狗控制命令:
ioctl 命令 | 作用 |
---|---|
WDIOC_SETOPTIONS | 用于开启或者关闭看门狗 |
WDIOC_KEEPALIVE | 喂狗 |
WDIOC_SETTIMEOUT | 设置超时时间 |
WDIOC_GETTIMEOUT | 获取超时时间 |
接下来将对这些命令进行简单介绍:
开启和关闭看门狗
开启和关闭看门狗需要调用如下函数:
ioctl(int fd, WDIOC_SETOPTIONS, int *option);
开启和关闭 option 的宏定义如下:
#define WDIOS_DISABLECARD 0x0001
#define WDIOS_ENABLECARD 0x0002
设置超时时间
调用下面的函数可以设置当前看门狗设备的超时时间,
ioctl(int fd, WDIOC_SETTIMEOUT, int *timeout);
获取超时时间
调用下面的函数可以获取当前看门狗设备的超时时间,
ioctl(int fd, WDIOC_GETTIMEOUT, int *timeout);
喂狗
喂狗操作:
ioctl(int fd, WDIOC_KEEPALIVE, NULL);
在看门狗定时器到达超时时间前,需要进行喂狗(可以重置看门狗定时时间),不然看门狗超时后会导致系统复位或产生中断信号。
看门狗底层简析
只分析驱动层看门狗涉及的文件,不讲原理
在 rk3568 SDK 的内核代码中,看门狗的驱动文件位于 kernel/drivers/watchdog 目录下,主要涉及的驱动文件包括 watchdog_dev.c,watchdog_core.c 和 dw_wdt.c,前两个是看门狗通用驱动(在 menuconfig 中使能看门狗后,前两个驱动文件便被编进内核中),dw_wdt.c 是专属驱动(dw 全称为 Synopsys DesignWare,)
上文介绍的 ioctl() 接口,其对应的驱动代码就在 watchdog_dev.c 中,该驱动文件还包括看门狗杂项设备的注册、文件描述符成员函数定义(open、write…)等等内容。
而 dw_wdt.c 是一个平台驱动文件,它能通过与平台设备(或设备树)匹配,获得寄存器地址、时钟等数据,操作底层看门狗设备。
iTOP-3568 的设备树中看门狗节点信息如下:
设备树描述了看门狗的寄存器、时钟和中断等属性,0xfe600000 为 RK3568 普通看门狗的寄存器首地址:
看门狗编程实验
实验代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
#define WDT_DEV "/dev/watchdog0"
int main(int argc, char** argv)
{
int fd;
int ret = 0;
int option;
int timeout = 0, feed_time = 0;
// 参数判断
if(argc != 3)
{
printf("the right format: ./app timout feed_time.\n");
return 0;
}
// 打开看门狗设备节点
fd = open(WDT_DEV, O_RDWR);
if(fd < 0)
{
printf("%s open failed.\n", WDT_DEV);
return 0;
}
printf("%s open successfully.\n", WDT_DEV);
// 关闭看门狗定时器(设备打开后会自动计时)
option = WDIOS_DISABLECARD;
ret = ioctl(fd, WDIOC_SETOPTIONS, &option);
if(ret < 0)
{
printf("set option failed.\n");
return 0;
}
printf("set option successfully.\n");
// 设置超时时间
timeout = atoi(argv[1]);
ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
if(ret < 0)
{
printf("set timeout failed.\n");
return 0;
}
printf("set timeout successfully.\n");
// 喂狗时间
feed_time = atoi(argv[2]);
// 开启看门狗定时器
option = WDIOS_ENABLECARD;
ret = ioctl(fd, WDIOC_SETOPTIONS, &option);
if(ret < 0)
{
printf("set option failed.\n");
return 0;
}
printf("set option successfully.\n");
// 循环喂狗
while(feed_time)
{
// 喂狗操作
ret = ioctl(fd, WDIOC_KEEPALIVE, NULL);
if(ret < 0)
{
printf("feed dog failed.\n");
return 0;
}
printf("feed dog successfully.\n");
sleep(feed_time); // 喂狗间隔时间
}
// 关闭设备文件
close(fd);
return 0;
}
实验结果:
设置看门狗定时器的超时时间和喂狗时间 feed_time 后,程序每隔 feed_time 秒喂一次狗,如果 feed_time 小于超时时间,或者程序退出后(程序代码中没有关闭看门狗),系统会重启。