瑞芯微RK Sensor寄存器配置与初始化流程调试 - 第4节
4.1 I2C总线物理层与协议概述
I2C(Inter-Integrated Circuit)是一种同步、半双工、多主从的串行通信总线,广泛应用于瑞芯微RK平台与Sensor(如摄像头、陀螺仪、温湿度传感器)之间的寄存器配置与数据读取。I2C仅需两根线即可完成通信:SCL(串行时钟线)和SDA(串行数据线),极大节省了PCB走线资源。
drivers/i2c/busses/ 目录下,Sensor作为从设备挂载在I2C总线上。初始化流程的第一步是确保I2C控制器时钟已使能、引脚复用正确。
4.2 I2C时序详解
I2C通信的每个字节(8位)后必须跟随一个应答位(ACK/NACK)。时序由SCL时钟同步,SDA在SCL低电平时变化,高电平时采样。以下是I2C通信的完整时序流程:
4.2.1 起始条件与停止条件
- 起始条件(S):SCL为高电平时,SDA由高电平切换到低电平。
- 停止条件(P):SCL为高电平时,SDA由低电平切换到高电平。
- 重复起始条件(Sr):在未产生停止条件前,主机再次产生起始条件,用于改变数据传输方向(如从写切换到读)。
4.2.2 数据采样与字节传输
每个数据字节传输9个SCL时钟周期:前8个周期传输数据位(MSB first),第9个周期为应答位。SDA在SCL低电平时变化,在SCL高电平时被接收方采样。
| SCL周期序号 | SDA行为 | 说明 |
|---|---|---|
| 1~8 | 数据位 D7~D0 | 主机控制SDA,从机在SCL高电平时采样 |
| 9 | 应答位 (ACK/NACK) | 接收方拉低SDA为ACK,保持高为NACK |
4.3 7位地址与10位地址
I2C从设备地址分为7位模式和10位模式。瑞芯微RK平台Sensor通常使用7位地址,但部分高精度Sensor(如某些温度传感器)可能使用10位地址。
4.3.1 7位地址格式
7位地址占用一个字节的高7位,最低位为读写标志位(R/W)。例如,Sensor地址0x48(7位)在写操作时发送0x90(0x48 << 1 | 0),读操作时发送0x91(0x48 << 1 | 1)。
| 位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| 内容 | A6 | A5 | A4 | A3 | A2 | A1 | A0 | R/W |
| 示例(写) | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
4.3.2 10位地址格式
10位地址需要两个字节传输:第一个字节高5位为11110xx(xx为地址高2位),低1位为R/W;第二个字节为地址低8位。10位地址在RK Sensor中较少见,但驱动开发时需兼容。
i2cdetect -y <bus> 命令扫描总线,确认Sensor的7位地址是否正确。地址冲突(两个设备地址相同)会导致应答混乱。
4.4 读写操作流程
I2C读写操作分为单字节读写和多字节读写。在RK Sensor寄存器配置中,最常用的是复合格式:先写寄存器地址,再读/写寄存器数据。
4.4.1 写操作流程(主机写数据到从机)
- 主机发送起始条件(S)。
- 主机发送从机地址 + 写标志(W)。
- 从机应答ACK。
- 主机发送寄存器地址(1字节或2字节)。
- 从机应答ACK。
- 主机发送数据字节(1~N字节)。
- 每字节后从机应答ACK。
- 主机发送停止条件(P)。
4.4.2 读操作流程(主机从从机读取数据)
- 主机发送起始条件(S)。
- 主机发送从机地址 + 写标志(W),先写入寄存器地址。
- 从机应答ACK。
- 主机发送寄存器地址。
- 从机应答ACK。
- 主机发送重复起始条件(Sr)。
- 主机发送从机地址 + 读标志(R)。
- 从机应答ACK。
- 从机发送数据字节,主机每字节后发送ACK(继续读)或NACK(最后一字节)。
- 主机发送停止条件(P)。
struct i2c_msg 消息结构体实现。读操作通常使用两个消息:第一个消息写寄存器地址(无停止条件),第二个消息读数据。使用 i2c_transfer() 函数一次性提交。
4.5 多字节传输与寄存器批量配置
在RK Sensor初始化过程中,经常需要连续配置多个寄存器(如设置增益、曝光时间、帧率等)。多字节传输允许在一次I2C事务中完成多个寄存器的读写,提高效率。
4.5.1 多字节写操作
主机连续发送多个数据字节,从机每字节后应答ACK,直到主机发送停止条件。寄存器地址自动递增(部分Sensor支持)。
// RK平台I2C多字节写示例(C语言伪代码)
int i2c_write_regs(struct i2c_client *client, u8 reg_addr, u8 *data, int len)
{
struct i2c_msg msg;
u8 buf[256];
buf[0] = reg_addr;
memcpy(&buf[1], data, len);
msg.addr = client->addr;
msg.flags = 0; // 写
msg.len = len + 1;
msg.buf = buf;
return i2c_transfer(client->adapter, &msg, 1);
}
4.5.2 多字节读操作
先写寄存器地址,然后重复起始,再连续读取多个字节。主机在每字节后发送ACK,最后一字节发送NACK。
// RK平台I2C多字节读示例
int i2c_read_regs(struct i2c_client *client, u8 reg_addr, u8 *data, int len)
{
struct i2c_msg msgs[2];
msgs[0].addr = client->addr;
msgs[0].flags = 0; // 写寄存器地址
msgs[0].len = 1;
msgs[0].buf = ®_addr;
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD; // 读数据
msgs[1].len = len;
msgs[1].buf = data;
return i2c_transfer(client->adapter, msgs, 2);
}
4.6 I2C时序参数与RK平台适配
I2C时序参数直接影响通信稳定性。RK平台通过设备树(DTS)配置I2C控制器时序,关键参数如下:
| 参数 | 说明 | 典型值 | RK DTS属性 |
|---|---|---|---|
| SCL时钟频率 | I2C总线时钟 | 100kHz / 400kHz | clock-frequency |
| 上升时间 (t_r) | SDA/SCL上升沿时间 | 300ns (400kHz) | i2c-scl-rising-time-ns |
| 下降时间 (t_f) | SDA/SCL下降沿时间 | 100ns (400kHz) | i2c-scl-falling-time-ns |
| 数据保持时间 (t_HD;DAT) | SCL下降沿后SDA保持时间 | 0~300ns | (由控制器自动计算) |
| 数据建立时间 (t_SU;DAT) | SCL上升沿前SDA建立时间 | 100ns (400kHz) | (由控制器自动计算) |
&i2c1 {
status = "okay";
clock-frequency = <400000>;
i2c-scl-rising-time-ns = <300>;
i2c-scl-falling-time-ns = <100>;
sensor@48 {
compatible = "vendor,sensor";
reg = <0x48>;
};
};