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从低电平切换到高电平。
时序规则: 起始和停止条件由主设备独占产生。从设备不允许产生起始或停止条件。
2.3 7位地址模式与10位地址模式
I2C总线支持两种从设备地址格式:7位地址和10位地址。地址在起始条件后立即发送,方向位(R/W)紧随其后。
2.3.1 7位地址模式
7位地址模式是最常用的格式。主设备发送1字节地址帧:高7位为从设备地址,最低位为读写方向位(0=写,1=读)。
| 位序 | 7 (MSB) | 6 | 5 | 4 | 3 | 2 | 1 | 0 (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)。
| 字节 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| 第1字节 | 1 | 1 | 1 | 1 | 0 | A9:A8 | R/W | |
| 第2字节 | A7:A0 | |||||||
驱动开发注意: 在Linux内核中,10位地址模式需要特殊处理。设备树中需设置
reg = <0x30>; 并配合 i2c-10-bit-address; 属性。驱动中需使用 I2C_M_TEN 标志。
2.4 读写操作时序
I2C总线上的数据传输以字节为单位,每个字节后必须跟一个应答位(ACK/NACK)。主设备控制时钟SCL,并在每个时钟脉冲的高电平期间采样SDA数据。
2.4.1 写操作时序
主设备向从设备写入数据:
- 主设备产生起始条件(S)。
- 主设备发送从设备地址 + 写位(0)。
- 从设备在第9个SCL周期发送ACK(拉低SDA)。
- 主设备发送1字节数据。
- 从设备发送ACK。
- 重复步骤4-5,直到数据发送完毕。
- 主设备产生停止条件(P)。
2.4.2 读操作时序
主设备从从设备读取数据:
- 主设备产生起始条件(S)。
- 主设备发送从设备地址 + 读位(1)。
- 从设备在第9个SCL周期发送ACK。
- 从设备发送1字节数据(主设备释放SDA,从设备驱动SDA)。
- 主设备在第9个SCL周期发送ACK(表示继续读)或NACK(表示停止读)。
- 重复步骤4-5,直到主设备发送NACK。
- 主设备产生停止条件(P)。
组合传输(Combined Transfer): 许多I2C设备(如EEPROM、传感器)需要先写寄存器地址再读数据。此时主设备在写操作后不发送停止条件,而是立即发送重复起始条件(Sr),然后切换为读操作。这种格式称为“组合传输”。
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线的“线与”特性进行仲裁:
- 每个主设备在发送数据时同时监视SDA电平。
- 如果某个主设备试图拉高SDA(发送1),但检测到SDA为低电平(另一个主设备发送0),则该主设备失去仲裁。
- 失去仲裁的主设备必须立即释放SDA和SCL,并停止发送数据。
- 仲裁可以在地址阶段或数据阶段发生。仲裁失败的主设备可以在总线空闲后重试。
仲裁原则: “低电平优先”。发送0的主设备赢得仲裁。因此,地址值较小的设备在冲突时具有更高优先级。
2.7 时序参数与高速模式
I2C总线定义了多种工作模式,不同模式下的时序参数不同:
| 参数 | 标准模式 (100 kHz) | 快速模式 (400 kHz) | 高速模式 (3.4 MHz) |
|---|---|---|---|
| SCL时钟频率 | 100 kHz | 400 kHz | 3.4 MHz |
| SCL低电平时间 | 4.7 μs | 1.3 μs | 0.16 μs |
| SCL高电平时间 | 4.0 μs | 0.6 μs | 0.06 μs |
| 上升时间 | 1000 ns | 300 ns | 160 ns |
| 下降时间 | 300 ns | 300 ns | 80 ns |
| 数据保持时间 | 0 ns | 0 ns | 10 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(时钟拉伸)。主设备必须支持时钟拉伸,否则会导致总线挂死。
- 仲裁处理:多主设备系统中,驱动应实现重试机制以应对仲裁失败。