4

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

 3 years ago
source link: https://my.oschina.net/u/4428324/blog/5023646
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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内核,不断学习,收获很多。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK