设计说明
源码说明
源代码位于 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 层接口头文件
模块架构
I2C 驱动 Driver 层采用 RT-Thread 的 I2C 设备驱动框架,APP 可以遵从 RT-Thread 的调用方式,也可以直接使用 HAL 层,支持 Baremetal 方式的应用场景。
参数配置:主要是设置 I2C 工作的主机模式,7bit 或 10bit 寻址,寻址的从机地址设置,FIFO 设置以及总线传输速率等。2.SCL时序参数设置:根据设置的总线传输速率,设置 SCL 的高低电平时间。
3.i2c_algorithm 的实现:作为主机端,主要是 master_xfer 的实现。在驱动实现中,以 message 为单位进行数据的收发,数据的传输采用中断的方式。
4.中断的处理:处理 master 端的数据收发,并产生相应的 start、ack、nack、restart、stop 信号。
关键流程设计
初始化流程
I2C模块驱动的初始化流程如下:
传输流程
在 I2C master 驱动中,数据的传输由 aic_i2c_master_xfer 发起,可以完成多个 i2c_msg 的传输。传输流程如下:
I2C模块总线信号
在 I2C 总线的数据传输过程,由 start/restart/stop 作为总线的控制信号。了解 I2C 模块中 start/restart/stop 信号的生成方式,有助于了解驱动的源码实现。
master transmitte
对图中3个关键点的解释:
1.I2C 作为 master transmitter 时,当向 TXFIFO 中写入数据时,I2C 模块会自动发出 start 信号
2.若 stop 位未置位,则当 TXFIFO 中的数据全部发送,TXFIFO 为空时,会保持 SCL 为低电平,直到再次向 TXFIFO 中写入数据
3.再次向 TXFIFO 写入数据时,将 stop 位置1,则在完成该字节的发送后,master 会自动发送 stop 信号
master receiver
对图中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
中断流程
数据结构设计
drv层管理I2C控制器资源的顶层结构体
struct aic_i2c_bus {
struct rt_i2c_bus_device bus; //RTT内核I2C控制器数据结构
aic_i2c_ctrl aic_bus; //I2C 控制器资源的底层结构体
struct rt_completion cmd_complete; //完成量,用于指示一个message是否传输完成
};
2
3
4
5
RTT内核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; //私有数据
};
2
3
4
5
6
7
8
9
10
hal层管理I2C控制器资源的底层结构体
struct aic_i2c_ctrl
{
int32_t index;
char *device_name;
unsigned long reg_base;
uint32_t addr_bit;
uint32_t speed_mode;
uint32_t bus_mode;
struct aic_i2c_msg *msg; //指向当前传输的message
struct aic_i2c_slave_info slave; //从机信息数据结构
enum aic_msg_status msg_status;
uint32_t slave_addr;
uint32_t abort_source;
uint32_t msg_err;
uint32_t buf_write_idx; //当前message为write msg时,buf_write_idx为写数据的计数。当前message为read msg时,buf_write_idx为写命令的计数(I2C模块需要每次写read命令,才能读出数据)。
uint32_t buf_read_idx; //读数据的计数
bool is_first_message; //是否是最后一个message
bool is_last_message; //是否是第一个message
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
I2C消息数据结构原型
struct aic_i2c_msg
{
uint16_t addr; // 从机地址
uint16_t flags; // 读写标志
uint16_t len; // 数据长度
uint8_t *buf; // 待传输数据的指针
};
2
3
4
5
6
7
I2C从机信息数据结构原型
struct aic_i2c_slave_info
{
void *callback_param; //回调参数
i2c_slave_cb_t slave_cb; //从机回调函数
};
2
3
4
5
接口设计
driver层接口设计
aic_hw_i2c_register
函数原型 | static int aic_hw_i2c_register() |
---|---|
功能说明 | 注册和初始化I2C设备 |
参数定义 | NULL |
返回值 | 0:注册成功 <0:注册失败 |
注意事项 |
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 总线参数进行设置,目前支持更改总线速率 |
参数定义 | bus:I2C 接口对应的总线指cmd:命令参数value:命令值 |
返回值 | RT_EOK:函数执行成功-RT_EIO:非法操作 |
注意事项 |
aic_i2c_slave_control
函数原型 | static rt_err_t aic_i2c_slave_control(struct rt_i2c_bus_device *bus, rt_uint32_t cmd, void *arg) |
---|---|
功能说明 | 对 I2C 从机回调函数进行配置 |
参数定义 | bus:I2C 接口对应的总线指针cmd:命令参数arg:回调函数参数 |
返回值 | RT_EOK:函数执行成功 |
注意事项 |
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数据传输函数 |
参数定义 | bus:I2C 接口对应的总线指针msgs: 发送的消息数组num: 发送的消息数量 |
返回值 | 返回已发出的消息数量 |
注意事项 |
aic_i2c_xfer_msg
函数原型 | static int aic_i2c_xfer_msg(struct aic_i2c_ctrl *i2c_dev, struct aic_i2c_msg *msg, bool is_first, bool is_last) |
---|---|
功能说明 | I2C数据传输函数 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体msg:指向当前将要传输的msg is_first:指示当前msg是否是第一个msg is_last:指示当前msg是否是最后一个msg |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
aic_i2c_xfer_msg_init
函数原型 | static void aic_i2c_xfer_msg_init(struct aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 在传输每个msg前进行的初始化,主要是将指示每个msg状态的变量设置为初始值,使能中断 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 无 |
注意事项 |
aic_i2c_handle_write
函数原型 | static void aic_i2c_handle_write(struct aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 当触发TX_EMPTY中断时,调用该函数。若是读msg,则调用该函数发送读命令,若是写msg,则调用该函数发送数据 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 无 |
注意事项 |
aic_i2c_handle_read
函数原型 | static void aic_i2c_handle_read(struct aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 当触发RX_FULL中断时,调用该函数读取接收到的数据,若完成当前msg的接收,则释放完成量 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 无 |
注意事项 |
hal层接口设计
hal_i2c_init
函数原型 | int hal_i2c_init(aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 初始化I2C的时钟,主从模式,速率等基础设置 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_clk_init
函数原型 | int hal_i2c_clk_init(aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 初始化I2C的时钟 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_set_hold
函数原型 | void hal_i2c_set_hold(aic_i2c_ctrl *i2c_dev, u32 val) |
---|---|
功能说明 | 设置SDA的保持时间 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \val:设置保持时间的cycle数量,保持时间:val*41.66 ns |
返回值 | 无 |
注意事项 |
hal_i2c_set_master_slave_mode
函数原型 | int hal_i2c_set_master_slave_mode(aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 设置主从模式 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_master_10bit_addr
函数原型 | int hal_i2c_master_10bit_addr(aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 设置主机模式的寻址模式 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_slave_10bit_addr
函数原型 | int hal_i2c_slave_10bit_addr(aic_i2c_ctrl *i2c_dev) |
---|---|
功能说明 | 设置从机模式的寻址模式 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_scl_cnt
函数原型 | static int hal_i2c_scl_cnt(uint32_t clk_freq, uint8_t is_standard_speed, uint16_t *hcnt, uint16_t *lcnt) |
---|---|
功能说明 | 根据i2c模块工作的时钟频率和i2c的传输速率,返回需要设置的hcnt值和lcnt值 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_speed_mode_select
函数原型 | int hal_i2c_speed_mode_select(aic_i2c_ctrl *i2c_dev, uint32_t clk_freq, uint8_t mode) |
---|---|
功能说明 | 设置I2C的传输的工作模式和传输速率 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ clk_freq:模块时钟的时钟频率 \mode:工作模式 |
返回值 | 0:执行成功<0:执行过程中发生错误 |
注意事项 |
hal_i2c_target_addr
函数原型 | void hal_i2c_target_addr(aic_i2c_ctrl *i2c_dev, uint32_t addr) |
---|---|
功能说明 | 设置I2C目标设备的地址 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ addr:目标地址 |
返回值 | 无 |
注意事项 |
hal_i2c_slave_own_addr
函数原型 | int hal_i2c_slave_own_addr(aic_i2c_ctrl *i2c_dev, uint32_t addr) |
---|---|
功能说明 | 设置SLAVE模式被寻址的地址 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ addr:目标地址 |
返回值 | 0:执行成功 <0:执行过程中发生错误 |
注意事项 |
hal_i2c_wait_transmit
函数原型 | static int32_t hal_i2c_wait_transmit(aic_i2c_ctrl *i2c_dev, uint32_t timeout) |
---|---|
功能说明 | I2C数据发送的超时函数 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ timeout:超时时间单位ms |
返回值 | 0:执行成功<0:超时 |
注意事项 |
hal_i2c_wait_receive
函数原型 | static int32_t hal_i2c_wait_receive(aic_i2c_ctrl *i2c_dev, uint32_t wait_data_num, uint32_t timeout) |
---|---|
功能说明 | I2C数据接收的超时函数 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ wait_data_num:等待接收数据的数量 \ timeout:超时时间单位ms |
返回值 | 0:执行成功<0:超时 |
注意事项 |
hal_i2c_wait_bus_free
函数原型 | int32_t hal_i2c_wait_bus_free(aic_i2c_ctrl *i2c_dev, uint32_t timeout) |
---|---|
功能说明 | 等待I2C总线空闲 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ timeout:超时时间单位ms |
返回值 | 0:执行成功<0:超时 |
注意事项 |
hal_i2c_master_send_msg
函数原型 | int32_t hal_i2c_master_send_msg(aic_i2c_ctrl *i2c_dev, struct aic_i2c_msg *msg, uint8_t is_last_message) |
---|---|
功能说明 | 发送数据 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \msg:指向当前将要传输的msg \is_last_message:指示当前msg是否是最后一个msg |
返回值 | send_count:发送数据的数量<0:发送出错 |
注意事项 |
hal_i2c_master_receive_msg
函数原型 | int32_t hal_i2c_master_receive_msg(aic_i2c_ctrl *i2c_dev, struct aic_i2c_msg *msg, uint8_t is_last_message) |
---|---|
功能说明 | 发送数据 |
参数定义 | i2c_dev:指向自定义的aic_i2c_ctrl结构体 \ msg:指向当前将要传输的msg \is_last_message:指示当前msg是否是最后一个msg |
返回值 | read_count:接收到数据的数量<0:接收出错 |
注意事项 |