3. I2C总线协议基础:从物理层到读写操作
各位同学,今天我们聊聊I2C总线。说实话,I2C在SFP模块里太常见了——模块的EEPROM、数字诊断信息,全是通过这两根线读出来的。我刚开始做光模块时,总觉得I2C很简单,不就是两根线嘛。结果有一次调试,模块死活读不到数据,折腾了两天才发现是时序问题。嗯,从那以后,我对I2C再也不敢马虎了。
3.1 I2C物理层:SCL和SDA
I2C总线就两根线:SCL(时钟线)和SDA(数据线)。你想想看,所有设备都挂在这两根线上,靠地址区分,是不是很巧妙?
物理层有几个关键点,我列出来:
- 开漏输出:SCL和SDA都是开漏结构。什么意思?就是只能拉低,不能主动拉高。拉高靠上拉电阻。
- 上拉电阻:一般4.7kΩ或10kΩ。我建议SFP模块用4.7kΩ,因为模块内部还有电容,阻值太大信号上升沿会变缓。
- 线或逻辑:多个设备可以同时拉低总线,谁先拉低谁说了算。这就是仲裁的基础。
- 最大电容:标准模式下总线电容不超过400pF。超过这个值,信号质量会变差。
重要提醒:SFP模块的I2C总线通常由主机(Host)提供上拉电阻。模块内部不要加额外的上拉,否则电阻并联后阻值太小,可能导致信号无法拉高。
我个人习惯在设计SFP模块时,在模块端加一个100Ω的串联电阻,用来抑制振铃。这个做法在高速I2C(400kHz)下特别有用。
3.2 I2C时序:起始条件、停止条件、数据有效性
时序是I2C的核心。说白了,就是SCL和SDA怎么配合,才能让数据正确传输。
3.2.1 起始条件(Start Condition)
起始条件很简单:SCL为高电平时,SDA从高切换到低。这个下降沿告诉所有从设备:总线要开始传输了,大家准备好。
我在项目中遇到过一个问题:主机发送起始条件时,SDA下降沿不够陡峭,导致某些从设备没检测到。后来查了手册,发现是上拉电阻太大,加上总线电容也大,信号边沿变缓了。换成4.7kΩ后问题解决。
3.2.2 停止条件(Stop Condition)
停止条件正好相反:SCL为高电平时,SDA从低切换到高。这个上升沿告诉所有设备:传输结束,总线释放。
小技巧:调试时可以用示波器同时抓SCL和SDA。看到SCL高电平时SDA有跳变,那就是起始或停止条件。我曾经靠这个快速定位了一个地址错误的问题。
3.2.3 数据有效性
数据有效性规则就一句话:SCL高电平时,SDA上的数据必须稳定。数据只能在SCL低电平时改变。
为什么会这样?因为从设备是在SCL的上升沿采样SDA。如果SDA在SCL高电平时变化,采样结果就不确定。
来看一个典型的I2C字节传输时序:
SCL: ████████░░░░████████░░░░████████░░░░...
SDA: ██░░██░░██░░██░░██░░██░░██░░██░░██...
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
D7 D6 D5 D4 D3 D2 D1 D0 ACK
每个字节8位,后面跟一个应答位(ACK)。主机发送完8位后释放SDA,从设备拉低SDA表示应答。
3.3 I2C地址与读写操作
I2C地址是7位的(也有10位地址模式,但SFP模块基本用7位)。每个从设备有一个唯一地址。SFP模块的EEPROM地址通常是0xA0(写)和0xA1(读)。
地址怎么组成?我画个图你就明白了:
7位地址 + 读写位 = 8位数据
例如:SFP EEPROM地址 0x50(7位)
写操作:0x50 << 1 | 0 = 0xA0
读操作:0x50 << 1 | 1 = 0xA1
读写操作流程,我总结成表格:
| 操作 | 流程 | 说明 |
|---|---|---|
| 写操作 | 起始条件 → 发送地址+写位 → 等待ACK → 发送寄存器地址 → 等待ACK → 发送数据 → 等待ACK → 停止条件 | 每次发送后都要等待从设备应答 |
| 读操作 | 起始条件 → 发送地址+写位 → 等待ACK → 发送寄存器地址 → 等待ACK → 重复起始条件 → 发送地址+读位 → 等待ACK → 读取数据 → 发送NACK → 停止条件 | 需要先写寄存器地址,再重新起始读 |
| 连续读写 | 在读写操作中,每传输一个字节后,地址自动+1 | SFP EEPROM支持连续读取,效率高 |
避坑指南:我曾经在连续读取SFP模块的DDM数据时,忘记在最后一个字节发送NACK。结果模块一直拉低SDA,总线被锁死了。记住:读操作的最后一个字节,主机要发送NACK(不拉低SDA),然后发送停止条件。
3.4 知识体系图
下面我用一张图把I2C的核心知识点串起来:
3.5 实战要点总结
最后,我把I2C调试中容易踩的坑列出来:
- 总线锁死:从设备没收到停止条件,一直拉低SDA。解决办法:主机发送9个时钟脉冲,让从设备复位。
- 地址错误:7位地址左移一位后,别忘了加上读写位。我见过有人直接发0x50,结果设备没应答。
- 应答超时:从设备处理慢,没来得及拉低SDA。建议加超时处理,一般5ms就够了。
- 电平不匹配:主机是3.3V,模块是1.8V?需要电平转换。SFP模块通常是3.3V,但有些新模块用1.8V。
我的调试习惯:先用逻辑分析仪抓完整的I2C波形,看起始条件、地址、数据、停止条件是否都对。没问题了再用示波器看信号质量。这样能快速定位问题。
好了,I2C的基础就讲到这里。记住:物理层是骨架,时序是血液,地址是灵魂。三者缺一不可。下一节我们讲SFP模块的EEPROM结构,到时候你会看到I2C怎么实际应用的。