这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » rtthread看门狗框架分析

共4条 1/1 1 跳转至

rtthread看门狗框架分析

高工
2025-02-09 10:48:57     打赏

       看门狗,是一个确保嵌入式平台稳定性的必要措施,虽然正常操作不应触发看门狗,但在一些特殊场景,比如ESD等情况导致的系统跑飞,就需要看门狗做复位了。

源码分析

源码路径

components\drivers\watchdog\watchdog.c

注册入口

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops wdt_ops =
{
    rt_watchdog_init,
    rt_watchdog_open,
    rt_watchdog_close,
    RT_NULL,
    RT_NULL,
    rt_watchdog_control,
};
#endif

rt_err_t rt_hw_watchdog_register(struct rt_watchdog_device *wtd,
                                 const char                *name,
                                 rt_uint32_t                flag,
                                 void                      *data)
{
    struct rt_device *device;
    RT_ASSERT(wtd != RT_NULL);

    device = &(wtd->parent);

    device->type        = RT_Device_Class_WDT;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    device->ops         = &wdt_ops;
#else
    device->init        = rt_watchdog_init;
    device->open        = rt_watchdog_open;
    device->close       = rt_watchdog_close;
    device->read        = RT_NULL;
    device->write       = RT_NULL;
    device->control     = rt_watchdog_control;
#endif
    device->user_data   = data;

    return rt_device_register(device, name, flag);
}

     查看了这么多设备驱动,其实我们会发现,注册接口其实都差不多,基本上就设置设备类型,指定device的操作函数表(不同类型设备实现方法不一),之后注册设备。唯一可能有差异的是部分设备,框架层存在一些操作,需要初始化一些框架层维护的数据。看门狗设备也不例外符合这么个规律。

初始化入口

static rt_err_t rt_watchdog_init(struct rt_device *dev)
{
    rt_watchdog_t *wtd;

    RT_ASSERT(dev != RT_NULL);
    wtd = (rt_watchdog_t *)dev;
    if (wtd->ops->init)
    {
        return (wtd->ops->init(wtd));
    }

    return (-RT_ENOSYS);
}

     从初始化入口看,基本上看门狗框架本身不维护任何信息,所有信息的维护都是交由驱动自己维护了。

打开入口

static rt_err_t rt_watchdog_open(struct rt_device *dev, rt_uint16_t oflag)
{
    return (RT_EOK);
}

     看起来这个入口并没有实现任何功能,而实际上,这个函数所实现的功能已通过control接口实现,而不知为何open函数未调用control实现的接口。

关闭入口

static rt_err_t rt_watchdog_close(struct rt_device *dev)
{
    rt_watchdog_t *wtd;

    RT_ASSERT(dev != RT_NULL);
    wtd = (rt_watchdog_t *)dev;

    if (wtd->ops->control(wtd, RT_DEVICE_CTRL_WDT_STOP, RT_NULL) != RT_EOK)
    {
        rt_kprintf(" This watchdog can not be stoped\n");

        return (-RT_ERROR);
    }

    return (RT_EOK);
}

      关闭入口需要驱动实现control中的RT_DEVICE_CTRL_WDT_STOP,具体功能是停止看门狗功能。

控制入口

static rt_err_t rt_watchdog_control(struct rt_device *dev,
                                    int              cmd,
                                    void             *args)
{
    rt_watchdog_t *wtd;

    RT_ASSERT(dev != RT_NULL);
    wtd = (rt_watchdog_t *)dev;

    return (wtd->ops->control(wtd, cmd, args));
}

     控制入口的实现,算是现在看的这么多驱动之中,实现最为迷惑的部分了,从实现上看,看不出任何对驱动层的实现要求,但实际上,还是有要求的,这些要求需要跳转到看门狗的头文件中查看。

#define RT_DEVICE_CTRL_WDT_GET_TIMEOUT    (RT_DEVICE_CTRL_BASE(WDT) + 1) /* 获取秒级的超时时间 */
#define RT_DEVICE_CTRL_WDT_SET_TIMEOUT    (RT_DEVICE_CTRL_BASE(WDT) + 2) /* 设置秒级的超时时间 */
#define RT_DEVICE_CTRL_WDT_GET_TIMELEFT   (RT_DEVICE_CTRL_BASE(WDT) + 3) /* 获取秒级的剩余时间(至重启) */
#define RT_DEVICE_CTRL_WDT_KEEPALIVE      (RT_DEVICE_CTRL_BASE(WDT) + 4) /* 刷新看门狗计时 */
#define RT_DEVICE_CTRL_WDT_START          (RT_DEVICE_CTRL_BASE(WDT) + 5) /* 启动看门狗 */
#define RT_DEVICE_CTRL_WDT_STOP           (RT_DEVICE_CTRL_BASE(WDT) + 6) /* 关闭看门狗 */

      这些变量就是control接口的参数cmd,也就是说,驱动需要实现这些入口。

总结

    至此,我们基本上可以梳理出驱动层的看门狗实现框架。即:

#include <board.h>

#ifdef RT_USING_WDT

//#define DRV_DEBUG
#define LOG_TAG             "drv.wdt"
#include <drv_log.h>

struct wdt_obj
{
    rt_watchdog_t watchdog;
    // TODO: wdt inside param
};

static rt_err_t wdt_init(rt_watchdog_t *wdt)
{
    return RT_EOK;
}

static rt_err_t wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
{
    switch (cmd)
    {
    case RT_DEVICE_CTRL_WDT_KEEPALIVE:
        // TODO: 执行喂狗动作 
        break;
        /* set watchdog timeout */
    case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
        // TODO:设置看门狗超时时间
        break;
    case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
        // TODO:获取设置的超时时间
        break;
    case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
        // TODO:获取看门狗的剩余计时
        break;
    case RT_DEVICE_CTRL_WDT_START:
        // TODO:启动看门狗
        break;
    case RT_DEVICE_CTRL_WDT_STOP:
        // TODO:关闭看门狗
        break;
    default:
        LOG_W("This command is not supported.");
        return -RT_ERROR;
    }
    return RT_EOK;
}

static struct rt_watchdog_ops ops =
{
    .init = wdt_init,
    .control = wdt_control,
};

int rt_wdt_init(void)
{
    struct wdt_obj *wdt;
    
    wdt =  (struct wdt_obj *)rt_malloc(sizeof(struct wdt_obj));
    if(wdt == RT_NULL)
    {
        LOG_E("wdt device malloc failed.");
        return -RT_ERROR;
    }
    wdt.watchdog.ops.ops = &ops;
    if (rt_hw_watchdog_register(&wdt.watchdog, "wdt", RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
    {
        LOG_E("wdt device register failed.");
        return -RT_ERROR;
    }
    LOG_D("wdt device register success.");
    return RT_EOK;
}
INIT_BOARD_EXPORT(rt_wdt_init);

#endif /* RT_USING_WDT */



关键词: rtthread     看门狗     框架     分析     watchd    

专家
2025-02-09 18:52:31     打赏
2楼

谢谢分享


专家
2025-02-09 18:53:30     打赏
3楼

谢谢分享


专家
2025-02-09 18:55:07     打赏
4楼

谢谢分享


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]