设计说明
源码说明
源代码位于:
-
bsp/artinchip/drv/wdt/drv_wdt.c,WDT Driver 层实现
-
bsp/artinchip/hal/wdt/hal_wdt.c,WDT HAL 层实现
-
bsp/artinchip/include/hal/hal_wdt.h,WDT HAL 层接口头文件
-
bsp/artinchip/include/drv/aic_drv_wdt.h,WDT DRV 层头文件
模块架构
WDT 驱动 Driver 层采用 RT-Thread 的 Watchdog 设备驱动框架,如果只使用 HAL 层也可以支持 baremetal 方式的应用场景。

针对 Watchdog 控制器的几个特色功能:
-
- 多通道
-
暂时只提供一个 Watchdog 设备 (对应通道 0)。
-
- 超时中断
-
在 Watchdog 超时之前可以产生一些中断信号,让软件有机会做一些预处理。
-
- 清零窗口
-
清零窗口设置范围为 0~3,看门狗在设置范围内不能 clean 计数。
-
- 调试模式的计数状态
-
当 CPU 进入 Jtag 的 debug 状态时,Watchdog 计数可以选择是否暂停,默认暂停。
暂未提供设置接口。
关键流程设计
初始化流程
通过调用 INIT_DEVICE_EXPORT(rt_hw_wdt_init)
宏定义,可以导出 WDT 驱动的初始化接口。通过调用
Watchdog 子系统的接口 rt_hw_watchdog_register() 注册一个 Watchdog 设备,将具体的
Watchdog 驱动程序与系统关联起来。
在 drv_wdt_init() 接口中实现 WDT 控制器的初始化流程放,主要步骤如下:
-
初始化模块的时钟 (clk)。
-
注册中断。
数据结构设计
Watchdog 数据类型及其结构描述如下:
-
struct aic_wdt_dev属于 Driver 层接口,记录 Watchdog 控制器的配置信息:
struct aic_wdt_dev { rt_watchdog_t wdt; struct aic_wdt chan; s32 dbg_continue; u32 cur_chan; };
-
struct aic_wdt属于 HAL 层接口,记录每一个 Watchdog 通道的配置信息:
struct aic_wdt { u32 clr_thd; u32 irq_thd; u32 rst_thd; };
接口设计
以下接口是 Watchdog 子系统需要的标准接口。
Driver 层接口设计
struct rt_watchdog_ops { rt_err_t (*init)(rt_watchdog_t *wdt); rt_err_t (*control)(rt_watchdog_t *wdt, int cmd, void *arg); };
函数原型 |
rt_err_t drv_wdt_init(rt_watchdog_t *wdt) |
---|---|
功能说明 |
Watchdog 控制器的初始化 |
参数定义 |
无 |
返回值 |
0,成功;<0,失败 |
注意事项 |
- |
函数原型 |
rt_err_t drv_wdt_control(rt_watchdog_t *wdt, int cmd, void *args) |
---|---|
功能说明 |
Watchdog 驱动的 ioctl 接口 |
参数定义 |
wdt - 指向 Watchdog 设备
cmd - ioctl 命令码
args - ioctl 命令相应的参数
|
返回值 |
0,成功;<0,失败 |
注意事项 |
- |
CMD 命令码定义
CMD 命令码可以用于控制 Watchdog 的行为,例如设置超时时间、获取剩余时间、刷新看门狗等。CMD 命令码详细定义描述如下:
- 标准命令码:
#define RT_DEVICE_CTRL_WDT_GET_TIMEOUT (RT_DEVICE_CTRL_BASE(WDT) + 1) /* get timeout(in seconds) */ #define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (RT_DEVICE_CTRL_BASE(WDT) + 2) /* set timeout(in seconds) */ #define RT_DEVICE_CTRL_WDT_GET_TIMELEFT (RT_DEVICE_CTRL_BASE(WDT) + 3) /* get the left time before reboot(in seconds) */ #define RT_DEVICE_CTRL_WDT_KEEPALIVE (RT_DEVICE_CTRL_BASE(WDT) + 4) /* refresh watchdog */ #define RT_DEVICE_CTRL_WDT_START (RT_DEVICE_CTRL_BASE(WDT) + 5) /* start watchdog */ #define RT_DEVICE_CTRL_WDT_STOP (RT_DEVICE_CTRL_BASE(WDT) + 6) /* stop watchdog */
详见 rt-thread/components/drivers/include/watchdog.h。
- AIC
特定的命令码
#define RT_DEVICE_CTRL_WDT_SET_IRQ_TIMEOUT (RT_DEVICE_CTRL_BASE(WDT) + 7) /* set pretimeout(in seconds) */ #define RT_DEVICE_CTRL_WDT_IRQ_ENABLE (RT_DEVICE_CTRL_BASE(WDT) + 8) /* start pretreatment */ #define RT_DEVICE_CTRL_WDT_IRQ_DISABLE (RT_DEVICE_CTRL_BASE(WDT) + 9) /* stop pretreatment */ #define RT_DEVICE_CTRL_WDT_SET_CLR_THD (RT_DEVICE_CTRL_BASE(WDT) + 10) /* set clear threshold */
详见 bsp/arcinchip/include/drv/aic_drv_wdt.h。
HAL 层接口设计
void hal_wdt_op_clr(u32 thd); s32 hal_wdt_is_running(void); void hal_wdt_clr_thd_set(u32 ch, struct aic_wdt *wdt); void hal_wdt_irq_thd_set(u32 ch, struct aic_wdt *wdt); void hal_wdt_rst_thd_set(u32 ch, struct aic_wdt *wdt); void hal_wdt_switch_chan(int chan); u32 hal_wdt_remain(struct aic_wdt *wdt); void hal_wdt_enable(u32 enable, u32 dbg_continue); void hal_wdt_irq_enable(u32 enable); int hal_wdt_irq_sta(void); void hal_wdt_thd_get(u32 ch, struct aic_wdt *wdt); int hal_wdt_clr_int(void); void hal_wdt_status_show(u32 ch);
Demo
test-wdt
命令进行操作。test-wdt
的详细说明,可查看源代码文件
bsp/examples/test-wdt/test-wdt.c。本 Demo 可以作为 Watchdog
设备的使用参考:#include <rtthread.h> #include <aic_core.h> #include <drivers/watchdog.h> #include <aic_drv_wdt.h> #include <hal_wdt.h> #include <getopt.h> irqreturn_t aic_wdt_irq(int irq, void *arg) { rt_kprintf("Watchdog chan0 IRQ happened\n"); return IRQ_HANDLED; } static void idle_hook(void) { rt_device_t wdt_dev = RT_NULL; wdt_dev = rt_device_find("wdt"); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL); } static void usage(char * program) { printf("\n"); printf("Usage: %s [-s timeout] [-p pretimeout] [-c clear threshold] [-g] [-k] [-u]\n",\ program); printf("\t -s, --set-timeout\tSet a timeout, in second\n"); printf("\t -p, --set-pretimeout\tSet a pretimeout, in second\n"); printf("\t -c, --set-clear threshold\tSet clear threshold,in second(0~3)\n"); printf("\t -g, --get-timeout\tGet the current timeout, in second\n"); printf("\t -k, --keepalive\tKeepalive the watchdog\n"); printf("\t -u, --usage \n"); printf("\n"); } void test_wdt(int argc, char **argv) { int opt; int timeout = 0; rt_device_t wdt_dev = RT_NULL; wdt_dev = rt_device_find("wdt"); rt_device_init(wdt_dev); optind = 0; while ((opt = getopt(argc, argv, "s:p:c:gku")) != -1) { switch (opt) { case 'c': timeout = strtoul(optarg, NULL, 10); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_SET_CLR_THD, &timeout); rt_kprintf("set clear threshold:%d\n", timeout); break; case 's': timeout = strtoul(optarg, NULL, 10); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_START, RT_NULL); rt_kprintf("set timeout:%d\n", timeout); break; case 'g': rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_GET_TIMEOUT, &timeout); rt_kprintf("timeout:%d\n", timeout); break; case 'p': timeout = strtoul(optarg, NULL, 10); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_SET_IRQ_TIMEOUT, &timeout); rt_device_control(wdt_dev, RT_DEVICE_CTRL_WDT_IRQ_ENABLE, &aic_wdt_irq); rt_kprintf("set pretimeout:%d\n", timeout); break; case 'k': rt_thread_idle_sethook(idle_hook); rt_kprintf("feed the dog! \n"); break; case 'u': default: usage(argv[0]); } } } MSH_CMD_EXPORT_ALIAS(test_wdt, test_wdt, Reboot the system);