SPI 协议深度解析:4 种模式与多从机通信

SPI 这玩意儿,说白了就是串行外设接口。很多同学刚接触时,觉得它不就是四根线嘛,能有多复杂?

嗯,我当年也这么想。直到有一次调试一块 LCD 屏幕,死活刷不出图像,折腾了两天才发现——是 SPI 模式配错了。从那以后,我每次初始化 SPI 都会先确认 CPOL 和 CPHA 的配置。

SPI 的四根核心信号线

先快速过一下基础。SPI 总线通常由四根线组成:

  • SCLK(Serial Clock)—— 时钟信号,由主机产生
  • MOSI(Master Out Slave In)—— 主机输出,从机输入
  • MISO(Master In Slave Out)—— 主机输入,从机输出
  • SS(Slave Select)—— 片选信号,低电平有效

你想想看,这四根线其实就定义了一个完整的全双工通信链路。主机负责产生时钟,数据在时钟的边沿被采样和移位。

CPOL 和 CPHA:时钟极性与相位

这才是 SPI 协议里最容易踩坑的地方。我见过不少工程师,包括我自己早期,都在这上面吃过亏。

CPOL(Clock Polarity)决定时钟空闲时的电平:

  • CPOL = 0:空闲时时钟为低电平
  • CPOL = 1:空闲时时钟为高电平

CPHA(Clock Phase)决定数据在哪个边沿被采样:

  • CPHA = 0:在时钟的第一个边沿采样数据
  • CPHA = 1:在时钟的第二个边沿采样数据

这两个参数组合起来,就形成了 SPI 的 4 种模式。我习惯用一张表来记忆:

模式 CPOL CPHA 空闲时钟电平 数据采样边沿
模式 0 0 0 低电平 上升沿(第一个边沿)
模式 1 0 1 低电平 下降沿(第二个边沿)
模式 2 1 0 高电平 下降沿(第一个边沿)
模式 3 1 1 高电平 上升沿(第二个边沿)

核心要点:主机和从机必须工作在相同的 SPI 模式下。如果模式不匹配,数据采样会错位,通信就会失败。我那个 LCD 翻车的案例,就是因为从机手册要求模式 3,而我默认用了模式 0。

时钟极性与相位的波形解读

光看表格可能还不够直观。我们来画一张时序图,看看模式 0 和模式 3 的波形差异。

SPI 模式 0 与模式 3 时序对比 模式 0 (CPOL=0, CPHA=0) SCLK ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 模式 3 (CPOL=1, CPHA=1) SCLK ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 关键区别 模式 0:空闲低电平,在上升沿(第一个边沿)采样数据 模式 3:空闲高电平,在上升沿(第二个边沿)采样数据 两种模式的采样边沿都是上升沿,但时钟空闲电平不同,导致数据对齐位置不同

我的调试习惯:拿到一个新的 SPI 从器件,第一件事就是去数据手册里找 "SPI Mode" 或 "CPOL/CPHA" 章节。有些手册会直接写 "Mode 0" 或 "Mode 3",有些会画时序图让你自己判断。我个人建议,先看时序图确认采样边沿,再对照表格确定模式。

多从机通信机制

实际项目中,一个 MCU 往往要挂多个 SPI 从设备。比如我们的 LCD 课程里,可能同时接了显示屏、Flash 存储、触摸芯片。怎么管理它们?

SPI 的多从机通信有两种主流方式:

1. 独立片选方式(最常用)

每个从机独占一根 SS 线。主机要跟哪个设备通信,就把对应的 SS 拉低,其他设备的 SS 保持高电平。

  • 优点:硬件简单,软件控制直观,从机之间完全隔离
  • 缺点:每增加一个从机,就要多占用一个 GPIO 引脚

我做过一个项目,挂了 6 个 SPI 从机,结果 MCU 的 GPIO 不够用了。后来不得不改用菊花链方式。

2. 菊花链方式

所有从机共享同一根 SS 线,数据从第一个从机的 MOSI 进,从它的 MISO 出,再接到第二个从机的 MOSI,以此类推。

  • 优点:节省 GPIO 引脚,只需要一根 SS 线
  • 缺点:数据延迟累加,从机数量受限于时序预算;所有从机必须支持菊花链模式

注意:不是所有 SPI 从机都支持菊花链。LCD 驱动芯片通常不支持。所以在本课程中,我们使用独立片选方式。每个从机单独拉一根 SS 线,虽然占引脚,但稳定可靠。

多从机通信的时序要点

多从机场景下,有几个容易忽略的细节:

  1. SS 信号的建立时间:拉低 SS 后,需要等待一小段时间再开始发送时钟。有些从机需要这个时间来完成内部准备。
  2. 总线竞争:同一时刻只能有一个从机的 MISO 被使能。如果两个从机同时被选中,它们的 MISO 输出会打架,导致数据错误。
  3. SS 释放后的高阻态:从机在 SS 拉高后,MISO 应该回到高阻态,避免影响其他从机的通信。

嗯,这里要注意第三点。我早期用过一个国产的 SPI Flash 芯片,它的 MISO 在 SS 拉高后没有完全高阻,导致总线上出现残留电平,干扰了另一个从机的通信。后来我在每个从机的 MISO 上串了一个 100Ω 的电阻,才把问题压下去。

SPI 模式选择实战建议

回到我们的 LCD 驱动场景。市面上绝大多数的 LCD 驱动芯片,默认都支持 SPI 模式 0 或模式 3。我个人习惯优先使用模式 0,因为:

  • 模式 0 的空闲电平是低,逻辑分析仪上看波形更清晰
  • 大部分 MCU 的 SPI 外设默认配置就是模式 0
  • 兼容性最好,很多老器件只支持模式 0

但如果你用的 LCD 芯片手册明确写了 "SPI Mode 3 Only",那就老老实实配模式 3。别问我怎么知道的——翻过车的人自然懂。

一句话总结:SPI 的 4 种模式由 CPOL 和 CPHA 决定。主机和从机必须模式一致。多从机通信时,独立片选最常用,注意 SS 时序和总线竞争。拿到新器件,先查手册确认模式,再写代码。