2. I2C总线协议基础
I2C(Inter-Integrated Circuit)总线是嵌入式系统中最常用的板级通信协议之一,由Philips(现NXP)在1980年代开发。在车载嵌入式系统中,I2C广泛用于连接传感器(如温度、压力、光照)、编解码器、触摸控制器、EEPROM、RTC、ADC/DAC等外设。本章从物理层、通信时序、地址模式三个维度深入剖析I2C协议,为后续Linux内核I2C子系统与设备树配置打下坚实基础。
2.1 I2C物理层
2.1.1 总线信号与拓扑
I2C总线仅使用两根双向信号线:
- SDA(Serial Data Line):串行数据线,用于传输地址、数据和控制信息。
- SCL(Serial Clock Line):串行时钟线,由主设备产生,同步所有数据传输。
总线采用开漏(Open-Drain)结构,所有设备的SDA和SCL引脚均为开漏输出,通过外部上拉电阻连接到电源电压(VDD)。这种结构允许多个设备共享总线,实现“线与”逻辑:任何设备拉低总线时,总线即为低电平;只有所有设备释放总线时,总线才被上拉至高电平。
2.1.2 上拉电阻与电平
| 参数 | 标准模式 (100kHz) | 快速模式 (400kHz) | 高速模式 (1MHz) |
|---|---|---|---|
| 最大上升时间 (tr) | 1000 ns | 300 ns | 120 ns |
| 最大总线电容 (Cb) | 400 pF | 400 pF | 550 pF |
| 推荐上拉电阻 (Rp) | 4.7kΩ ~ 10kΩ | 2.2kΩ ~ 4.7kΩ | 1.5kΩ ~ 2.2kΩ |
| 逻辑低电平 (VIL) | ≤ 0.3 × VDD | ||
| 逻辑高电平 (VIH) | ≥ 0.7 × VDD | ||
在车载系统中,I2C总线电平通常与主控SoC的I/O电压一致(如1.8V、3.3V或5V)。当连接不同电平的外设时,必须使用电平转换器(如PCA9306)或选择支持多电压的I2C缓冲器。
2.2 I2C通信时序
I2C通信以主设备(Master)发起、从设备(Slave)响应的方式进行。每次传输包含起始条件、从设备地址、读写位、数据字节和应答位,最后以停止条件结束。
2.2.1 起始条件与停止条件
起始条件(START)和停止条件(STOP)是I2C总线上的特殊信号,由主设备产生:
- 起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
- 停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
总线在起始条件后进入忙(Busy)状态,在停止条件后恢复空闲(Idle)状态。主设备可以在一次传输中连续发送多个数据帧,中间使用重复起始条件(Repeated START, Sr)而不产生停止条件,用于改变传输方向或切换从设备。
2.2.2 数据有效性
I2C协议规定:在SCL时钟的高电平期间,SDA上的数据必须保持稳定;在SCL的低电平期间,SDA允许变化。这意味着数据采样发生在SCL的上升沿或高电平期间,而数据更新发生在SCL的低电平期间。
每个数据字节长度为8位(MSB优先),后面紧跟一个应答位。因此,每传输一个字节需要9个SCL时钟周期。
2.2.3 应答机制(ACK/NACK)
应答机制是I2C协议可靠性的核心:
- 应答(ACK):在第9个时钟周期,接收方将SDA拉低,表示已成功接收上一个字节。
- 非应答(NACK):在第9个时钟周期,接收方保持SDA为高电平,表示未成功接收或希望结束传输。
主设备在以下情况会生成NACK:
- 读取操作的最后一次数据接收后,主设备发送NACK以通知从设备停止发送。
- 从设备地址不匹配或从设备忙时,从设备回复NACK。
- 数据校验错误或协议违规时。
2.3 7位与10位地址模式
2.3.1 7位地址模式
7位地址模式是I2C最常用的寻址方式。主设备在起始条件后发送的第一个字节包含:
- 高7位(bit 7 ~ bit 1):从设备地址。
- 最低位(bit 0):读写标志(0 = 写,1 = 读)。
理论上7位地址可支持128个从设备,但地址0x00(通用呼叫地址)和0x01(起始字节)被保留,实际可用地址范围为0x02~0x7F。许多外设通过配置引脚(如A0、A1、A2)选择多个可用地址,以支持同一总线上挂载多个相同型号的器件。
2.3.2 10位地址模式
10位地址模式用于需要超过128个从设备的场景。主设备发送两个字节来寻址:
- 第一个字节:高5位为11110,紧接着高2位地址(bit 9~bit 8),最后是读写位。
- 第二个字节:低8位地址(bit 7~bit 0)。
10位地址模式与7位地址模式在总线上兼容:从设备通过第一个字节的高5位(11110)识别是否为10位地址模式。在车载系统中,10位地址模式较少使用,但在高端ADAS摄像头模块或复杂传感器融合单元中可能遇到。
| 特性 | 7位地址模式 | 10位地址模式 |
|---|---|---|
| 地址范围 | 0x02 ~ 0x7F(126个可用) | 0x000 ~ 0x3FF(1024个可用) |
| 寻址字节数 | 1字节(含读写位) | 2字节(首字节含11110前缀) |
| 兼容性 | 所有I2C设备均支持 | 需从设备明确支持 |
| 车载使用频率 | 极高(95%以上外设) | 低(仅特殊传感器/扩展器) |
| Linux内核表示 | 直接使用7位值(如0x48) | 需设置I2C_TENBIT标志 |
2.4 典型I2C通信流程
一个完整的I2C写操作时序如下(以7位地址为例):
- 主设备产生起始条件(S)。
- 主设备发送从设备地址 + 写标志(0)(共1字节)。
- 从设备回复ACK(拉低SDA)。
- 主设备发送寄存器地址/命令字节(1字节)。
- 从设备回复ACK。
- 主设备发送数据字节(1字节或多字节)。
- 每发送一个字节,从设备回复ACK。
- 主设备产生停止条件(P)。
读操作类似,但在发送寄存器地址后,主设备使用重复起始条件(Sr)重新发送从设备地址 + 读标志(1),然后从设备开始发送数据,主设备每接收一个字节后回复ACK,最后一个字节回复NACK并产生停止条件。
struct i2c_msg结构体数组描述,由i2c_transfer()函数执行。驱动开发者只需填充消息结构,无需手动操作SDA/SCL时序——这是I2C核心层和适配器驱动的职责。