4、SPI总线时序分析:模式选择、时钟极性与相位、数据采样窗口
SPI 总线,说实话,是嵌入式工程师最常用的接口之一。但越是常用,越容易在时序上翻车。我见过太多人,连 SPI 的四种模式都搞不清楚,就直接上代码了。结果呢?数据读出来全是乱的。
今天咱们就好好聊聊 SPI 的时序。我会结合我自己的踩坑经历,把模式选择、时钟极性、相位,还有那个容易被忽略的采样窗口,一次讲透。
4.1 SPI 的四种模式:CPOL 和 CPHA
SPI 总线的核心,是两个参数:时钟极性(CPOL)和时钟相位(CPHA)。这两个参数组合起来,就形成了四种模式。
先别急着背表格。咱们先理解一下它们到底在干什么。
- CPOL:决定了时钟空闲时的电平。CPOL=0 表示空闲时时钟为低电平,CPOL=1 表示空闲时时钟为高电平。
- CPHA:决定了数据是在时钟的哪个边沿被采样。CPHA=0 表示在第一个边沿采样,CPHA=1 表示在第二个边沿采样。
嗯,这里要注意:第一个边沿和第二个边沿,是相对于一次传输的起始时刻来说的。不是随便抓一个时钟周期看。
四种模式如下表所示:
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 |
|---|---|---|---|---|
| 模式 0 | 0 | 0 | 低电平 | 上升沿(第一个边沿) |
| 模式 1 | 0 | 1 | 低电平 | 下降沿(第二个边沿) |
| 模式 2 | 1 | 0 | 高电平 | 下降沿(第一个边沿) |
| 模式 3 | 1 | 1 | 高电平 | 上升沿(第二个边沿) |
我个人习惯,最常用的是模式 0 和模式 3。为什么?因为很多 Flash 芯片和传感器默认就支持这两种模式。模式 1 和模式 2 也不是不能用,但你要仔细看数据手册。
4.2 用逻辑分析仪看时钟极性和相位
光看表格,你可能还是觉得抽象。咱们直接上逻辑分析仪抓波形。
假设你配置了 SPI 模式 0(CPOL=0, CPHA=0)。用逻辑分析仪抓到的波形应该是这样的:
- 空闲时,SCLK 为低电平。
- CS 拉低后,SCLK 开始输出时钟脉冲。
- 数据在 SCLK 的上升沿被采样。
- 数据在 SCLK 的下降沿发生变化。
如果你配置的是模式 3(CPOL=1, CPHA=1):
- 空闲时,SCLK 为高电平。
- CS 拉低后,SCLK 开始输出时钟脉冲。
- 数据在 SCLK 的上升沿被采样。
- 数据在 SCLK 的下降沿发生变化。
看到了吗?模式 0 和模式 3 的采样边沿都是上升沿。区别只是空闲电平不同。这就是为什么很多器件可以同时兼容这两种模式。
4.3 数据采样窗口:最容易忽略的坑
好,模式选对了,相位也对了,为什么数据还是错的?
这时候,你就要考虑数据采样窗口了。
说白了,采样窗口就是数据在时钟边沿附近保持稳定的那段时间。SPI 协议本身没有规定数据必须在时钟边沿的哪个位置变化,但实际电路中,数据变化和时钟边沿之间是有延迟的。
我举个例子。你配置了模式 0,理论上数据应该在下降沿变化,上升沿采样。但实际抓波形时,你可能会发现:
- 数据变化发生在下降沿之后一点点(因为从机内部有延迟)。
- 或者数据变化发生在下降沿之前一点点(因为主机输出有延迟)。
这两种情况,都会导致采样窗口偏移。如果偏移量太大,采样点就会落在数据变化的过程中,而不是稳定区域。结果就是:采到的数据可能是 0,也可能是 1,完全随机。
4.4 如何用逻辑分析仪分析采样窗口
具体怎么操作?我一般这么干:
- 抓取一次完整的 SPI 传输,包括 CS、SCLK、MOSI、MISO 四根线。
- 放大波形,找到数据变化的位置。
- 测量数据变化点与采样边沿之间的时间差。这个时间差就是采样窗口的余量。
- 判断余量是否足够。一般来说,余量至少要有时钟周期的 10% 以上才比较安全。
举个例子,假设你的 SPI 时钟是 10MHz,周期是 100ns。那么采样窗口余量至少要有 10ns。如果余量只有 2-3ns,那就很危险了。
4.5 实战:一个 SPI 模式不匹配的案例
最后,分享一个我实际处理过的案例。
有一次,一个同事说他的 SPI 传感器读出来的数据全是 0xFF。我让他把逻辑分析仪抓的波形发给我。一看波形,我就发现问题了。
波形显示:
- SCLK 空闲时为高电平。
- CS 拉低后,第一个时钟边沿是下降沿。
- 数据在下降沿附近变化。
这明显是模式 2(CPOL=1, CPHA=0)的配置。但同事的代码里配置的是模式 3。模式 3 的采样边沿是上升沿,而实际数据在下降沿变化。所以,主机在上升沿采样时,数据还没稳定,自然读到的全是 0xFF。
解决方案很简单:把代码里的模式改成模式 2,或者把从机的配置改成模式 3。改完之后,数据就正常了。
你看,有时候问题就这么简单。但如果没有逻辑分析仪,你可能要花一整天去查代码、查寄存器,最后还是一头雾水。