- 简介
- OneOS 在各类外设的基础上抽象出了设备驱动模型,本文将围绕驱动模型来分析I2C驱动的实现过程。
- I2C驱动以STM32为例,主要分析驱动模型中各层之间的调用关系。
- OneOS设备驱动模型见OneOS 官网(https://os.iot.10086.cn)文档驱动部分。
- I2C驱动总概
- I2C驱动框架如下图所示:
- 从图中可以看出用户可以直接访问设备统一接口和I2C设备框架层的API。
-
驱动为I2C设备提供的API见下表:
API
层
os_device_find
管理层
os_i2c_transfer
框架层
os_i2c_client_write
框架层
os_i2c_client_read
框架层
os_i2c_client_write_byte
框架层
os_i2c_client_read_byte
框架层
os_i2c_master_send
框架层
os_i2c_master_recv
框架层
- 对于不同芯片,管理层提供设备操作接口,框架层提供I2C这类设备通用的接口,驱动层提供具体芯片的I2C设备驱动程序。
- STM32系列芯片I2C驱动实现过程:
- 设备注册:
OneOS启动之后会进入到_driver_stm32_i2c_driver_init(),当执行初始化函数时,会调用到driver_match_devices()完成驱动和设备的匹配,匹配成功就会执行设备驱动层的stm32_i2c_probe()函数,在probe()函数中调用os_i2c_bus_device_register()函数,实现st的i2c设备注册到i2c总线设备中。在框架层的os_i2c_bus_device_register()函数,通过调用os_device_register()函数实现i2c总线设备挂载到内核设备链表上。
- 设备访问:
应用层通过find函数查找到设备,设备ops函数在框架层和驱动层实现,同一功能函数层层调用,调用关系如下:
os_device_read_nonblock→i2c_bus_device_read(os_i2c_master_recv)→os_i2c_transfer→stm32_i2c_transfer(调用ST系列HAL库函数)
os_device_write_block→i2c_bus_device_write(os_i2c_master_send)→os_i2c_transfer→ stm32_i2c_transfer(调用ST系列HAL库函数)
os_device_control→i2c_bus_device_control→os_i2c_transfer()→stm32_i2c_transfer(调 用ST系列HAL库函数)
- 设备管理层
设备管理层实现了对设备驱动程序的封装,是所有设备通用的函数接口,I2C设备在管理层实现设备查找和注册。
- 查找设备:os_device_find()
函数原型:os_device_t *os_device_find(const char *name)
位置:driversdevice.c
参数:name(设备名称)
返回值类型:os_device_t(返回设备指针)
注:通过os_device_find()访问设备时,只在设备管理层实现。
- os_device_find()根据传入设备的名称 “i2c1″,通过定义os_list_for_each_entry遍历设备链表os_device_list查找设备;若查找到设备,返回相应的设备指针,否则返回空指针OS_NULL。
- os_device_list的值来源于设备注册函数os_device_register()。
- 注册设备:os_device_register()
位置:driversdevice.c
参数:dev(设备指针),name(设备名称)
返回值类型:os_err_t
- 首先用os_device_find查找设备名是否已被注册过,如果已注册过,则返回无效参数的错误类型。
- 初始化基类对象,纳入对象容器实现设备的初始化,并通过os_list_add将设备结点添加到系统的设备链表里。
4、设备框架层
设备框架层对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。
-
函数接口(API):
函数
功能
os_i2c_bus_device_find
根据I2C总线名称查找I2C总线设备
i2c_bus_device_control
控制I2C总线设备的特性
i2c_bus_device_write
将发送数据写入I2C总线设备
i2c_bus_device_read
读I2C总线设备接收的数据
os_i2c_master_recv
I2C总线设备数据接收
os_i2c_master_send
I2C总线设备数据发送
os_i2c_client_write
I2C 主设备数据发送
os_i2c_client_read
I2C 主设备数据接收
os_i2c_client_write_byte
使用cmd向I2C 主设备写入单字节数据
os_i2c_client_read_byte
根据cmd读取I2C主设备单字节数据
os_i2c_transfer
使用I2C设备传输消息
os_i2c_bus_device_register
注册I2C设备总线
- 主要作用:
- 这一层主要起到承上启下的作用,为上层应用提供统一的API,为下层驱动,提供注册函数。
- 实现设备ops函数:i2c_ops
- const static struct os_device_ops i2c_ops = {
- .read = i2c_bus_device_read,
- .write = i2c_bus_device_write,
- .control = i2c_bus_device_control
- };
- 调用os_device_register函数将I2C设备注册到设备管理层。
5、设备驱动层
1、 实现设备ops功能函数stm32_i2c_transfer,对接底层硬件,调用STM32的HAL库。
2、 probe函数实现设备初始化,调用os_i2c_bus_device_register向框架层注册设备。
3、 调用probe函数的方法。
- 调用OS_DRIVER_INFO,将st_i2c的probe和name赋值给os_driver_info_t。
- OS_DRIVER_INFO stm32_i2c_driver = {
- .name = “I2C_HandleTypeDef”,
- .probe = stm32_i2c_probe,
- };
- #define OS_DRIVER_INFO static OS_USED OS_SECTION(“driver_table”) const os_driver_info_t
- os_driver_info_t结构体定义如下:
- typedef struct os_driver_info
- {
- char *name;
- int (*probe)(const struct os_driver_info *drv, const struct os_device_info *dev);
- } os_driver_info_t;
- 在设备进行初始化时会将stm32_i2c_driver作为OS_DRIVER_DEFINE的参数,调用驱动和设备匹配函数,让driver逐一与device_table中的device对应的driver进行比较,直到找到相同的driver即匹配完成,之后将device和driver传递给probe完成设备注册。