瑞芯微RK Sensor寄存器配置与初始化流程调试 - 第4节

4.1 I2C总线物理层与协议概述

I2C(Inter-Integrated Circuit)是一种同步、半双工、多主从的串行通信总线,广泛应用于瑞芯微RK平台与Sensor(如摄像头、陀螺仪、温湿度传感器)之间的寄存器配置与数据读取。I2C仅需两根线即可完成通信:SCL(串行时钟线)和SDA(串行数据线),极大节省了PCB走线资源。

关键特性:支持7位和10位地址模式;标准模式100kHz、快速模式400kHz、高速模式3.4MHz;多主机仲裁;应答机制确保数据可靠传输。
RK平台调试提示:在RK Linux内核中,I2C适配器驱动通常位于 drivers/i2c/busses/ 目录下,Sensor作为从设备挂载在I2C总线上。初始化流程的第一步是确保I2C控制器时钟已使能、引脚复用正确。
I2C总线物理连接拓扑 RK SoC (Master) Sensor A (0x48) Sensor B (0x4A) Sensor C (0x68) Rpu Rpu SDA SCL VDD (3.3V/1.8V) 上拉电阻 4.7kΩ 典型值

4.2 I2C时序详解

I2C通信的每个字节(8位)后必须跟随一个应答位(ACK/NACK)。时序由SCL时钟同步,SDA在SCL低电平时变化,高电平时采样。以下是I2C通信的完整时序流程:

4.2.1 起始条件与停止条件

  • 起始条件(S):SCL为高电平时,SDA由高电平切换到低电平。
  • 停止条件(P):SCL为高电平时,SDA由低电平切换到高电平。
  • 重复起始条件(Sr):在未产生停止条件前,主机再次产生起始条件,用于改变数据传输方向(如从写切换到读)。
I2C 起始条件与停止条件时序 S 起始 P 停止 SCL SDA SCL高电平时SDA下降沿→起始;SCL高电平时SDA上升沿→停止

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)。

位76543210
内容A6A5A4A3A2A1A0R/W
示例(写)10010000

4.3.2 10位地址格式

10位地址需要两个字节传输:第一个字节高5位为11110xx(xx为地址高2位),低1位为R/W;第二个字节为地址低8位。10位地址在RK Sensor中较少见,但驱动开发时需兼容。

地址冲突排查:在RK平台调试时,如果I2C通信失败,首先使用 i2cdetect -y <bus> 命令扫描总线,确认Sensor的7位地址是否正确。地址冲突(两个设备地址相同)会导致应答混乱。
7位地址 vs 10位地址 帧格式 7位地址: S 7位地址 (A6~A0) R/W ACK 10位地址: S 11110 A9 A8 R/W ACK A7~A0 (低8位) ACK S=起始条件;ACK=从机应答;R/W=0写/1读

4.4 读写操作流程

I2C读写操作分为单字节读写和多字节读写。在RK Sensor寄存器配置中,最常用的是复合格式:先写寄存器地址,再读/写寄存器数据。

4.4.1 写操作流程(主机写数据到从机)

  1. 主机发送起始条件(S)。
  2. 主机发送从机地址 + 写标志(W)。
  3. 从机应答ACK。
  4. 主机发送寄存器地址(1字节或2字节)。
  5. 从机应答ACK。
  6. 主机发送数据字节(1~N字节)。
  7. 每字节后从机应答ACK。
  8. 主机发送停止条件(P)。

4.4.2 读操作流程(主机从从机读取数据)

  1. 主机发送起始条件(S)。
  2. 主机发送从机地址 + 写标志(W),先写入寄存器地址。
  3. 从机应答ACK。
  4. 主机发送寄存器地址。
  5. 从机应答ACK。
  6. 主机发送重复起始条件(Sr)。
  7. 主机发送从机地址 + 读标志(R)。
  8. 从机应答ACK。
  9. 从机发送数据字节,主机每字节后发送ACK(继续读)或NACK(最后一字节)。
  10. 主机发送停止条件(P)。
RK驱动实现:在Linux内核中,I2C读写操作通过 struct i2c_msg 消息结构体实现。读操作通常使用两个消息:第一个消息写寄存器地址(无停止条件),第二个消息读数据。使用 i2c_transfer() 函数一次性提交。
I2C 读操作完整流程(写寄存器地址 + 读数据) S Addr+W ACK Reg Addr ACK Sr Addr+R ACK Data Byte ACK Data Byte NACK P 写寄存器地址阶段(无停止条件) → 重复起始 → 读数据阶段 最后一字节主机发送NACK,表示不再读取,随后发送停止条件P Linux I2C 读操作消息结构 struct i2c_msg msgs[2]; msgs[0].addr = slave_addr; msgs[0].flags = 0; msgs[0].len = 1; msgs[0].buf = &reg_addr; msgs[1].addr = slave_addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 2; msgs[1].buf = data_buf;

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 = &reg_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);
}
多字节传输避坑:部分Sensor不支持地址自动递增,此时需要逐寄存器读写。在RK平台调试时,如果多字节读取返回错误数据,先尝试单字节读取确认每个寄存器值,再排查地址递增功能是否使能。

4.6 I2C时序参数与RK平台适配

I2C时序参数直接影响通信稳定性。RK平台通过设备树(DTS)配置I2C控制器时序,关键参数如下:

参数说明典型值RK DTS属性
SCL时钟频率I2C总线时钟100kHz / 400kHzclock-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)(由控制器自动计算)
RK平台DTS配置示例:
&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>;
    };
};
I2C 时序参数定义 ← 上一章 📖 返回目录 下一章 →