7.6.5. 设计说明

7.6.5.1. 源码说明

源代码位于 bsp/artinchip/

  • bsp/artinchip/drv/i2c/drv_i2c.c,I2C Driver 层实现

  • bsp/artinchip/hal/i2c/hal_i2c.c,I2C HAL 层实现

  • bsp/artinchip/include/hal/hal_i2c.h,I2C HAL 层接口头文件

7.6.5.2. 模块架构

I2C 驱动 Driver 层采用 RT-Thread 的 I2C 设备驱动框架,APP 可以遵从 RT-Thread 的调用方式,也可以直接使用 HAL 层,支持 baremetal 方式的应用场景。

../../../_images/i2c_structure.png

7.6.5.2.1. I2C master

I2C 作为 master 时,驱动的实现主要包括4个部分:

  1. 硬件参数配置:主要是设置 I2C 工作的主机模式,7bit 或 10bit 寻址,寻址的从机地址设置,FIFO 设置以及总线传输速率等。

  2. SCL时序参数设置:根据设置的总线传输速率,设置 SCL 的高低电平时间。

  3. i2c_algorithm 的实现:作为主机端,主要是 master_xfer 的实现。在驱动实现中,以 message 为单位进行数据的收发,数据的传输采用中断的方式。

  4. 中断的处理:处理 master 端的数据收发,并产生相应的 start、ack、nack、restart、stop 信号。

7.6.5.3. 关键流程设计

7.6.5.3.1. 初始化流程

I2C模块驱动的初始化流程如下:

../../../_images/design_1.png

7.6.5.3.2. 传输流程

在 I2C master 驱动中,数据的传输由 aic_i2c_master_xfer 发起,可以完成多个 i2c_msg 的传输。传输流程如下:

../../../_images/design_2.png

7.6.5.3.3. I2C模块总线信号

在 I2C 总线的数据传输过程,由 start/restart/stop 作为总线的控制信号。了解 I2C 模块中 start/restart/stop 信号的生成方式,有助于了解驱动的源码实现。

7.6.5.3.3.1. master transmitter

../../../_images/design_3.png

对图中3个关键点的解释:

  1. I2C 作为 master transmitter 时,当向 TXFIFO 中写入数据时,I2C 模块会自动发出 start 信号

  2. 若 stop 位未置位,则当 TXFIFO 中的数据全部发送,TXFIFO 为空时,会保持 SCL 为低电平,直到再次向 TXFIFO 中写入数据

  3. 再次向 TXFIFO 写入数据时,将 stop 位置1,则在完成该字节的发送后,master 会自动发送 stop 信号

7.6.5.3.3.2. master receiver

../../../_images/design_4.png

对图中3个关键点的解释:

  1. I2C 作为 master receiver 时,当向 TXFIFO 写入读命令(即向 I2C_DATA_CMD 写入读命令)时,I2C 模块会自动发送 start 信号

  2. 当接收到 slave 端发送的数据后,只有再次发送一次读命令,才会对本次收到的数据恢复 ACK 确认信号

  3. master 在接收到最后一个数据后,回复 NACK,slave 端才会结束数据的传送。在发送最后一个读命令时,同时将 stop 位置位,则master在接收到slave发送的数据后,I2C模块会自动发送NACK信号

注解

I2C 模块的数据传输,无论是 transmitter 还是 receiver,都会用到 TXFIFO,transmitter 时用来发送数据,receiver 时用来发送命令。所以,中断处理中,触发 TXFIFO_EMPTY 中断的,可能是 read msg,也可能是 write msg

7.6.5.3.4. 中断流程

../../../_images/design_5.png

7.6.5.4. 数据结构设计

管理 I2C 控制器资源的顶层结构体

struct rt_i2c_bus_device
{
    struct rt_device parent;                    // 设备基类 device
    const struct rt_i2c_bus_device_ops *ops;    // I2C 操作方法
    rt_uint16_t  flags;                         // I2C 读写标志
    struct rt_mutex lock;                       // 互斥锁,保证多线程访问安全
    rt_uint32_t  timeout;                       // 超时时间
    rt_uint32_t  retries;                       // 调用次数
    void *priv;                                 // 私有数据
};

7.6.5.5. 接口设计

对 I2C 总线操作的结构体

struct rt_i2c_bus_device_ops
{
    rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num);
    rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num);
    rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus, rt_uint32_t, rt_uint32_t);
};

D211 实例化的结构体为:

static const struct rt_i2c_bus_device_ops i2c_ops = {
    aic_i2c_master_xfer,    // master_xfer
    RT_NULL,                // slave_xfer
    aic_i2c_bus_control,    // bus_control
};

I2C 消息结构体

struct rt_i2c_msg
{
    rt_uint16_t addr;       // I2C 从设备地址
    rt_uint16_t flags;      // I2C 读写标志
    rt_uint16_t len;        // 待传输数据的长度
    rt_uint8_t  *buf;       // 待传输数据的指针
};

7.6.5.5.1. aic_i2c_master_xfer

函数原型

static rt_size_t aic_i2c_master_xfer(struct rt_i2c_bus_device *bus, | struct rt_i2c_msg msgs[], rt_uint32_t num)

功能说明

打印I2C发生abort的原因,并返回相应的error值

参数定义

bus:I2C 接口对应的总线指针
msgs: 发送的消息数组
num: 发送的消息数量

返回值

返回已发出的消息数量

注意事项

7.6.5.5.2. aic_i2c_bus_control

函数原型

static rt_err_t aic_i2c_bus_control(struct rt_i2c_bus_device *bus, | rt_uint32_t cmd, rt_uint32_t value)

功能说明

对 I2C 总线参数进行设置,目前支持更改总线速率,成功返回 RT_EOK

参数定义

bus:I2C 接口对应的总线指针
cmd:命令参数
value:命令值

返回值

RT_EOK:函数执行成功
-RT_EIO:非法操作

注意事项