RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP,内置NPU,支持INT4/INT8/INT16/FP16混合运算能力,支持安卓12和、Debian11、Build root、Ubuntu20和22版本登系统。了解更多信息可点击迅为官网
【粉丝群】824412014
【实验平台】:迅为RK3588开发板
【内容来源】《iTOP-3588开发板系统编程手册》
【全套资料及网盘获取方式】联系淘宝客服加入售后技术支持群内下载
【视频介绍】:【强者之芯】 新一代AIOT高端应用芯片 iTOP -3588人工智能工业AI主板
第15章 看门狗应用编程
15.1看门狗介绍
看门狗(Watchdog)是一种用于检测系统异常的硬件或软件。在计算机系统中,看门狗通常是一个独立的计时器或电路,它能够周期性地计数或检测系统的某些特定状态,例如某个程序是否在规定的时间内执行完毕,是否有输入输出操作等等,如果系统出现了异常情况,比如程序崩溃,系统死锁等等,看门狗将会检测到这种异常情况,并触发一些预定义的处理方式,例如重新启动系统,发送警报等等,以保证系统的稳定性和可靠性。
硬件看门狗通常是一个计时器芯片,它会定期向系统发送脉冲信号,如果系统在一定时间内没有对这个信号做出响应,看门狗将会认为系统出现了故障,并触发相应的处理。在嵌入式系统中,看门狗通常由一个硬件模块和一个软件模块组成,硬件模块负责生成定时器信号,而软件模块则负责检测系统状态并重置计时器。
而在嵌入式系统中,看门狗通常是非常重要的一部分,因为它可以保证系统的可靠性和稳定性。看门狗可以用于检测和解决系统中的各种问题,例如程序崩溃、死循环、死锁、硬件故障等等。看门狗还可以用于提高系统的安全性,例如防止黑客攻击、保护系统不被病毒侵袭等等。
RK3588集成了两个看门狗定时器(WDOG):WDOG1 和 WDOG2;WDOG2 用于安全目的,而 WDOG1 则是一个普通的看门狗,支持产生中断信号以及复位 CPU。
Linux 系统中所注册的看门狗外设,都会在/dev/目录下生成对应的设备节点(设备文件),设备节点名称通常为 watchdogX(X 表示一个数字编号 0、1、2、3 等),譬如/dev/watchdog0、/dev/watchdog1 等,通过这些设备节点可以控制看门狗外设。
修改设备树topeet_rk3588_config.dtsi在最后添加以下内容:
&wdt {
status = "okay";
};
重新编译并烧写内核,开发板系统启动之后使用以下命令进行看门狗设备的查看,如下图所示:
ls /dev/watchdog* -l
从上图可以看到总共有两个看门狗相关的节点,/dev/watchdog和/dev/watchdog0,/dev/watchdog0为RK3588的 WDOG1 所对应的设备节点,而/dev/watchdog 设备节点则代表系统默认的看门狗设备,通常就是指 watchdog0。
15.2 ioctl函数
由于在之后的章节中会频繁用到ioctl函数,所以在本小节将对ioctl 函数进行介绍。
ioctl() 函数是 Unix-like 操作系统中用于与设备驱动程序交互的系统调用之一。它的名字来自于 input/output control 的缩写,用于向设备驱动程序传递控制命令和参数,以便进行各种操作,如配置设备、查询状态、发送/接收数据等等。
ioctl() 函数所需头文件和函数原型如下所示:
所需头文件 | 函数原型 | |
1 | #include <sys/ioctl.h> | int ioctl(int fd, unsigned long request, ...); |
其中,fd 是设备的文件描述符,request 是请求的命令码,后面的参数是可选的命令参数。request 是一个无符号长整型数,通常使用宏定义来定义命令码,宏定义通常被包含在一个对应设备驱动程序的头文件中。
ioctl() 函数的功能和使用方式比较灵活,它可以接受任何类型的参数,包括指针、结构体、整型等等。具体来说,request 参数通常用于指定一个特定的操作,... 参数用于传递操作所需的数据。
设备驱动程序需要实现一个 ioctl 函数来处理传递过来的命令。在 ioctl 函数中,根据 request 参数的值进行相应的操作,对数据进行读取、写入等等。设备驱动程序必须将所有可能的命令编码成数字,并根据 request 参数的值进行判断,以执行相应的操作(如果想要了解ioctl函数在驱动程序中是如何实现的,可以学习迅为提供的驱动相关的视频)。
ioctl 函数的实际用法通常与特定的设备和操作有关。例如,在网络编程中,ioctl 可以用于获取或设置网络接口卡的状态、MAC 地址、MTU 等信息;在字符设备编程中,ioctl 可以用于设置终端属性、查询设备状态等等。在一些应用程序中,也会使用 ioctl 函数与设备驱动程序进行交互。
15.3看门狗的使用
关于Linux系统编程中看门狗使用步骤如下表所示:
步骤 | 描述 |
打开设备文件 | 通过 open() 函数打开看门狗设备文件,获取文件描述符 |
配置参数 | 使用 ioctl() 函数调用 WDIOC_SETTIMEOUT设置看门狗超时时间 |
启动看门狗 | 通过 ioctl() 函数调用 WDIOC_SETOPTIONS启动看门狗 |
定时喂狗 | 在超时时间内通过 ioctl() 函数调用 WDIOC_KEEPALIVE喂狗,重置看门狗计数器 |
停止看门狗 | 在不需要看门狗保护的情况下,通过ioctl()函数调用WDIOC_SETOPTIONS停止看门狗 |
关闭设备文件 | 通过 close() 函数关闭看门狗设备文件 |
其中对于打开和关闭设备文件我们已经很熟悉了,这里就不再进行介绍,本小节主要介绍ioctl函数对于看门狗的控制部分。
看门狗关于ioctl函数指令宏定义在头文件<linux/watchdog.h>中,每一个不同的指令宏表示向设备请求不同的操作,如下所示:
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
下面将根据看门狗的使用步骤,对部分ioctl指令进行对应的讲解。
(1)设置超时时间
设置看门狗的超时时间可以使用ioctl指令和WDIOC_SETTIMEOUT请求代码。使用该指令需要传入一个指向unsigned int类型变量的指针,表示新的超时时间,单位为毫秒。需要注意的是,设置的超时时间必须在看门狗设备支持的超时时间范围内。
例如可以使用以下代码将看门狗超时时间设置为10s:
unsigned int timeout = 10000; // 设置10秒超时时间
int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
(2) 获取超时时间
获取看门狗的超时时间可以使用ioctl指令和WDIOC_GETTIMEOUT请求代码。使用该指令将返回当前的超时时间,单位为毫秒。
例如可以使用以下代码获取看门狗的超时时间:
1
2 int timeout = ioctl(fd, WDIOC_GETTIMEOUT, NULL);
printf("Watchdog timeout: %d ms\n", timeout);
- 开启和关闭看门狗
开启和关闭看门狗都是使用ioctl指令和WDIOC_SETOPTIONS请求代码,只是传入的标志位不同,开启看门狗需要传入WDOG_KEEPALIVE标志位,关闭看门狗需要传入WDIOS_DISABLECARD标志位。
int ret = ioctl(fd, WDIOC_SETOPTIONS, WDOG_KEEPALIVE);
int ret = ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
- 喂狗操作
WDIOC_KEEPALIVE:这个指令用于向看门狗发送喂狗信号,避免看门狗超时。例如,可以使用以下代码喂狗:
ioctl(int fd, WDIOC_KEEPALIVE, NULL);
至此,关于看门狗使用的一些ioctl指令宏的讲解就结束了,将在下一小节进行看门狗的实际实验。
15.4看门狗实验
本小节代码在配套资料“iTOP-3588开发板\03_【iTOP-RK3588开发板】指南教程\03_系统编程配套程序\65”目录下,如下图所示:
实验要求:
开启看门狗,并通过main函数传参设置看门狗超时时间。
15.4.1编写应用程序
实验步骤:
首先进入到ubuntu的终端界面输入以下命令来创建 demo65_watchdog.c文件,如下图所示:
vim demo65_watchdog.c
然后向该文件中添加以下内容:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
int main(int argc, char *argv[])
{
int fd, timeout;
if (argc != 2) // 检查参数个数是否正确
{
printf("使用方法:%s <超时时间>\n", argv[0]);
return -1;
}
timeout = atoi(argv[1]); // 将字符串类型的超时时间转换成整型
if (timeout < 1 || timeout > 3600) // 检查超时时间是否合法
{
printf("超时时间应在1到3600秒之间。\n");
return -1;
}
fd = open("/dev/watchdog", O_RDWR); // 打开看门狗设备文件
if (fd < 0) // 检查打开是否成功
{
printf("打开看门狗设备文件失败。\n");
return -1;
}
ioctl(fd, WDIOC_SETTIMEOUT, &timeout); // 设置看门狗超时时间
ioctl(fd, WDIOC_KEEPALIVE, 0); // 喂狗操作
ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD); // 开启看门狗
printf("看门狗已启用,超时时间为 %d 秒。\n", timeout);
while (1) // 进入死循环
{
sleep(1);
}
return 0;
}
保存退出之后,使用以下命令设置交叉编译器环境,并对demo101_watchdog.c进行交叉编译,编译完成如下图所示:
export PATH=/usr/local/arm64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH
aarch64-none-linux-gnu-gcc -o demo65_watchdog demo65_watchdog.c
最后将交叉编译生成的demo65_watchdog文件拷贝到/home/nfs共享目录下即可。
15.4.2开发板测试
Buildroot系统启动之后,首先使用以下命令进行nfs共享目录的挂载(其中192.168.1.7为作者ubuntu的ip地址,需要根据自身ubuntu的ip来设置),如下图所示:
mount -t nfs -o nfsvers=3,nolock 192.168.1.7:/home/nfs /mnt
nfs共享目录挂载到了开发板的/mnt目录下,进入到/mnt目录下,如下图所示:
可以看到/mnt目录下的demo65_watchdog文件已经存在了,然后使用以下命令设置超时时间为5S,如下图所示:
./demo65_watchdog 5
5秒钟之后,由于没有进行喂狗操作,所以系统会重启。至此看门狗应用实验就完成了。