I2C驱动开发实战:从设备地址探测到寄存器读写 - 第1节
1.1 I2C 总线历史与演进
I2C(Inter-Integrated Circuit)总线由 Philips(现 NXP)半导体于 1982 年推出,最初用于电视、音响等消费电子设备中的芯片间短距离通信。其设计目标是以最少的引脚(仅需 SDA 和 SCL 两根线)实现多主设备、多从设备的同步串行通信。
| 版本 | 推出年份 | 最大速率 | 关键特性 |
|---|---|---|---|
| Standard-mode (Sm) | 1982 | 100 kbit/s | 基本 7 位寻址,单主模式 |
| Fast-mode (Fm) | 1992 | 400 kbit/s | 多主仲裁,10 位扩展寻址 |
| Fast-mode Plus (Fm+) | 2007 | 1 Mbit/s | 更强驱动能力,兼容 Fm 时序 |
| High-speed mode (Hs) | 2000 | 3.4 Mbit/s | 主设备间高速握手,从设备可选 |
| Ultra Fast-mode (UFm) | 2012 | 5 Mbit/s | 单向推挽传输,不再需要上拉电阻 |
驱动开发关注点: 嵌入式 Linux 中最常见的是 Standard-mode 和 Fast-mode。Fm+ 在部分传感器和电源管理芯片中开始普及,驱动需注意时序参数差异。
1.2 物理层特性:SDA 与 SCL
I2C 总线使用两根双向开漏(Open-Drain)信号线:
- SDA(Serial Data Line):串行数据线,用于传输地址、控制字和数据。
- SCL(Serial Clock Line):串行时钟线,由主设备产生,同步数据传输。
两根线均为开漏结构,这意味着设备只能将线拉低(输出 0),不能主动拉高。高电平由外部上拉电阻提供。这种设计允许多个设备共享总线,通过线与(Wired-AND)逻辑实现仲裁。
关键物理特性:
- 双向半双工通信:同一时刻只能一个设备驱动 SDA。
- 多主设备仲裁:多个主设备可同时尝试驱动总线,通过 SDA 电平比较决定胜出者。
- 从设备不产生时钟:SCL 始终由当前主设备控制。
1.3 电气连接与上拉电阻
1.3.1 上拉电阻的作用
由于 I2C 总线使用开漏输出,必须通过外部上拉电阻将 SDA 和 SCL 拉至高电平。上拉电阻的核心作用包括:
- 提供高电平:当所有设备释放总线(输出高阻)时,电阻将线拉至 VDD。
- 限制上升时间:电阻值与总线电容共同决定信号上升沿的斜率。
- 支持线与仲裁:多个设备同时拉低时,总线保持低电平,不会发生短路。
1.3.2 上拉电阻值的选择
电阻值的选择需要在功耗、上升时间和噪声容限之间权衡。下表给出典型场景的推荐值:
| 总线模式 | 总线电容 (Cb) | 推荐 Rp 范围 | 典型值 |
|---|---|---|---|
| Standard-mode (100 kHz) | ≤ 400 pF | 1.5 kΩ ~ 10 kΩ | 4.7 kΩ |
| Fast-mode (400 kHz) | ≤ 400 pF | 1.0 kΩ ~ 4.7 kΩ | 2.2 kΩ |
| Fast-mode Plus (1 MHz) | ≤ 550 pF | 0.5 kΩ ~ 2.0 kΩ | 1.0 kΩ |
| High-speed mode (3.4 MHz) | ≤ 100 pF | 0.2 kΩ ~ 1.0 kΩ | 0.5 kΩ |
驱动开发陷阱: 上拉电阻过小会导致低电平输出电压 VOL 超标(IOL 过大),设备可能无法正确识别低电平。电阻过大则上升时间变长,高速模式下信号畸变,导致通信失败。在 Linux 设备树中,部分 SoC 内置可编程上拉,但通常建议外部上拉更可靠。
1.3.3 总线电容与最大从设备数量
I2C 规范规定总线最大电容为 400 pF(Standard/Fast-mode)或 550 pF(Fm+)。每个从设备的引脚电容加上 PCB 走线电容累加后不得超过此限值。典型从设备引脚电容为 5~10 pF,因此一条总线上通常可挂接 8~16 个设备,具体取决于走线长度。
1.4 总线空闲状态与起始/停止条件
I2C 总线在空闲时,SDA 和 SCL 均为高电平(由上拉电阻拉高)。数据传输由主设备产生的起始条件和停止条件界定:
- 起始条件 (S):SCL 为高电平时,SDA 从高电平切换到低电平。
- 停止条件 (P):SCL 为高电平时,SDA 从低电平切换到高电平。
起始和停止条件由主设备独占产生,从设备只能检测但不能主动产生。在 Linux 驱动中,i2c_msg 的 flags 字段通过 I2C_M_STOP 和 I2C_M_NOSTART 控制这些条件的生成。
1.5 数据有效性与时序要求
I2C 的数据采样规则非常严格:
- 数据稳定:在 SCL 高电平期间,SDA 上的数据必须保持稳定。
- 数据变化:在 SCL 低电平期间,SDA 允许变化(准备下一位数据)。
- 字节格式:每次传输 8 位数据(MSB 先发),后跟 1 位应答位(ACK/NACK)。
从设备在每 8 位数据后的第 9 个 SCL 周期拉低 SDA 表示应答(ACK),保持高电平表示非应答(NACK)。NACK 通常用于表示从设备忙、地址不匹配或传输结束。
驱动编程要点: Linux I2C 核心层自动处理起始/停止条件和 ACK/NACK 检测。驱动开发者只需填充
struct i2c_msg 结构体,指定 addr、flags、len 和 buf,由 i2c_transfer() 完成底层时序。
// Linux I2C 消息结构体定义 (include/uapi/linux/i2c.h)
struct i2c_msg {
__u16 addr; // 从设备地址(7 位或 10 位)
__u16 flags; // 传输标志:I2C_M_RD, I2C_M_STOP 等
__u16 len; // 数据长度(字节数)
__u8 *buf; // 数据缓冲区指针
};