4. I2C总线协议基础:物理层、时序、地址、读写操作与多主机仲裁

I2C(Inter-Integrated Circuit)总线是嵌入式系统中使用最广泛的板级通信协议之一,尤其适合传感器、EEPROM、ADC/DAC等低速外设的连接。在Zephyr OS的传感器驱动框架中,I2C是默认的首选物理层接口。理解I2C的物理层特性、时序约束、地址机制、读写流程以及多主机仲裁规则,是编写稳定、可移植的传感器驱动的必要前提。

4.1 I2C物理层特性

I2C总线仅需两根双向信号线即可完成多设备通信:

  • SDA(Serial Data Line):串行数据线,用于传输地址、控制字和数据。
  • SCL(Serial Clock Line):串行时钟线,由主机(Master)驱动,决定通信速率。

所有设备通过开漏(Open-Drain)输出连接到SDA和SCL,外部必须接上拉电阻(典型值4.7kΩ @100kHz,2.2kΩ @400kHz)。这种结构允许任何设备拉低总线(实现时钟拉伸和仲裁),且不会造成短路。

关键参数速查:
  • 标准模式(Sm):100 kbit/s
  • 快速模式(Fm):400 kbit/s
  • 快速模式+(Fm+):1 Mbit/s
  • 高速模式(Hs):3.4 Mbit/s
  • 最大总线电容:400 pF
  • 上拉电阻范围:1kΩ ~ 10kΩ(取决于速率和电容)
Zephyr实践提示: 在设备树中通过 clock-frequency = <100000> 属性配置I2C速率。传感器驱动通常使用标准模式或快速模式,高速模式需要额外的I/O口驱动能力。
I2C总线物理连接拓扑 Rₚ Rₚ VDD (3.3V / 5V) SDA SCL 主机 (Master) MCU / SoC 从机 1 传感器 A 从机 2 传感器 B 所有设备通过开漏输出连接SDA/SCL,外部上拉电阻保证总线空闲时为高电平 任何设备均可拉低总线实现时钟拉伸或仲裁

4.2 I2C时序与信号约定

I2C通信的每个bit由SCL时钟同步,数据在SCL低电平时变化,高电平时采样。以下是核心时序定义:

时序参数 符号 标准模式 (100kHz) 快速模式 (400kHz) 说明
SCL时钟频率 fSCL 100 kHz 400 kHz 由主机决定
保持时间(起始条件) tHD;STA 4.0 μs 0.6 μs SCL低后SDA变化
建立时间(起始条件) tSU;STA 4.7 μs 0.6 μs SDA变化到SCL高
数据保持时间 tHD;DAT 0 μs 0 μs SCL低后数据有效
数据建立时间 tSU;DAT 250 ns 100 ns SCL高前数据稳定
SCL低电平时间 tLOW 4.7 μs 1.3 μs 时钟低脉冲宽度
SCL高电平时间 tHIGH 4.0 μs 0.6 μs 时钟高脉冲宽度
上升/下降时间 tr / tf 1000 ns 300 ns 受总线电容影响
常见陷阱: 传感器驱动中如果I2C时钟拉伸(Clock Stretching)处理不当,会导致通信超时。Zephyr的I2C API默认支持时钟拉伸,但需要确保从机在SCL低电平的保持时间不超过主机设置的超时阈值(通常10ms)。
I2C起始/停止条件与数据采样时序 SCL SDA S 起始 P 停止 数据采样点 起始条件:SCL高电平时SDA由高→低;停止条件:SCL高电平时SDA由低→高 数据在SCL高电平时采样,SCL低电平时允许SDA变化(每字节后跟ACK/NACK)

4.3 设备地址与7位/10位寻址

I2C总线上的每个从机设备都有一个唯一的地址。标准I2C使用7位地址,理论上支持112个设备(保留16个地址)。10位地址扩展了设备容量,但在传感器领域极少使用。

4.3.1 7位地址结构

地址字节在起始条件后发送,格式如下:

Bit 7 (MSB) Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 (LSB)
A6 A5 A4 A3 A2 A1 A0 R/W#
  • A6~A0:7位设备地址,由芯片厂商分配或通过引脚配置。
  • R/W#:读写标志位,0表示主机写(发送),1表示主机读(接收)。
