4. SPI 四种模式详解:Mode0~Mode3 归纳总结

SPI 通信里最让人头疼的,就是时钟极性和相位。说白了就是两个位:CPOL(Clock Polarity) 和 CPHA(Clock Phase)。组合起来正好四种模式,每个模式对应一套严格的时序规则。搞不清它们,设备就连不上——我踩过这个坑,所以这一节咱们彻底讲透。

4.1 CPOL 与 CPHA 到底在控制什么?

  • CPOL:时钟空闲时的电平。0 = 空闲低电平,1 = 空闲高电平。
  • CPHA:数据采样发生在哪个边沿。0 = 第一个边沿采样,1 = 第二个边沿采样。

你想想看,CPOL 决定了时钟闲下来时是高还是低;CPHA 决定了数据是上升沿读还是下降沿读。这两个组合起来,就对应四种截然不同的时序行为。

快速记忆口诀:

CPOL 看空闲,高1低0;CPHA 看采样,一0二1。

4.2 逐个拆解四种模式

Mode 0(CPOL=0, CPHA=0)—— 最常用的“默认模式”

这是大多数 SPI 设备默认使用的模式。时钟空闲为低电平,数据在时钟的第一个边沿(上升沿)采样,第二个边沿(下降沿)更新。简单、直观、兼容性好。

我记得有一次调试一个温度传感器,手册上说“支持 SPI Mode0”,我直接就配了 Mode0,一次搞定。很多单片机的主机模式默认也是 Mode0,比如 STM32 的 SPI 初始化如果不设置 CPOL/CPHA,就是 Mode0。

// 伪代码:配置 Mode0
SPI_InitTypeDef spi;
spi.CPHA = SPI_CPHA_1Edge;   // 第一个边沿采样
spi.CPOL = SPI_CPOL_Low;     // 空闲低电平

Mode 1(CPOL=0, CPHA=1)—— 数据在下降沿采样

时钟空闲还是低电平,但采样发生在第二个边沿(下降沿)。这种模式比较少用,但有些老式 EEPROM 或 ADC 会用它。

有一次客户反馈说一片 flash 读写偶尔出错,我抓了波形才发现设备要的是 Mode1,而我配成了 Mode0。时钟空闲电平相同,只是采样移了一个边沿,数据就错位了。嗯,这里要注意,眼睛看不仔细很容易翻车。

// 伪代码:配置 Mode1
spi.CPHA = SPI_CPHA_2Edge;   // 第二个边沿采样
spi.CPOL = SPI_CPOL_Low;

Mode 2(CPOL=1, CPHA=0)—— 空闲高电平,上升沿采样

时钟空闲时为高电平,数据在第一个边沿(下降沿)采样。这里要小心:因为时钟空闲高,第一个边沿是下降沿。所以采样发生在下降沿。

我曾经被一个国产加速度计坑过,手册上写了“SCLK idle high, data latch on first edge”,但没写 Mode 编号。我一开始想当然配了 Mode0,结果读数全乱。后来抓波形才意识到是 Mode2。

// 伪代码:配置 Mode2
spi.CPOL = SPI_CPOL_High;
spi.CPHA = SPI_CPHA_1Edge;

Mode 3(CPOL=1, CPHA=1)—— 空闲高电平,下降沿采样

时钟空闲高,第二个边沿采样。这是什么?上升沿更新,下降沿采样。和 Mode0 正好是反相的极性。很多 SD 卡、LCD 驱动芯片默认就是 Mode3。

我个人习惯:如果遇到一个全新的从设备,我会先用逻辑分析仪抓它发的波形,看看空闲时 SCLK 是高还是低,再结合数据在哪个边沿跳变,反推出 Mode。这比翻手册快得多。

// 伪代码:配置 Mode3
spi.CPOL = SPI_CPOL_High;
spi.CPHA = SPI_CPHA_2Edge;

4.3 四种模式关键参数对比

模式CPOLCPHASCK 空闲电平采样边沿数据更新边沿
Mode 000低上升沿下降沿
Mode 101低下降沿上升沿
Mode 210高下降沿上升沿
Mode 311高上升沿下降沿

