Edit online

设计说明

Read time: 6 minute(s)
Edit online

源码说明

Read time: 6 minute(s)

源代码位于:

  • 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 层头文件

Edit online

模块架构

Read time: 6 minute(s)

WDT 驱动 Driver 层采用 RT-Thread 的 Watchdog 设备驱动框架,如果只使用 HAL 层也可以支持 baremetal 方式的应用场景。


sw_system3

1. Watchdog 驱动的软件架构图

针对 Watchdog 控制器的几个特色功能:

  1. 多通道

    暂时只提供一个 Watchdog 设备 (对应通道 0)。

  2. 超时中断

    在 Watchdog 超时之前可以产生一些中断信号,让软件有机会做一些预处理。

  3. 清零窗口

    清零窗口设置范围为 0~3,看门狗在设置范围内不能 clean 计数。

  4. 调试模式的计数状态

    当 CPU 进入 Jtag 的 debug 状态时,Watchdog 计数可以选择是否暂停,默认暂停。

    暂未提供设置接口。

Edit online

关键流程设计

Read time: 6 minute(s)
Edit online

初始化流程

Read time: 6 minute(s)

通过调用 INIT_DEVICE_EXPORT(rt_hw_wdt_init) 宏定义,可以导出 WDT 驱动的初始化接口。通过调用 Watchdog 子系统的接口 rt_hw_watchdog_register() 注册一个 Watchdog 设备,将具体的 Watchdog 驱动程序与系统关联起来。

drv_wdt_init() 接口中实现 WDT 控制器的初始化流程放,主要步骤如下:

  1. 初始化模块的时钟 (clk)。

  2. 注册中断。

Edit online

数据结构设计

Read time: 6 minute(s)

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;
    };
Edit online

接口设计

Read time: 6 minute(s)

以下接口是 Watchdog 子系统需要的标准接口。

Edit online

Driver 层接口设计

Read time: 6 minute(s)
以下接口是 Watchdog 设备驱动框架的标准接口。
struct rt_watchdog_ops
{
    rt_err_t (*init)(rt_watchdog_t *wdt);
    rt_err_t (*control)(rt_watchdog_t *wdt, int cmd, void *arg);
};
1. drv_wdt_init

函数原型

rt_err_t drv_wdt_init(rt_watchdog_t *wdt)

功能说明

Watchdog 控制器的初始化

参数定义

返回值

0,成功;<0,失败

注意事项

-

2. drv_wdt_control

函数原型

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

Edit online

HAL 层接口设计

Read time: 6 minute(s)
HAL 层的函数接口声明存放在 hal_wdt.h 中,主要接口有:
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);
Edit online

Demo

Read time: 6 minute(s)
本 Demo 展示了如何使用 Watchdog 设备,并通过 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);