【OneOS学习笔记】设备驱动模型中的I2C

  1. 简介
  • OneOS 在各类外设的基础上抽象出了设备驱动模型本文将围绕驱动模型来分析I2C驱动的实现过程。
  • I2C驱动以STM32为例,主要分析驱动模型中各层之间的调用关系。
  • OneOS设备驱动模型见OneOS 官网(https://os.iot.10086.cn)文档驱动部分。
  1. I2C驱动总概
  • I2C驱动框架如下图所示:

  1. 从图中可以看出用户可以直接访问设备统一接口和I2C设备框架层的API。
  2. 驱动为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

    框架层

  3. 对于不同芯片,管理层提供设备操作接口,框架层提供I2C这类设备通用的接口,驱动层提供具体芯片的I2C设备驱动程序。
  • STM32系列芯片I2C驱动实现过程:
  1. 设备注册:

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总线设备挂载到内核设备链表上。

  1. 设备访问:

应用层通过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库函数)

  1. 设备管理层

设备管理层实现了对设备驱动程序的封装,是所有设备通用的函数接口,I2C设备在管理层实现设备查找和注册。

  1. 查找设备:os_device_find()

函数原型:os_device_t *os_device_find(const char *name)

位置:drivers\device.c

参数:name(设备名称)

返回值类型:os_device_t(返回设备指针)

注:通过os_device_find()访问设备时,只在设备管理层实现。

  1. os_device_find()根据传入设备的名称 "i2c1",通过定义os_list_for_each_entry遍历设备链表os_device_list查找设备;若查找到设备,返回相应的设备指针,否则返回空指针OS_NULL。
  2. os_device_list的值来源于设备注册函数os_device_register()。
  1. 注册设备:os_device_register()

位置:drivers\device.c

参数:dev(设备指针),name(设备名称)

返回值类型:os_err_t

  1. 首先用os_device_find查找设备名是否已被注册过,如果已注册过,则返回无效参数的错误类型。
  2. 初始化基类对象,纳入对象容器实现设备的初始化,并通过os_list_add将设备结点添加到系统的设备链表里。

4、设备框架层

设备框架层对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。

  1. 函数接口(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设备总线

  2. 主要作用:
  1. 这一层主要起到承上启下的作用,为上层应用提供统一的API,为下层驱动,提供注册函数。
  2. 实现设备ops函数:i2c_ops
  1. const static struct os_device_ops i2c_ops = {
  2.     .read    = i2c_bus_device_read,
  3.     .write   = i2c_bus_device_write,
  4.     .control = i2c_bus_device_control
  5. };
  1. 调用os_device_register函数将I2C设备注册到设备管理层。

5、设备驱动层

1、 实现设备ops功能函数stm32_i2c_transfer,对接底层硬件,调用STM32的HAL库。

2、 probe函数实现设备初始化,调用os_i2c_bus_device_register向框架层注册设备。

3、 调用probe函数的方法。

  1. 调用OS_DRIVER_INFO,将st_i2c的probe和name赋值给os_driver_info_t。
  1. OS_DRIVER_INFO stm32_i2c_driver = {
  2.     .name  = "I2C_HandleTypeDef",
  3.     .probe = stm32_i2c_probe,
  4. };
  1. #define OS_DRIVER_INFO static OS_USED OS_SECTION("driver_table") const os_driver_info_t
  1. os_driver_info_t结构体定义如下:
  1. typedef struct os_driver_info
  2. {
  3.     char *name;
  4.     int (*probe)(const struct os_driver_info *drv, const struct os_device_info *dev);
  5. } os_driver_info_t;
  1. 在设备进行初始化时会将stm32_i2c_driver作为OS_DRIVER_DEFINE的参数,调用驱动和设备匹配函数,让driver逐一与device_table中的device对应的driver进行比较,直到找到相同的driver即匹配完成,之后将device和driver传递给probe完成设备注册。
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/5443273/blog/10084141