4. I2C 寄存器读写基础:协议、地址、时序与 SMBus 区别

在 RK 平台 Sensor 驱动调试中,I2C 是最常用的板级通信总线。Sensor 通常作为 I2C 从设备,主控通过 I2C 控制器读写其内部寄存器,以完成初始化配置、模式切换和数据采集。本章从协议层到驱动层,系统梳理 I2C 的核心概念与实操要点。

4.1 I2C 协议概述

I2C(Inter-Integrated Circuit)是一种同步、半双工、多主从的总线协议,由 Philips 公司(现 NXP)在 1980 年代提出。它仅需两根线:串行数据线 SDA 和串行时钟线 SCL,即可挂载多个设备。

关键特性速览:
  • 物理层:开漏输出 + 上拉电阻,线与逻辑。
  • 速率模式:标准模式 100 kHz,快速模式 400 kHz,高速模式 3.4 MHz。
  • 地址长度:7 位地址(主流)或 10 位地址(扩展)。
  • 数据格式:大端传输,MSB first,每字节后跟 ACK/NACK。
  • 多主支持:通过仲裁和时钟同步实现多主共存。
I2C 总线拓扑结构 Rₚ Rₚ VDD VDD SDA SCL 主控 (Master) 从设备 1 (Sensor A) 从设备 2 (Sensor B) 说明: 每个从设备有唯一地址;主控通过地址选择通信对象,未选中的设备释放总线。

4.2 7 位地址与 10 位地址

I2C 从设备地址分为 7 位模式和 10 位模式。在 RK 平台 Sensor 驱动中,绝大多数 Sensor 使用 7 位地址。

特性 7 位地址 10 位地址
地址范围 0x00 ~ 0x7F(保留 0x00~0x07) 0x000 ~ 0x3FF
理论最大设备数 112 个(实际受总线电容限制) 1024 个
地址字节数 1 字节(高 7 位为地址,LSB 为 R/W) 2 字节(首字节 11110XX + R/W,次字节为低 8 位)
兼容性 所有 I2C 设备均支持 需从设备明确支持 10 位模式
RK 平台使用场景 95% 以上的 Sensor(如 MPU6050、ICM-20602) 极少数多路复用器或特殊 PMIC
驱动调试提示:在 RK 平台设备树中,7 位地址直接填写十六进制值,例如 reg = <0x68>。注意:设备树中的地址是 7 位左对齐值,不包含 R/W 位。如果 Sensor 数据手册标注地址为 0xD0(含 R/W),则实际 7 位地址为 0x68。

4.3 I2C 读写时序

I2C 通信以 START 条件开始,以 STOP 条件结束。每次传输包含:从设备地址 + R/W 位、寄存器地址、数据字节,每字节后跟 ACK 应答。

4.3.1 写时序(Master → Slave)

写操作通常用于配置 Sensor 寄存器。标准格式如下:

START | 7-bit ADDR + W(0) | ACK | REG_ADDR | ACK | DATA_BYTE | ACK | ... | STOP

4.3.2 读时序(Master ← Slave)

读操作需要先写寄存器地址,再重新发送 START 条件切换为读方向:

START | 7-bit ADDR + W(0) | ACK | REG_ADDR | ACK |
RESTART | 7-bit ADDR + R(1) | ACK | DATA_BYTE | NACK | STOP
I2C 读写时序对比 写时序: START ADDR+W ACK REG_ADDR ACK DATA ACK STOP 读时序: START ADDR+W ACK REG_ADDR ACK RESTART ADDR+R ACK DATA NACK 时序要点: 1. 写时序:START → 从设备地址+写位 → 寄存器地址 → 数据字节 → STOP 2. 读时序:START → 从设备地址+写位 → 寄存器地址 → RESTART → 从设备地址+读位 → 数据字节 → NACK → STOP 3. RESTART(重复起始条件)是读操作的关键,不能使用 STOP+START 替代,否则可能丢失总线所有权。 4. 读最后一个字节时 Master 发送 NACK,通知从设备停止发送。

4.4 SMBus 与 I2C 的区别

SMBus(System Management Bus)基于 I2C 协议,但在时序、电压、超时和命令格式上有严格约束。RK 平台部分 PMIC 和电池管理芯片使用 SMBus,Sensor 驱动中也可能遇到兼容性问题。

