2. I2C总线时序详解:7位地址与10位地址模式、读写操作时序、ACK/NACK机制、时钟同步与仲裁

I2C(Inter-Integrated Circuit)总线是一种同步、多主从、串行通信总线,广泛应用于嵌入式系统中连接微控制器与外设(如传感器、EEPROM、ADC/DAC、IO扩展芯片等)。理解其底层时序是编写正确、健壮的I2C设备驱动与设备树映射的前提。本章将深入剖析I2C总线的核心时序要素:地址模式、读写操作、应答机制以及总线冲突解决。

2.1 I2C总线物理层与信号定义

I2C总线仅使用两条双向开漏信号线:

  • SCL(Serial Clock Line):串行时钟线,由主设备驱动。
  • SDA(Serial Data Line):串行数据线,用于传输地址和数据。

两条线均通过上拉电阻连接到VCC。当总线空闲时,SCL和SDA均为高电平。

关键概念: 开漏结构允许多个设备共享总线,通过“线与”逻辑实现仲裁和时钟同步。任何设备都可以将SCL或SDA拉低,但只能释放到高电平(由上拉电阻完成)。

2.2 起始条件与停止条件

总线上数据传输的开始和结束由主设备产生的特定信号定义:

  • 起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
  • 停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
时序规则: 起始和停止条件由主设备独占产生。从设备不允许产生起始或停止条件。
I2C 起始条件与停止条件时序 SCL SDA S P SDA下降沿(SCL高) SDA上升沿(SCL高)

2.3 7位地址模式与10位地址模式

I2C总线支持两种从设备地址格式:7位地址和10位地址。地址在起始条件后立即发送,方向位(R/W)紧随其后。

2.3.1 7位地址模式

7位地址模式是最常用的格式。主设备发送1字节地址帧:高7位为从设备地址,最低位为读写方向位(0=写,1=读)。

位序7 (MSB)6543210 (LSB)
内容从设备地址 (A6:A0)R/W

7位地址范围:0x00 ~ 0x7F。其中0x00为通用呼叫地址,0x01为起始字节,0x02~0x77为可用地址,0x78~0x7F为保留地址。

2.3.2 10位地址模式

10位地址模式用于扩展地址空间。主设备发送两个字节:

  • 第一个字节:高5位为11110,接着是高2位地址(A9:A8),最低位为R/W。
  • 第二个字节:低8位地址(A7:A0)。
字节76543210
第1字节11110A9:A8R/W
第2字节A7:A0
驱动开发注意: 在Linux内核中,10位地址模式需要特殊处理。设备树中需设置 reg = <0x30>; 并配合 i2c-10-bit-address; 属性。驱动中需使用 I2C_M_TEN 标志。
7位地址 vs 10位地址帧结构 7位地址帧: A6:A0 R/W → 共1字节 10位地址帧: 11110 A9:A8 R/W → 第1字节 A7:A0 → 第2字节 7位地址:最多127个从设备 10位地址:最多1023个从设备

2.4 读写操作时序

I2C总线上的数据传输以字节为单位,每个字节后必须跟一个应答位(ACK/NACK)。主设备控制时钟SCL,并在每个时钟脉冲的高电平期间采样SDA数据。

2.4.1 写操作时序

主设备向从设备写入数据:

  1. 主设备产生起始条件(S)。
  2. 主设备发送从设备地址 + 写位(0)。
  3. 从设备在第9个SCL周期发送ACK(拉低SDA)。
  4. 主设备发送1字节数据。
  5. 从设备发送ACK。
  6. 重复步骤4-5,直到数据发送完毕。
  7. 主设备产生停止条件(P)。

2.4.2 读操作时序

主设备从从设备读取数据:

  1. 主设备产生起始条件(S)。
  2. 主设备发送从设备地址 + 读位(1)。
  3. 从设备在第9个SCL周期发送ACK。
  4. 从设备发送1字节数据(主设备释放SDA,从设备驱动SDA)。
  5. 主设备在第9个SCL周期发送ACK(表示继续读)或NACK(表示停止读)。
  6. 重复步骤4-5,直到主设备发送NACK。
  7. 主设备产生停止条件(P)。
组合传输(Combined Transfer): 许多I2C设备(如EEPROM、传感器)需要先写寄存器地址再读数据。此时主设备在写操作后不发送停止条件,而是立即发送重复起始条件(Sr),然后切换为读操作。这种格式称为“组合传输”。
I2C 写操作完整时序(7位地址) S A6 A5 A4 A3 A2 A1 A0 W ACK D7 D6 D5 D4 D3 D2 D1 D0 ACK P 地址阶段(7位地址 + W) A 数据阶段(1字节数据) A P