核心总结:

  • CPOL 决定空闲电平,CPHA 决定采样边沿顺序。
  • Mode0 和 Mode3 采样边沿都是上升沿,但空闲电平相反。
  • Mode1 和 Mode2 采样边沿都是下降沿,空闲电平也相反。

4.4 实战中如何识别和切换模式?

用逻辑分析仪抓取 SCLK 和 MOSI 波形,看两个关键点:

  1. SCLK 空闲时是高还是低 → 确定 CPOL。
  2. 观察 MOSI 或 MISO 数据变化边沿:数据通常在什么时刻稳定?从设备在哪个边沿采样?

举个例子:如果空闲时是低电平,并且在时钟的第一个边沿(上升沿)数据稳定,那就是 Mode0。如果第一个边沿数据还在变化,要到第二个边沿才稳定,那就是 Mode1。

我曾经踩过的坑:

有一次我需要用 STM32 和一片 AD 芯片通信,手册写“SPI Mode2”。我配置了 CPOL=1, CPHA=0,但数据就是不对。折腾半天发现芯片内部对上电顺序有要求,必须在 CS 拉低前先让 SCLK 拉到高电平,否则芯片默认 CPOL=0。所以不要只看模式编号,还要看启动时序。

4.5 模式选择:主机跟着从机走

这是铁律。主机 SPI 的模式必须和从设备完全一致,否则时序错位,数据全是乱码。实际项目中,优先查阅从设备的数据手册,找到“SPI Timing Characteristics”表格,里面会明确写出所需的 CPOL 和 CPHA,或者直接给出 Mode 编号。

如果手册里只给了时序图,那就按上面的方法反推。我通常会把四种模式的配置宏都写进代码里,用一个 switch 来选,方便调试时快速切换。

// 实用小函数:根据模式号配置
void SPI_SetMode(SPI_HandleTypeDef *hspi, uint8_t mode) {
    switch(mode) {
        case 0: hspi->Init.CPOL = SPI_POLARITY_LOW;
                hspi->Init.CPHA = SPI_PHASE_1EDGE; break;
        case 1: hspi->Init.CPOL = SPI_POLARITY_LOW;
                hspi->Init.CPHA = SPI_PHASE_2EDGE; break;
        case 2: hspi->Init.CPOL = SPI_POLARITY_HIGH;
                hspi->Init.CPHA = SPI_PHASE_1EDGE; break;
        case 3: hspi->Init.CPOL = SPI_POLARITY_HIGH;
                hspi->Init.CPHA = SPI_PHASE_2EDGE; break;
        default: break;
    }
}

你可能会问:如果主从都支持多种模式,选哪个好?我个人习惯首选 Mode0 或 Mode3,因为它们采样都在上升沿,和大多数数字逻辑的边沿一致,抗干扰相对好一些。Mode1 和 Mode2 采样在下降沿,有时会遇到建立时间不足的问题。

SPI 四种模式决策树 CPOL = 0 还是 1? CPOL = 0(空闲低) CPOL = 1(空闲高) Mode 0 CPHA=0,第一个边沿采样 空闲低,上升沿采样 Mode 1 CPHA=1,第二个边沿采样 空闲低,下降沿采样 Mode 2 CPHA=0,第一个边沿采样 空闲高,下降沿采样 Mode 3 CPHA=1,第二个边沿采样 空闲高,上升沿采样 采样边沿判断小技巧: CPHA=0 → 在时钟的第一个边沿采样;CPHA=1 → 在第二个边沿采样。 空闲低=0,空闲高=1。 四个模式中,边界容易混淆的是 Mode0 和 Mode3(采样都在上升沿), 以及 Mode1 和 Mode2(采样都在下降沿)。区分就看空闲电平。

4.6 本节小结

四种模式其实就两个参数,记住:CPOL 看空闲,CPHA 看采样位置。实测中别光信手册上的模式编号,一定用逻辑分析仪确认波形。我建议你把四种模式代码都写好,调试时动态切换,省得反复改代码编译。

另外,如果用了 DMA 或 FIFO,切换模式时注意重新初始化外设,不然配置可能不生效。