1. I2C总线概述
I2C(Inter-Integrated Circuit)总线是由Philips公司(现NXP)在1980年代推出的一种同步、多主从、串行通信总线。它仅需两根信号线——串行数据线(SDA)和串行时钟线(SCL),即可实现芯片间的短距离通信,是嵌入式系统中使用最广泛的板级总线之一。
1.1 物理层特性
| 参数 | 标准模式 (Standard) | 快速模式 (Fast) | 高速模式 (High-Speed) |
|---|---|---|---|
| 最高时钟频率 | 100 kHz | 400 kHz | 3.4 MHz |
| 总线最大电容 | 400 pF | 400 pF | 100 pF |
| 最大从设备数量 | 受限于地址空间(7位:127个) | 受限于地址空间 | 受限于地址空间 |
| 输出级 | 开漏 | 开漏 | 开漏 + 电流源 |
1.2 电气连接与上拉电阻
I2C总线采用开漏(Open-Drain)结构,所有设备的SDA和SCL引脚内部为MOS管漏极开路输出。总线空闲时,两根线均被外部上拉电阻拉至高电平(VDD)。
- 上拉电阻阻值选择:取决于总线电容和通信速率。典型值在1 kΩ ~ 10 kΩ之间。
- 逻辑电平:低电平为0V,高电平为VDD(通常为1.8V、3.3V或5V)。
- 线与特性:多个设备可以同时将总线拉低,实现仲裁和时钟同步。
驱动开发提示:在Linux设备树中,上拉电阻通常由硬件设计决定,驱动无需配置。但需注意I2C控制器IP的电气特性是否支持标准/快速/高速模式,这直接影响时钟频率的设定。
1.3 SDA/SCL信号时序
I2C总线的数据传输以起始条件(START)开始,以停止条件(STOP)结束。数据在SCL时钟高电平时采样,低电平时变化。
- 空闲状态:SCL = 1,SDA = 1。
- 起始条件(S):SCL = 1 时,SDA 从 1 跳变到 0。
- 数据位传输:SCL 低电平时 SDA 变化,SCL 高电平时 SDA 被采样。
- 停止条件(P):SCL = 1 时,SDA 从 0 跳变到 1。
- 应答位(ACK):每传输8位数据后,接收方在第9个时钟周期将SDA拉低表示应答。
关键时序参数(标准模式):tHD;STA ≥ 4.0 μs(起始保持时间),tSU;STO ≥ 4.0 μs(停止建立时间),tLOW ≥ 4.7 μs(时钟低电平时间),tHIGH ≥ 4.0 μs(时钟高电平时间)。
1.4 I2C协议基础
I2C协议定义了完整的通信帧格式,包括地址、读写方向、数据和应答机制。
1.4.1 帧格式
| S | 7位从设备地址 | R/W | ACK | 8位数据字节 | ACK | ... | 8位数据字节 | ACK/NACK | P |
- S:起始条件
- 7位从设备地址:高7位为设备地址,最低位为读写位(0=写,1=读)
- R/W:读写方向位
- ACK:从设备应答(低电平有效)
- 数据字节:MSB优先,每字节后跟ACK
- P:停止条件
1.4.2 读写操作流程
写操作流程:主机发送起始条件 → 发送从设备地址+写位(0) → 等待ACK → 发送寄存器地址 → 等待ACK → 发送数据字节 → 等待ACK → ... → 发送停止条件。
读操作流程:主机发送起始条件 → 发送从设备地址+写位(0) → 等待ACK → 发送寄存器地址 → 等待ACK → 发送重复起始条件(Sr) → 发送从设备地址+读位(1) → 等待ACK → 读取数据字节 → 主机发送NACK → 发送停止条件。
1.4.3 10位地址与扩展
7位地址空间最多支持127个从设备(0x00为广播地址,0x01~0x7F可用)。I2C规范也支持10位地址模式,通过保留地址0xF0~0xF7作为前缀来扩展地址空间。
| 地址类型 | 地址范围 | 最大设备数 | 常见用途 |
|---|---|---|---|
| 7位地址 | 0x01 ~ 0x7F | 127 | 大多数传感器、EEPROM、ADC/DAC |
| 10位地址 | 0x000 ~ 0x3FF | 1024 | 复杂外设、多路复用器 |
| 保留地址 | 0x00, 0xF0~0xFF | — | 广播、10位前缀、特殊命令 |
1.5 I2C总线在嵌入式系统中的角色
在Linux嵌入式系统中,I2C总线主要用于连接低速外设,如:
- 传感器:温度传感器(LM75)、湿度传感器(SHT20)、加速度计(MPU6050)
- 存储设备:EEPROM(AT24Cxx)、铁电存储器(FM24CLxx)
- 接口扩展:GPIO扩展器(PCA9535)、ADC/DAC(ADS1115)
- 多媒体:音频编解码器(WM8731)、HDMI接口(TDA998x)
驱动开发注意事项:I2C从设备地址通常由硬件引脚(如A0/A1/A2)决定,同一总线上不能出现地址冲突。在设备树中通过
reg = <0x48>; 属性指定,驱动通过 i2c_client->addr 获取。