2.5 ACK/NACK机制

每个字节传输完成后,接收方必须在第9个SCL周期发送应答信号:

  • ACK(Acknowledge):接收方在第9个SCL周期拉低SDA,表示“已收到,请继续”。
  • NACK(Not Acknowledge):接收方在第9个SCL周期保持SDA高电平,表示“未收到”或“停止传输”。
场景发送方接收方应答行为
主设备发送地址主设备从设备从设备ACK:地址匹配;NACK:无此设备或忙
主设备写数据主设备从设备从设备ACK:数据已接收;NACK:无法接收(如缓冲区满)
主设备读数据从设备主设备主设备ACK:继续读下一字节;NACK:停止读
驱动调试要点: 当主设备发送地址后收到NACK,通常表示从设备不存在、地址错误或设备处于复位状态。驱动中应检查 i2c_msg 的返回状态,并实现重试或错误恢复逻辑。

2.6 时钟同步与仲裁

I2C总线支持多主设备环境。时钟同步和仲裁机制确保多个主设备可以共享总线而不会破坏数据。

2.6.1 时钟同步

多个主设备可能同时产生不同频率的时钟。时钟同步通过“线与”特性实现:

  • 所有主设备驱动SCL。如果某个主设备拉低SCL,则SCL被拉低。
  • 只有所有主设备都释放SCL(输出高电平)时,SCL才会被上拉电阻拉高。
  • 结果:SCL的低电平时间由拉低时间最长的主设备决定,高电平时间由拉高时间最短的主设备决定。最终所有主设备同步到统一的时钟周期。

2.6.2 仲裁

当多个主设备同时尝试控制总线时,通过SDA线的“线与”特性进行仲裁:

  1. 每个主设备在发送数据时同时监视SDA电平。
  2. 如果某个主设备试图拉高SDA(发送1),但检测到SDA为低电平(另一个主设备发送0),则该主设备失去仲裁。
  3. 失去仲裁的主设备必须立即释放SDA和SCL,并停止发送数据。
  4. 仲裁可以在地址阶段或数据阶段发生。仲裁失败的主设备可以在总线空闲后重试。
仲裁原则: “低电平优先”。发送0的主设备赢得仲裁。因此,地址值较小的设备在冲突时具有更高优先级。
多主设备时钟同步与仲裁流程 主设备1(地址0x50) 主设备2(地址0x30) 线与仲裁 (低电平优先) 仲裁结果 主设备2赢得总线 时钟同步:SCL低电平时间 = max(主设备1低电平时间, 主设备2低电平时间) SCL高电平时间 = min(主设备1高电平时间, 主设备2高电平时间) 仲裁时序示意: 主设备1 SDA: 1 0 1 0 1 0 1 0 主设备2 SDA: 1 0 0 1 0 1 0 1 总线SDA: 1 0 0 (主设备2赢得仲裁)

2.7 时序参数与高速模式

I2C总线定义了多种工作模式,不同模式下的时序参数不同:

参数标准模式 (100 kHz)快速模式 (400 kHz)高速模式 (3.4 MHz)
SCL时钟频率100 kHz400 kHz3.4 MHz
SCL低电平时间4.7 μs1.3 μs0.16 μs
SCL高电平时间4.0 μs0.6 μs0.06 μs
上升时间1000 ns300 ns160 ns
下降时间300 ns300 ns80 ns
数据保持时间0 ns0 ns10 ns
驱动配置建议: 在设备树中通过 clock-frequency 属性设置I2C总线频率。对于大多数传感器外设,100 kHz或400 kHz是安全选择。高速模式需要硬件支持,且对PCB布局有严格要求。

2.8 总结:I2C时序在驱动开发中的关键点

  • 地址匹配:驱动中必须正确设置从设备地址(7位或10位),设备树中 reg 属性对应地址。
  • ACK检测:每次传输后检查ACK状态。NACK通常表示设备故障或地址错误。
  • 组合传输:使用 i2c_master_send() 和 i2c_master_recv() 时注意内部实现;复杂场景使用 i2c_transfer() 发送 i2c_msg 数组。
  • 时钟拉伸:某些从设备在需要处理数据时会拉低SCL(时钟拉伸)。主设备必须支持时钟拉伸,否则会导致总线挂死。
  • 仲裁处理:多主设备系统中,驱动应实现重试机制以应对仲裁失败。