2. 硬件基础:I2C总线物理层协议、时序与地址

I2C(Inter-Integrated Circuit)总线是一种由Philips(现NXP)开发的同步、多主从、串行通信总线。在嵌入式Linux驱动开发中,理解I2C的硬件基础是正确配置设备树、调试驱动时序的前提。本节从物理层、时序协议、地址与读写操作三个维度展开。

2.1 I2C总线物理层协议

I2C总线仅使用两条双向开漏线:SCL(串行时钟线)和SDA(串行数据线)。所有设备通过这两条线并联在总线上,通过唯一地址进行区分。

信号线 类型 功能描述 电气特性
SCL 时钟线 由主设备驱动,同步数据传输 开漏输出,需上拉电阻
SDA 数据线 双向传输地址和数据 开漏输出,需上拉电阻
关键点:开漏结构允许多个设备共享总线,通过“线与”逻辑实现仲裁。上拉电阻通常选择4.7kΩ(标准模式)或1.5kΩ(快速模式),具体值取决于总线电容和速率。

I2C总线支持多种速率模式,常见标准如下:

  • 标准模式(Sm):100 kbit/s
  • 快速模式(Fm):400 kbit/s
  • 快速模式+(Fm+):1 Mbit/s
  • 高速模式(Hs):3.4 Mbit/s

在嵌入式Linux系统中,大多数传感器、EEPROM、RTC、音频编解码器使用标准模式或快速模式。设备树中通过 clock-frequency 属性指定总线速率。

I2C总线物理连接拓扑 Rp Rp VDD (3.3V / 5V) SCL SDA 主设备 (Master) 从设备 1 (0x50 EEPROM) 从设备 2 (0x76 传感器) 所有设备共享SCL和SDA线,通过唯一7位或10位地址区分 上拉电阻Rp连接至VDD,确保总线空闲时为高电平

2.2 I2C时序:起始条件、停止条件与数据有效性

I2C总线的数据传输由主设备控制,每个传输周期以起始条件(START)开始,以停止条件(STOP)结束。数据在SCL时钟的配合下逐位传输。

2.2.1 起始条件(S)

当SCL为高电平时,SDA从高电平切换到低电平。此信号表示总线从空闲状态进入忙碌状态,所有从设备开始监听后续地址。

2.2.2 停止条件(P)

当SCL为高电平时,SDA从低电平切换到高电平。此信号表示传输结束,总线释放为空闲状态。

2.2.3 数据有效性

  • 数据稳定:在SCL高电平期间,SDA上的数据必须保持稳定。
  • 数据变化:仅在SCL低电平期间,SDA允许变化。
  • 字节格式:每次传输8位数据(MSB先行),后跟1位应答位(ACK/NACK)。
驱动调试提示:在Linux中,I2C控制器驱动负责硬件时序的精确生成。如果设备树中配置的 clock-frequency 过高,或上拉电阻不匹配,可能导致SCL高电平时间不足,造成从设备无应答(NACK)。此时应检查逻辑分析仪抓取的时序波形。
I2C 时序:起始条件、数据有效性、停止条件 SCL SDA START STOP 数据位 (MSB → LSB) ACK SCL高电平时SDA必须保持稳定,数据在SCL低电平时变化 起始条件:SCL高 → SDA下降沿;停止条件:SCL高 → SDA上升沿

2.3 I2C地址与读写操作

每个I2C从设备都有一个唯一的设备地址,用于主设备在通信开始时进行寻址。地址分为7位和10位两种格式,嵌入式系统中以7位地址最为常见。

2.3.1 7位地址格式

主设备在起始条件后发送的第一个字节包含7位地址和1位读写标志(R/W)。

位序 7 (MSB) 6 5 4 3 2 1 0 (LSB)
内容 A6 A5 A4 A3 A2 A1 A0 R/W
说明 7位设备地址 0=写,1=读
地址示例:EEPROM AT24C02的7位地址为 0x50(二进制 1010000)。写操作时发送字节 0xA0(10100000),读操作时发送字节 0xA1(10100001)。

2.3.2 读写操作流程

一次完整的I2C传输遵循以下步骤:

  1. 主设备发送起始条件(S):总线从空闲变为忙碌。
  2. 主设备发送从设备地址 + R/W位:所有从设备接收并比对地址。
  3. 被寻址的从设备发送应答位(ACK):拉低SDA表示确认。
  4. 数据传输:主设备(写模式)或从设备(读模式)逐字节发送数据,每字节后跟ACK。
  5. 主设备发送停止条件(P):总线释放为空闲。
I2C 写操作帧格式(7位地址) S 从设备地址 (7位) 0 ACK 寄存器地址 (8位) ACK 数据字节 (8位) ACK P 起始 地址 写 应答 寄存器 应答 数据 应答 停止 主设备控制:S、地址、R/W、数据、P;从设备控制:ACK 读操作时,R/W=1,从设备发送数据,主设备发送ACK/NACK

2.4 多主设备与仲裁

I2C总线支持多个主设备同时尝试控制总线。仲裁机制基于开漏结构的“线与”特性:

  • 仲裁过程:多个主设备同时发送起始条件,在SDA上逐位比较。如果某个主设备试图拉低SDA而检测到高电平(另一主设备已拉低),则该主设备失去仲裁,立即释放总线。
  • 仲裁不丢失数据:由于数据位本身是“线与”结果,赢得仲裁的主设备继续传输,不会破坏已发送的数据。
  • 时钟同步:多个主设备通过SCL的“线与”实现时钟同步,所有设备以最慢的SCL低电平周期为准。
嵌入式开发注意:在Linux系统中,I2C控制器驱动通常只配置为主设备模式。如果系统需要多主设备支持,必须确保硬件控制器支持多主模式,并在设备树中正确配置 multi-master 属性。大多数嵌入式SoC的I2C控制器默认仅支持单主模式。

2.5 总结:I2C硬件基础要点

知识点 核心内容 驱动开发关联
物理层 SCL/SDA开漏 + 上拉电阻 设备树中配置clock-frequency影响上拉电阻选择
起始/停止条件 SCL高电平时SDA的下降沿/上升沿 控制器驱动自动生成,但需检查时序是否满足从设备要求
数据有效性 SCL高电平数据稳定,低电平变化 驱动中数据移位操作需与SCL边沿对齐
7位地址 地址字节高7位为设备地址,最低位为R/W 设备树中 reg 属性填写7位地址值
读写操作 写:地址+0 + 数据;读:地址+1 + 接收数据 Linux I2C核心层通过 i2c_msg 结构体封装读写操作
多主仲裁 基于“线与”的逐位仲裁 设备树中 multi-master 属性控制