RTT小师弟 · 2021年04月19日

RT-Thread 内核学习笔记 - 设备模型rt_device的理解

RT-Thread 内核学习笔记 - 内核对象rt_object

RT-Thread 内核学习笔记 - 内核对象管理

RT-Thread 内核学习笔记 - 内核对象操作API

RT-Thread 内核学习笔记 - 内核对象初始化链表组织方式

RT-Thread 内核学习笔记 - 内核对象链表结构深入理解

RT-Thread 内核学习笔记 - 设备模型rt_device的理解

RT-Thread 内核学习笔记 - 理解defunct僵尸线程

前言

  • 最近在看内核源码,暂时避开费脑力的任务调度、内存管理等较复杂的实现方法,发现rt_device设备框架实现很简单。
  • rt_device,设备管理的框架(模型),提供标准的设备操作接口API,一些外设,可以抽象成设备,进行统一的管理操作,如LCD、Touch、Sensor等。

rt_device的结构

  • rt_device,是内核对象派生出来的,因此,有些操作,就是在操作内核对象。上几篇笔记研究内核对象的管理,现在发现,看device.c文件,很容易能看懂。

device.png

rt_device_class_type.png

rt_device的使用

  • RT-Thread 的PIN、CAN、Serial、I2C、SPI、PM等,都抽象成一种设备模型。这些设备模型,派生于rt_device即可。

pin设备模型:结构如下:

/* pin device and operations for RT-Thread */
struct rt_device_pin
{
    struct rt_device parent; /* 派生于rt_device */
    const struct rt_pin_ops *ops; /* 设备特有的操作接口,还可以根据需要增加其他成员 */
};
  • 所以用户可以派生自己想要的设备框架,增加特定设备的操作接口:ops,特定属性:结构体成员。
  • 需要把具体的设备,注册到内核容器上,这里调用rt_device的注册接口。

如:

/* 使用时,需要把设备名称、操作接口等,传入 */
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _hw_pin.parent.type         = RT_Device_Class_Miscellaneous; /* 设备类型,为了区分设备种类 */
    _hw_pin.parent.rx_indicate  = RT_NULL; /* 接收回调,串口、CAN一般会有 */
    _hw_pin.parent.tx_complete  = RT_NULL; /* 发送回调,串口、CAN一般会有 */

#ifdef RT_USING_DEVICE_OPS
    _hw_pin.parent.ops          = &pin_ops;
#else
    _hw_pin.parent.init         = RT_NULL; /* 以下标准的rt_device设备操作接口,根据需要实现 */
    _hw_pin.parent.open         = RT_NULL;
    _hw_pin.parent.close        = RT_NULL;
    _hw_pin.parent.read         = _pin_read;
    _hw_pin.parent.write        = _pin_write;
    _hw_pin.parent.control      = _pin_control;
#endif

    _hw_pin.ops                 = ops;  /* 操作接口,设备的特有操作接口 */
    _hw_pin.parent.user_data    = user_data; /* 不是必要的用户数据 */

    /* register a character device */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);  /* 设备注册接口:注册为具体设备 */

    return 0;
}
  • 具体设备对接设备框架
/* 具体设备的OPS 实现 */
const static struct rt_pin_ops _stm32_pin_ops =
{
    stm32_pin_mode,
    stm32_pin_write,
    stm32_pin_read,
    stm32_pin_attach_irq,
    stm32_pin_dettach_irq,
    stm32_pin_irq_enable,
};

/* 实际设备的注册方法 */
rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
  • 设备注册后,可以通过:list_device查看

其他

  • rt_device_read rt_device_write等操作前,需要:rt_device_open
  • rt_device_open rt_device_close 操作最好成对出现,原因是rt_device内部有引用计数,如你open两次,close一次,计数为1,没有真正的close。
  • 一般通过rt_device_find,通过设备名称,查找设备,获取设备的操作句柄,也就是设备结构体指针,从而可以进一步进行操作设备的操作接口ops或通过设备的标准操作接口操作设备。
  • RT-Thread 的设备类型很多,可以派生各种设备模型(框架),从而可以注册挂载很多设备上去,可以方便的实现读写控制等操作,如控制硬件、传感器等。

总结

  • 设备派生于内核对象:rt_object,熟悉内核对象,有利于熟悉rt_device的操作
  • 继续研究RT-Thread内核,不断学习,收获很多。
推荐阅读
关注数
8071
内容数
181
小而美的物联网操作系统,经过14年的累积发展,RT-Thread 已经拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量超过4亿台,成为国人自主开发、国内最成熟稳定和装机量最大的开源 RTOS。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息