对比项 I2C SMBus
电压标准 无固定标准(常见 1.8V / 3.3V / 5V) 固定 3.3V ± 5%
最低时钟频率 DC(可无限慢) 最低 10 kHz(防止死锁)
超时机制 无硬件超时 35 ms 超时检测(时钟低电平超时)
最大速率 标准 100 kHz / 快速 400 kHz / 高速 3.4 MHz 最大 100 kHz
地址应答 允许 NACK 后继续通信 NACK 后必须 STOP
命令协议 无固定命令格式 固定协议:Quick Command、Send Byte、Receive Byte、Write Byte/Word、Read Byte/Word、Block Read/Write
分组错误校验 无 可选 PEC(Packet Error Checking)
典型应用 Sensor、EEPROM、ADC/DAC PMIC、电池管理、温度监控
驱动兼容性警告:在 RK 平台上,如果 Sensor 数据手册标注为 SMBus 兼容,驱动中应使用 SMBus 专用 API(如 i2c_smbus_read_byte_data()),而非通用 I2C 传输函数。SMBus 的 35 ms 超时机制可能导致 I2C 慢速设备通信失败,需在设备树中调整时钟频率或关闭超时检测。

4.5 RK 平台 I2C 驱动框架中的寄存器读写

在 Linux 内核中,I2C 驱动通过 struct i2c_client 表示从设备,通过 struct i2c_adapter 表示 I2C 控制器。Sensor 驱动通常使用以下 API 进行寄存器读写:

4.5.1 核心 API 对比

函数 说明 适用场景
i2c_smbus_read_byte_data() 读取单个寄存器(1 字节) SMBus 兼容设备,单寄存器读取
i2c_smbus_write_byte_data() 写入单个寄存器(1 字节) SMBus 兼容设备,单寄存器写入
i2c_smbus_read_i2c_block_data() 读取连续寄存器块 批量读取 Sensor 数据(如加速度计 XYZ)
i2c_transfer() 通用 I2C 消息传输 非 SMBus 设备,自定义时序
regmap_init_i2c() 基于 regmap 框架的 I2C 封装 推荐方式:自动处理缓存、批量操作、调试

4.5.2 使用 regmap 进行寄存器读写(推荐)

在 RK 平台 Sensor 驱动中,推荐使用 regmap 框架,它封装了 I2C 传输细节,并提供缓存、批量读写和调试接口。

/* 驱动初始化时创建 regmap */
static const struct regmap_config sensor_regmap_config = {
    .reg_bits = 8,          /* 寄存器地址宽度:8 位 */
    .val_bits = 8,          /* 寄存器数据宽度:8 位 */
    .max_register = 0x7F,   /* 最大寄存器地址 */
    .cache_type = REGCACHE_RBTREE,  /* 使用红黑树缓存 */
};

struct regmap *regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
if (IS_ERR(regmap)) {
    dev_err(&client->dev, "Failed to init regmap\n");
    return PTR_ERR(regmap);
}

/* 读写操作示例 */
int val;
regmap_read(regmap, 0x0D, &val);   /* 读取 WHO_AM_I 寄存器 */
regmap_write(regmap, 0x1A, 0x10);  /* 写入配置寄存器 */
调试技巧:使用 regmap 时,可以通过 debugfs 查看寄存器缓存状态:cat /sys/kernel/debug/regmap/<i2c-bus>-<addr>/registers。在 RK 平台上,这比直接使用 i2cget/i2cset 更高效,且不会干扰驱动运行状态。

4.6 常见寄存器读写问题与排查方法

在 Sensor 驱动调试初期,寄存器读写失败是最常见的问题。以下是 RK 平台上的典型故障场景:

  • 设备地址错误:设备树中 reg 值与 Sensor 实际 7 位地址不匹配。使用 i2cdetect -y <bus> 扫描确认。
  • ACK 丢失:Sensor 未响应,通常由电源未上电、复位引脚拉低或 I2C 上拉电阻缺失导致。用示波器抓取 SDA/SCL 波形确认。
  • 时钟拉伸超时:部分 Sensor 在内部处理时会拉低 SCL,RK 平台 I2C 控制器默认支持时钟拉伸,但需确认超时时间配置。
  • 寄存器地址自动递增:连续读取时,部分 Sensor 不支持地址自动递增,需逐字节发送寄存器地址。
  • 字节序问题:16 位寄存器在 I2C 上为大端传输,但 Sensor 内部可能使用小端存储,驱动中需做字节交换。
I2C 寄存器读写故障排查流程 读写失败 步骤1:检查设备树 reg 地址 步骤2:i2cdetect 扫描确认设备在线 在线? 否 检查电源/复位/上拉 是 步骤3:i2cget 读 WHO_AM_I 确认寄存器读写正常

4.7 本章小结