常见传感器地址示例:
  • BME280:0x76(ADDR=GND)或 0x77(ADDR=VDDIO)
  • MPU6050:0x68(AD0=GND)或 0x69(AD0=VDD)
  • LSM6DSO:0x6A(SA0=GND)或 0x6B(SA0=VDD)
在Zephyr设备树中通过 reg = <0x76>; 指定地址。

4.3.2 保留地址

以下地址被I2C规范保留,不能分配给从机设备:

地址(7位) 用途
0x00 通用呼叫地址(General Call)
0x01 起始字节(Start Byte)
0x02 CBUS地址
0x03 保留
0x04 ~ 0x07 高速模式主机码
0x78 ~ 0x7F 10位地址扩展标识
I2C地址字节发送流程 起始 A6 A5 A4 A3 A2 A1 A0 R/W ACK 主机发送7位地址 + R/W位后释放SDA,从机在第9个SCL周期拉低SDA作为应答(ACK) 若从机未应答(NACK),主机应发送停止条件或重复起始条件 R/W=0:主机写;R/W=1:主机读

4.4 I2C读写操作流程

I2C通信的基本单元是帧(Frame),每个帧包含一个起始条件、地址字节、若干数据字节、应答位和停止条件。传感器驱动中最常用的两种操作模式是写寄存器和读寄存器。

4.4.1 写操作(主机→从机)

  1. 主机发送起始条件(S)。
  2. 主机发送7位地址 + W(0),等待从机ACK。
  3. 主机发送寄存器地址(1字节或2字节),等待从机ACK。
  4. 主机发送数据字节,每字节后等待从机ACK。
  5. 主机发送停止条件(P)。

4.4.2 读操作(主机←从机)

  1. 主机发送起始条件(S)。
  2. 主机发送7位地址 + W(0),等待从机ACK。
  3. 主机发送寄存器地址,等待从机ACK。
  4. 主机发送重复起始条件(Sr)。
  5. 主机发送7位地址 + R(1),等待从机ACK。
  6. 主机读取数据字节,每字节后主机发送ACK(继续读)或NACK(最后一字节)。
  7. 主机发送停止条件(P)。
Zephyr API对应:
// 写操作:i2c_burst_write + i2c_reg_write_byte
int ret = i2c_reg_write_byte(dev, 0x76, 0x1D, 0x01);  // 向地址0x76的寄存器0x1D写入0x01

// 读操作:i2c_burst_read + i2c_reg_read_byte
uint8_t val;
ret = i2c_reg_read_byte(dev, 0x76, 0x1D, &val);       // 从地址0x76的寄存器0x1D读取1字节
I2C读操作完整时序(写地址→重复起始→读数据) S Addr+W ACK RegAddr ACK Sr Addr+R ACK Data[0] NACK P 读操作流程:S → Addr+W → ACK → RegAddr → ACK → Sr → Addr+R → ACK → Data[0] → NACK → P 重复起始条件(Sr)用于在不释放总线的情况下切换通信方向 最后一字节主机发送NACK,通知从机停止发送 主机→从机 主机→从机 从机→主机

4.5 多主机仲裁与时钟同步

I2C支持多个主机同时连接到总线,通过仲裁(Arbitration)机制决定哪个主机获得总线控制权。仲裁发生在SDA线上,基于“线与”特性:

  • 仲裁原则:多个主机同时发送数据时,谁先拉低SDA谁就赢得仲裁。发送高电平但检测到SDA为低电平的主机失去仲裁,立即释放总线。
  • 时钟同步:多个主机可能产生不同频率的SCL,通过“线与”机制,SCL的低电平时间由最慢的主机决定,高电平时间由最快的主机决定,最终同步出一个共同的时钟。
<
场景 仲裁结果 处理方式
地址匹配 + 数据相同 所有主机继续通信 无冲突,正常传输
地址匹配 + 数据不同 发送0的主机获胜 失败主机释放总线,可重试
地址不同 地址值小的主机获胜 失败主机检测到地址不匹配,释放总线