1. SPI协议基础:时钟极性(CPOL)和时钟相位(CPHA)的定义与作用

各位做嵌入式开发的朋友,想必都跟SPI打过交道。SPI看似简单,就四根线,但调试起来经常让人抓狂。我碰到过好几次——设备明明连接正确,可数据就是错位。最后发现,问题出在时钟极性(CPOL)和时钟相位(CPHA)上。这两个参数,说白了就是定义什么时候采样数据。搞懂它们,SPI调试能少一半的坑。

1.1 SPI基础回顾

SPI是全双工同步通信。主机控制时钟SCK。数据线MOSI(主机输出从机输入)和MISO(主机输入从机输出)。片选CS用于选择从机。每个时钟周期传输一位。但时钟的“有效边沿”由谁决定?嗯,就是CPOL和CPHA。

1.2 时钟极性 CPOL

CPOL决定SCK在空闲时的电平。你想想看:如果CPOL=0,空闲时SCK为低电平;CPOL=1,空闲时SCK为高电平。这不难理解。

提示:大多数从机手册会明确给出要求的CPOL和CPHA。读手册时先看这两个参数。

1.3 时钟相位 CPHA

CPHA决定数据是在时钟的第一个边沿采样,还是第二个边沿采样。CPHA=0,第一个边沿采样;CPHA=1,第二个边沿采样。结合CPOL,每个时钟周期就有两个可能的采样边沿。所以一共四种组合。

1.4 四种模式

我们把CPOL和CPHA组合起来,就是标准的SPI模式。

模式CPOLCPHA空闲时钟电平数据采样边沿
Mode 000低第一个边沿(上升沿)
Mode 101低第二个边沿(下降沿)
Mode 210高第一个边沿(下降沿)
Mode 311高第二个边沿(上升沿)
重点:Mode0和Mode3最常用。大部分从机默认Mode0。但也不,一定要看具体器件手册。

1.5 为什么CPOL和CPHA如此重要?

假设主机设置了Mode0,从机要求Mode3。这时时钟空闲电平不同,采样边沿也差半个周期。数据会在错误时刻被锁存。我碰过一块温度传感器,规格书上写的是Mode0,但生产批次不一样,实际跑起来必须用Mode3才能读到正确温度。折腾了一下午才发现是CPHA反了。

再举个例子:高速SPI(几十MHz)时,如果从机的建立保持时间不够,稍微错一点边沿,数据就全乱。所以调SPI的第一步,就是确认主从机的CPOL和CPHA是否匹配。

警告:某些MCU的SPI外设允许动态改变CPOL/CPHA,但必须在片选拉高(空闲)状态下设置。边传输边切模式?不会有好下场。

1.6 理解CPOL和CPHA的数据锁存逻辑

我用一张图来记忆。看下面这张“SPI模式选择树”,你从CPOL选边,再从CPHA选边,就能定位到具体模式。

SPI 模式选择决策树 开始 CPOL = 0 还是 1? CPOL = 0(空闲低) CPOL = 1(空闲高) CPHA=0 → Mode0 CPHA=1 → Mode1 CPHA=0 → Mode2 CPHA=1 → Mode3

从上图你能快速找到对应模式。我个人习惯在代码里写一个初始化函数,把CPOL和CPHA作为参数传入,这样换从机时只需改宏定义。

// SPI初始化示例(STM32 HAL库风格)
void SPI_Init(SPI_HandleTypeDef *hspi, uint8_t mode)
{
    hspi->Init.CLKPolarity = (mode & 0x02) ? SPI_POLARITY_HIGH : SPI_POLARITY_LOW;
    hspi->Init.CLKPhase = (mode & 0x01) ? SPI_PHASE_2EDGE : SPI_PHASE_1EDGE;
    HAL_SPI_Init(hspi);
}
小技巧:模式编号的二进制:bit1是CPOL,bit0是CPHA。例如Mode3=0b11 ⇒ CPOL=1, CPHA=1。记不住时直接算。

1.7 本章小结

CPOL和CPHA是SPI通信的基石。你只需要记住:CPOL定空闲电平,CPHA定采样边沿,两者组合就是四种模式。调试时先确认主从机的模式是否一致。我早期踩过的坑,百分之八十都是从这里开始的。希望这一章能帮你打好基础。