3、I2C/SPI通信协议:I2C协议基础、SPI协议基础、在Retimer中如何选择通信接口、时序分析与常见问题
做固件开发这些年,打交道最多的就是I2C和SPI。说白了,Retimer芯片的配置、状态读取、固件升级,全靠这两个接口。你想想看,如果通信都搞不定,后面所有工作都是白搭。
今天咱们就把这两个协议掰开揉碎了讲。我会结合自己在Retimer项目中的实际踩坑经历,帮你把基础打牢。
3.1 I2C协议基础
I2C,Inter-Integrated Circuit,飞利浦公司发明的。两根线:SCL(时钟)和SDA(数据)。我刚开始接触时觉得它很简单,后来才发现,越简单的东西越容易出幺蛾子。
3.1.1 总线结构
I2C是主从架构。一个总线上可以挂多个设备,每个设备有唯一地址。7位地址模式最多支持127个设备,10位地址模式可以更多。但实际项目中,我建议一个总线上别超过10个设备,否则电容负载太大,信号容易变形。
关键点:I2C是开漏输出,必须外接上拉电阻。阻值选多大?我个人习惯:标准模式100kHz用4.7kΩ,快速模式400kHz用2.2kΩ。如果总线电容大,电阻要更小。
3.1.2 通信时序
I2C的时序其实就几个关键动作:起始条件、停止条件、数据传送、应答信号。
// 起始条件:SCL高电平时,SDA从高变低
// 停止条件:SCL高电平时,SDA从低变高
// 数据传送:SCL低电平时改变SDA,SCL高电平时采样SDA
// 应答信号:第9个时钟周期,从机拉低SDA表示ACK
嗯,这里要注意:每个字节必须跟一个ACK/NACK。如果从机没拉低SDA,主机要发送停止条件或者重新起始条件。我在项目中遇到过,有些Retimer芯片在忙的时候会NACK,这时候需要主机重试。
3.1.3 读写操作
I2C的读写流程是这样的:
- 写操作:起始条件 → 设备地址+写位(0) → ACK → 寄存器地址 → ACK → 数据字节 → ACK → ... → 停止条件
- 读操作:起始条件 → 设备地址+写位(0) → ACK → 寄存器地址 → ACK → 重新起始条件 → 设备地址+读位(1) → ACK → 读取数据 → NACK → 停止条件
我的经验:读操作时,最后一个字节主机要发送NACK,告诉从机不用再发了。我曾经忘了这个细节,结果从机一直发数据,总线被锁死。
3.2 SPI协议基础
SPI,Serial Peripheral Interface,摩托罗拉发明的。四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。
说白了,SPI就是全双工、同步、高速的通信方式。Retimer固件升级时,我更喜欢用SPI,因为速度快,而且没有I2C那些地址和应答的麻烦。
3.2.1 四种模式
SPI有四种模式,由时钟极性(CPOL)和时钟相位(CPHA)决定:
| 模式 | CPOL | CPHA | 数据采样边沿 |
|---|---|---|---|
| 模式0 | 0 | 0 | 上升沿采样 |
| 模式1 | 0 | 1 | 下降沿采样 |
| 模式2 | 1 | 0 | 上升沿采样 |
| 模式3 | 1 | 1 | 下降沿采样 |
警告:Retimer芯片的SPI模式一定要看数据手册。我见过有人用模式0去驱动只支持模式3的芯片,结果数据全是乱的。别问我怎么知道的。
3.2.2 通信流程
SPI的通信流程比I2C简单:
- 主机拉低CS,选中从机
- 主机在SCLK上产生时钟
- 主机通过MOSI发送数据,同时通过MISO接收数据
- 传输完成后,主机拉高CS
注意:SPI是全双工的,每发送一个字节,同时也会收到一个字节。如果只需要发送,接收的数据可以忽略。如果只需要接收,可以发送0x00或0xFF作为占位符。
3.3 在Retimer中如何选择通信接口
这个问题,我经常被问到。其实没有绝对的好坏,关键看场景。
我画了一张图,帮你理清思路:
我个人习惯是这样的:
- 配置和监控:用I2C。因为只需要读写几个寄存器,I2C的地址机制很方便,而且线少。
- 固件升级:用SPI。固件文件通常几百KB甚至几MB,I2C的400kHz速度太慢了。SPI可以跑到几十MHz,快很多。
- 调试:两个都用。I2C用来查看状态,SPI用来下载固件。
避坑指南:有些Retimer芯片的I2C地址是可以配置的。如果板子上有多个Retimer,记得给它们分配不同的地址。我曾经因为两个芯片地址冲突,折腾了两天才发现。
3.4 时序分析与常见问题
时序问题,是通信协议里最让人头疼的。我见过太多工程师,代码写得没问题,但就是通信失败,最后发现是时序不满足要求。
3.4.1 I2C时序关键参数
| 参数 | 标准模式(100kHz) | 快速模式(400kHz) | 说明 |
|---|---|---|---|
| SCL时钟频率 | ≤100kHz | ≤400kHz | 别超了,超了芯片不认 |
| SCL低电平时间 | ≥4.7μs | ≥1.3μs | 时钟低电平要保持够长 |
| SCL高电平时间 | ≥4.0μs | ≥0.6μs | 时钟高电平也要够长 |
| 数据建立时间 | ≥250ns | ≥100ns | 数据要在时钟上升沿前稳定 |
| 数据保持时间 | ≥0ns | ≥0ns | 数据在时钟下降沿后保持 |
注意:有些MCU的I2C外设,时钟频率设置不准确。比如你设了400kHz,实际可能只有350kHz或者450kHz。最好用示波器量一下实际波形。
3.4.2 SPI时序关键参数
SPI的时序参数相对宽松,但有几个点要注意:
- SCLK频率:看数据手册,一般Retimer支持到几十MHz。但PCB走线长了,频率要降低。
- CS建立时间:CS拉低后,要等一段时间再发时钟。这个时间通常几ns到几十ns。
- CS保持时间:最后一个时钟结束后,CS要保持低电平一段时间再拉高。
- 数据有效时间:数据在时钟边沿前后要稳定。
3.4.3 常见问题与解决方法
我整理了几个高频问题,都是我在项目中真实遇到过的:
- I2C总线锁死
现象:SDA一直被拉低,无法通信。
原因:从机异常,或者主机在通信过程中被中断。
解决:连续发送9个时钟脉冲,让从机释放总线。或者硬件复位。
- SPI数据错位
现象:读回来的数据跟预期不符,但波形看起来没问题。
原因:SPI模式不匹配,或者时钟相位设置错误。
解决:用示波器看数据是在上升沿还是下降沿变化,确认模式。
- 通信速度上不去
现象:设了高速,但实际通信失败。
原因:PCB走线太长,或者上拉电阻太大。
解决:缩短走线,减小上拉电阻。SPI的话,可以在MISO线上加个串联电阻抑制过冲。
- 片选信号干扰
现象:一个SPI设备工作时,另一个设备也被误选中。
原因:CS信号有毛刺,或者电平转换太慢。
解决:在CS引脚上加个小电容(10pF左右)滤波。
我的经验:调试通信问题时,别急着改代码。先用示波器抓波形,看看起始条件、停止条件、数据、应答是不是对的。波形对了,问题就解决了一半。
好了,I2C和SPI的基础就讲到这里。这两个协议是Retimer固件开发的基石,一定要熟练掌握。下一节我们会讲具体的固件升级流程,到时候会用到今天的内容。
小练习:找一块Retimer开发板,用逻辑分析仪抓一下I2C和SPI的波形,对照数据手册看看时序是否满足要求。这是最快的学习方法。
公众号:蓝海资料掘金营,微信deep3321