WATCHDOG设备
WATCHDOG简介
硬件看门狗(watchdog timer)是一个定时器,其定时输出连接到电路的复位端。在产品化的嵌入式系统中,为了使系统在异常情况下能自动复位,一般都需要引入看门狗。当看门狗启动后,计数器开始自动计数,在计数器溢出前如果没有被复位,计数器溢出就会对 CPU 产生一个复位信号使系统重启(俗称 “被狗咬”)。系统正常运行时,需要在看门狗允许的时间间隔内对看门狗计数器清零(俗称“喂狗“),不让复位信号产生。如果系统不出问题,程序能够按时“喂狗”。一旦程序发生跑飞、死锁等情况,没有“喂狗”,系统“被咬”导致复位。
驱动支持
访问WATCHDOG设备前,需要保证相关驱动配置已选中。
Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。
Linux环境:在代码根目录下执行scons --menuconfig进入配置。
WATCHDOG驱动所在路径如下:
RT-Thread Components -> Device Drivers -> Using Watch Dog device drivers
访问WATCHDOG设备
访问WATCHDOG设备,库中提供了以下接口:
函数 | 描述 |
---|---|
rt_device_find() | 根据WATCHDOG名称查找设备获取设备句柄 |
rt_device_control() | 控制WATCHDOG设备 |
查找WATCHDOG设备
查找WATCHDOG设备,函数原型如下所示:
rt_device_t rt_device_find(const char* name);
-
参数
[IN]name:WATCHDOG设备名称,目前注册到的系统中的WATCHDOG设备名称为"wdt"。
-
返回值
RT_NULL:失败,设备不存在。
非RT_NULL:成功,该返回值是操作WATCHDOG设备的句柄,在后续的接口中作为函数入参。
控制WATCHDOG设备
控制指定WATCHDOG设备,函数原型如下所示:
rt_err_t rt_device_control(rt_device_t dev, int cmd, void* arg);
-
参数
[IN]dev:WATCHDOG设备句柄,查找设备函数的返回值
[IN]cmd:命令控制字,在这里主要支持以下宏定义
// 宏定义所在文件相对路径: // rt-thread/components/drivers/include/drivers/watchdog.h #define RT_DEVICE_CTRL_WDT_GET_TIMEOUT (1) /* 获取溢出时间 */ #define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (2) /* 设置溢出时间 */ #define RT_DEVICE_CTRL_WDT_KEEPALIVE (4) /* 喂狗 */ #define RT_DEVICE_CTRL_WDT_START (5) /* 启动看门狗 */ #define RT_DEVICE_CTRL_WDT_STOP (6) /* 停止看门狗 */
[INOUT]arg:输入/输出值,类型为(rt_uint32_t *)。
-
返回值
0,正常
其他:错误,RT-Thread定义的错误类型。
WATCHDOG使用示例
使用示例需要配置menuconfig,使能例程与外设,步骤如下:
- 使能例程
Application Example Config -> Enable Watchdog Example
- 使能外设驱动
Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable WDT
以下提供WATCHDOG测试实例,测试步骤如下:
- 根据WATCHDOG设备名称,获取WATCHDOG设备句柄。
- 设置WATCHDOG输出。
#include <rtthread.h>
#ifdef APP_EXAMPLE_WATCHDOG
#ifndef RT_USING_WDT
#error "Please enable rt-thread wdt device driver"
#endif
#ifndef BSP_USING_WDT
#error "Please enable on-chip peripheral wdt config"
#endif
#include <rtdevice.h>
#include "uc_watchdog_app.h"
#define WDT_DEVICE_NAME "wdt"
#define WACHDOG_KEEP_TIMEOUT 5
static rt_device_t wdg_dev = NULL;
static void idle_watchdog_hook(void)
{
rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
}
static int watchdog_app_disable(void)
{
rt_err_t ret = RT_EOK;
ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_STOP, RT_NULL);
if (ret != RT_EOK)
{
rt_kprintf("start %s failed!\n", WDT_DEVICE_NAME);
return -RT_ERROR;
}
return ret;
}
static int watchdog_app_enable(void)
{
rt_err_t ret = RT_EOK;
ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_START, RT_NULL);
if (ret != RT_EOK)
{
rt_kprintf("start %s failed!\n", WDT_DEVICE_NAME);
return -RT_ERROR;
}
return ret;
}
static void watchdog_app_close(void)
{
watchdog_app_disable();
rt_thread_idle_delhook(idle_watchdog_hook);
}
int watchdog_app_sample(void)
{
rt_err_t ret = RT_EOK;
rt_uint32_t timeout = WACHDOG_KEEP_TIMEOUT;
rt_kprintf("watchdog_app_sample\n");
wdg_dev = rt_device_find(WDT_DEVICE_NAME);
if (!wdg_dev)
{
rt_kprintf("find %s failed!\n", WDT_DEVICE_NAME);
return -RT_ERROR;
}
ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout);
if (ret != RT_EOK)
{
rt_kprintf("set %s timeout failed!\n", WDT_DEVICE_NAME);
return -RT_ERROR;
}
rt_thread_idle_sethook(idle_watchdog_hook);
watchdog_app_enable();
rt_kprintf("enable %s success!\n", WDT_DEVICE_NAME);
rt_kprintf("current tick is %d\n", rt_tick_get());
rt_kprintf("delay wdt for %d seconds, the iddle thread will feed the dog twice\n", (WACHDOG_KEEP_TIMEOUT * 2));
rt_kprintf("current tick is %d, wait for %d seconds\n", rt_tick_get(), (WACHDOG_KEEP_TIMEOUT * 2));
rt_thread_delay((WACHDOG_KEEP_TIMEOUT * 2) * 1000);
rt_kprintf("current tick is %d\n", rt_tick_get());
rt_kprintf("The chip is dead, please wait for the watchdog to restart the chip...\n");
rt_kprintf("The watchdog will restart the chip in %d seconds...\n", WACHDOG_KEEP_TIMEOUT);
while (1)
{
;
}
return RT_EOK;
}
#endif