1. I2C总线概述

1.1 I2C总线历史

I2C(Inter-Integrated Circuit)总线由飞利浦半导体(现恩智浦半导体)于1982年发明,最初用于电视接收机中微控制器与外设之间的低速通信。其设计目标是以最少的引脚数(仅需两根线)实现芯片间的可靠通信。

时间 里程碑 关键特性
1982年 飞利浦发布I2C总线规范v1.0 标准模式100 kbit/s,7位地址
1992年 规范升级至v2.0 增加快速模式400 kbit/s,10位地址
1998年 规范升级至v2.1 完善时序参数,统一命名
2007年 NXP发布v3.0 增加高速模式3.4 Mbit/s
2012年 NXP发布v4.0 超快速模式5 Mbit/s,仅单向
2014年 NXP发布v5.0 增加US模式,统一文档
内核开发者视角: Linux内核自2.6系列起内置了完善的I2C子系统(drivers/i2c/),支持标准、快速、高速三种模式。嵌入式显示驱动中,DDC/CI、EDID读取、触摸控制器、背光调节等场景均依赖I2C总线。

1.2 物理层特性

I2C总线采用开漏(Open-Drain)结构,仅需两根信号线:

  • SDA(Serial Data Line):串行数据线,双向传输
  • SCL(Serial Clock Line):串行时钟线,由主设备驱动

电气连接要点:

  • 所有设备的SDA和SCL引脚均为开漏输出,通过上拉电阻连接至VDD(通常为3.3V或5V)
  • 总线空闲时,SDA和SCL均为高电平(由上拉电阻拉高)
  • 设备通过将对应引脚拉低来驱动总线
  • 上拉电阻典型值:1kΩ~10kΩ(取决于总线电容和速率)
  • 总线电容限制:标准模式≤400pF,快速模式≤200pF
显示驱动中的典型连接: 在嵌入式显示系统中,I2C总线通常连接:
  • HDMI/DVI的DDC通道(EDID读取)
  • 触摸屏控制器(如FT5x06、GT911)
  • 背光驱动芯片(如TI LP8556)
  • 显示面板的配置寄存器(如MIPI DSI桥接芯片)
I2C总线电气连接示意图 Rₚ Rₚ VDD (3.3V) SDA SCL 主设备 (SoC/CPU) 从设备1 (EDID EEPROM) 从设备2 (触摸控制器) 所有设备共享SDA和SCL两条总线,通过唯一地址区分 上拉电阻Rₚ确保总线空闲时为高电平

1.3 SDA/SCL信号时序

I2C总线的数据传输遵循严格的时序协议,核心信号包括:

信号事件 SDA状态 SCL状态 说明
起始条件(S) 高→低 高 SCL为高时,SDA由高变低
停止条件(P) 低→高 高 SCL为高时,SDA由低变高
数据位传输 稳定数据 高→低→高 SCL低时改变SDA,SCL高时采样
应答位(ACK) 低(应答) 第9个时钟脉冲 接收方拉低SDA表示应答
非应答位(NACK) 高 第9个时钟脉冲 接收方释放SDA表示非应答
调试陷阱: 在Linux内核I2C驱动调试中,最常见的硬件问题是:
  • SDA或SCL被拉死(一直为低)→ 检查上拉电阻和从设备是否异常
  • 无应答(NACK)→ 地址错误、设备未上电或总线速率不匹配
  • 时钟拉伸(Clock Stretching)→ 从设备拉低SCL,主设备需等待
I2C总线起始条件与数据位时序 SCL SDA S P D7 D6 D5 D4 D3 D2 D1 D0 SCL高电平时采样SDA数据,SCL低电平时允许SDA变化 起始条件:SCL高时SDA由高→低;停止条件:SCL高时SDA由低→高 每个字节后跟一个应答位(ACK/NACK)

1.4 I2C地址与仲裁机制

地址格式

I2C总线使用两种地址格式:

地址类型 位数 可用地址数 地址范围 典型应用
7位地址 7 112(保留16个) 0x08 ~ 0x77 大多数I2C设备(EDID、触摸、背光)
10位地址 10 1024 0x000 ~ 0x3FF 需要更多地址的复杂系统
显示驱动中的常见I2C地址:
  • EDID EEPROM(DDC通道):0x50(7位地址)
  • HDMI DDC:0x50 ~ 0x5F(取决于显示器和显卡)
  • 触摸控制器FT5x06:0x38
  • 触摸控制器GT911:0x5D 或 0x14
  • 背光驱动LP8556:0x2C

仲裁机制

I2C总线支持多主设备通信,仲裁机制确保多个主设备同时发起传输时不会造成数据冲突:

  • 仲裁发生在SDA线上:多个主设备同时输出数据时,输出低电平的设备会“覆盖”输出高电平的设备
  • 仲裁原则:谁先输出低电平,谁赢得总线控制权
  • 丢失仲裁的设备:检测到SDA电平与自己输出不一致时,立即释放SDA和SCL,转为从模式
  • 仲裁不破坏数据:赢得仲裁的设备继续传输,丢失仲裁的设备不产生数据损坏
  • 时钟同步:多个主设备通过SCL线与逻辑实现时钟同步,以最慢设备的时钟为准
I2C总线仲裁机制流程 主设备1 输出:0x50(写) 主设备2 输出:0x51(写) SDA仲裁 线与逻辑检测 赢得仲裁 主设备1继续传输 丢失仲裁 主设备2释放总线 仲裁关键规则 1. 仲裁在SDA线上进行,SCL由所有主设备同步 2. 输出低电平的设备赢得仲裁(线与逻辑:低覆盖高) 3. 丢失仲裁的设备立即释放总线,转为从模式 4. 仲裁过程不破坏数据完整性,赢得仲裁的设备继续正常传输 5. 显示驱动中通常只有一个主设备(SoC),仲裁主要用于多主场景

1.5 数据传输格式

I2C总线上的数据以帧为单位传输,每帧包含:

  1. 起始条件(S)
  2. 从设备地址(7位或10位) + 读写位(R/W)
  3. 从设备应答位(ACK)
  4. 数据字节(8位) + 应答位(可重复多次)
  5. 停止条件(P)
Linux内核中的I2C消息结构:
struct i2c_msg {
    __u16 addr;    /* 从设备地址(7位或10位) */
    __u16 flags;   /* 标志位:I2C_M_RD(读)、I2C_M_TEN(10位地址)等 */
    __u16 len;     /* 消息数据长度(字节数) */
    __u8 *buf;     /* 数据缓冲区指针 */
};

显示驱动中典型的I2C读写操作:先写寄存器地址,再读寄存器值。

I2C写操作帧格式(7位地址) S 地址(7bit) 0x50 R/W 0 ACK 寄存器地址 0x1A ACK 数据字节 0x55 ACK P 写操作:主设备发送从设备地址(R/W=0),然后发送寄存器地址,最后写入数据 每个字节后从设备必须回复ACK,否则主设备终止传输 显示驱动调试时,使用 i2cget/i2cset 工具或 /sys/bus/i2c 接口验证通信