rtthread studio与正点原子apollo[15]--设备IO注册
前言
RT-Thread官方提供大部分设备的标准接口,如UART,ADC,I2C总线等,但并不是所有的设备,当我们所使用的设备在RT-Thread中未定义时,就需要按照RT-Thread提供的I/O 设备模型框架创建并注册自己的I/O设备,注册后的设备可以调用标准的I/O设备接口函数对设备进行相应的操作。
IO设备模型的介绍参考RT-Thread官方文档
I/O设备模型
一、I/O设备模型
RT-Thread 提供了的 I/O 设备模型框架共分成三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。
1、I/O 设备管理层实现了对设备驱动程序的封装。
用户通过标准的接口函数访问设备,而这些函数就是由I/O设备管理层封装的,相关的接口函数在rtthread\src\device.c文件中定义
//查找设备
rt_device_t rt_device_find(const char *name);
//初始化设备
rt_err_t rt_device_init (rt_device_t dev);
//打开设备
rt_err_t rt_device_open (rt_device_t dev, rt_uint16_t oflag);
//关闭设备
rt_err_t rt_device_close(rt_device_t dev);
//设备读
rt_size_t rt_device_read (rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size);
//设备写
rt_size_t rt_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size);
//设备控制
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg);
//接收回调
rt_err_t rt_device_set_rx_indicate(rt_device_t dev,rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size));
//发送回调
rt_err_t rt_device_set_tx_complete(rt_device_t dev,rt_err_t (*tx_done)(rt_device_t dev, void *buffer));
2、设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。
这部分代码存储在工程目录\rt-thread\components\drivers下,在启动相应功能后,代码会自动加载到工程中,如串口是工程默认开启的,因此工程中的配置如下
3、设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。负责创建和注册 I/O 设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到 I/O 设备管理器中。
功能代码存储位置:工程目录\drivers\下,如串口代码通过注册函数注册到系统,并实现了初始化等功能
二、I/O设备创建注册过程
I/O设备的注册有两种模式:
1、不经过设备驱动框架,直接注册到 I/O 设备管理器中
(1)创建设备—>(2)直接向I/O设备管理层注册设备—>(3)使用设备
2、设备实例先注册到对应的设备驱动框架中,再由设备驱动框架向 I/O 设备管理器进行注册
(1)创建设备—>(2)根据特定设备模型创建设备实例—>(3)向I/O设备管理层注册设备—>(4)使用设备
创建设备
可以通过静态申明的方式创建设备实例,也可以用接口进行动态创建。
例如RT-tThread对IO引脚和串口设备的创建采用的是静态申明的方式
//静态创建pin设备对象
static struct rt_device_pin _hw_pin;
//静态创建串口设备对象
struct rt_serial_device *serial;
动态创建接口
//动态创建一个特定类型的设备,返回类型是 rt_device_t
rt_device_t rt_device_create(int type, int attach_size);
其中设备类型在rtdef.h文件中枚举定义,类型非常丰富,可以根据需要定义
enum rt_device_class_type
{
RT_Device_Class_Char = 0, /**< character device */
RT_Device_Class_Block, /**< block device */
RT_Device_Class_NetIf, /**< net interface */
RT_Device_Class_MTD, /**< memory device */
RT_Device_Class_CAN, /**< CAN device */
RT_Device_Class_RTC, /**< RTC device */
RT_Device_Class_Sound, /**< Sound device */
RT_Device_Class_Graphic, /**< Graphic device */
RT_Device_Class_I2CBUS, /**< I2C bus device */
RT_Device_Class_USBDevice, /**< USB slave device */
RT_Device_Class_USBHost, /**< USB host bus */
RT_Device_Class_USBOTG, /**< USB OTG bus */
RT_Device_Class_SPIBUS, /**< SPI bus device */
RT_Device_Class_SPIDevice, /**< SPI device */
RT_Device_Class_SDIO, /**< SDIO bus device */
RT_Device_Class_PM, /**< PM pseudo device */
RT_Device_Class_Pipe, /**< Pipe device */
RT_Device_Class_Portal, /**< Portal device */
RT_Device_Class_Timer, /**< Timer device */
RT_Device_Class_Miscellaneous, /**< Miscellaneous device */
RT_Device_Class_Sensor, /**< Sensor device */
RT_Device_Class_Touch, /**< Touch device */
RT_Device_Class_PHY, /**< PHY device */
RT_Device_Class_Security, /**< Security device */
RT_Device_Class_Unknown /**< unknown device */
};
创建设备时,需要提供访问设备的操作方法,操作方法被定义成一组函数指针结构体,同样在rtdef.h文件中
struct rt_device_ops
{
/* common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
};
注册设备
设备创建成功后还必须注册设备才能正常使用,注册设备实际上就是给定设备访问名称并与创建的设备对象关联,并指明设备操作模式
rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags);
设备注册后就可以使用标准的I/O设备访问接口进行操作了,当设备不需要使用时可以注销或销毁
rt_err_t rt_device_unregister(rt_device_t dev);
void rt_device_destroy(rt_device_t device);
三、I/O设备注册实例
设备注册代码参考如下
//设备句柄
static rt_device_t test_dev;
int test_dev_Create(void)
{
//注册设备为字符设备
test_dev = rt_device_create(RT_Device_Class_Char,0);
if (test_dev != RT_NULL) {
//设备注册成功,添加设备方法
test_dev->init = test_dev_Init;
test_dev->open = test_dev_Open;
test_dev->close = test_dev_Close;
test_dev->read = test_dev_Read;
test_dev->write = test_dev_Write;
rt_device_register(test_dev,"test_dev", RT_DEVICE_FLAG_RDWR);
}
return 0;
}
INIT_DEVICE_EXPORT(test_dev_Create);
其中的设备方法需要以函数的形式提供
如
rt_err_t test_dev_Init(rt_device_t dev)
{
//这里根据实际设备添加代码,如stm32可以将cubemx生成的初始化代码在此加载
rt_kprintf("test_dev_Init test!\n");
return E_OK;
}
其他操作函数根据功能依次实现即可。