2. SPI 时钟极性与时钟相位:CPOL 和 CPHA 的详细解释

说实话,刚接触 SPI 的时候,我也被 CPOL 和 CPHA 这两个参数搞得晕头转向。明明就是四个数字组合,怎么就能让数据读出来全错呢?后来调了几块板子,烧了几片 Flash,才算真正摸透了它们的脾气。

CPOL 和 CPHA,一个是时钟极性,一个是时钟相位。两者配合,决定了 SPI 在什么时刻采样数据、什么时候输出数据。说白了吧,这就是 SPI 通信的“握手规则”。主设备和从设备必须用同一套规则,否则数据就会错位。

2.1 什么是 CPOL?(时钟极性)

CPOL 决定了 SPI 时钟线(SCK)在空闲状态时的电平。就这么简单。

  • CPOL = 0:空闲时时钟为低电平。你想想看,总线闲着的时候,SCK 就老老实实拉低。
  • CPOL = 1:空闲时时钟为高电平。SCK 平时就悬在高处。

我个人习惯把 CPOL 理解为“时钟的默认姿势”。主设备一上电,SCK 是什么电平,那就是 CPOL 的值。我在一个项目中遇到过一个奇怪现象:用逻辑分析仪抓到的波形明明是对的,但数据就是不对。后来发现是 CPOL 搞反了,从设备在空闲时以为时钟跳变来了,结果提前采了数据。

2.2 什么是 CPHA?(时钟相位)

CPHA 决定了数据在时钟的哪个边沿被采样。说白了,就是选择上升沿还是下降沿来“读取”数据线上的电平。

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

这里要注意:第一个边沿和第二个边沿,取决于 CPOL。如果 CPOL=0,第一个边沿是上升沿;如果 CPOL=1,第一个边沿是下降沿。嗯,这就是为什么 CPOL 和 CPHA 总是成对出现的原因。

我曾经掉进过的坑:有一次我把 CPOL 设成了 1,CPHA 也设成了 1。从设备手册上明明写的是 Mode 3。结果数据还是一塌糊涂。后来才发现,我理解错了“第二个边沿”——手册里画的是下降沿采样,但我的主设备配置成了上升沿采样。一个字:惨。

2.3 四种 SPI 模式

CPOL 和 CPHA 组合起来,就是 SPI 的四种模式。这可能是嵌入式面试里最常见的问题了。我整理了一个表格,方便你对照记忆:

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

最常用的模式是 Mode 0 和 Mode 3。大多数 Flash、SD 卡、传感器都支持这两种。Mode 1 和 Mode 2 比较少见,但我遇到过一些老款 ADC 芯片只能用 Mode 2。

2.4 采样边沿与数据错位的关系

为什么 CPHA 设错了会导致数据错位?我来拆解一下:

  1. CPHA = 0:数据在第一个边沿被锁存。 这时候数据线(MOSI/MISO)上的数据必须在第一个边沿之前就已经稳定。主设备在第一个边沿把数据读走,然后在第二个边沿更新数据。
  2. CPHA = 1:数据在第二个边沿被锁存。 主设备先在第一个边沿输出数据,等数据稳定后,在第二个边沿去读。

你想想看,如果主设备用 CPHA=0 发送,但从设备用 CPHA=1 接收。主设备认为数据应该在第一个边沿被读走,但从设备却等第二个边沿才读。结果就是,从设备读到的数据,其实是主设备在第一个边沿之后更新的新数据——刚好晚了一个时钟周期。

这就是经典的“位偏移”问题。数据不是乱码,而是整体左移或右移了一位。用逻辑分析仪抓波形,你会发现 MISO 线上的数据和 SCK 的边沿对不上。

一个验证技巧:我建议你在调试时先发一个已知的字节,比如 0x55(二进制 01010101)。如果读回来是 0xAA(10101010),那基本上就是 CPHA 反了,数据错位了一位。如果读回来是 0xAB 之类的乱值,那问题可能更复杂,需要检查其他因素。

2.5 核心逻辑框架图

下面这张图展示了 CPOL 和 CPHA 的组合如何决定 SPI 的四种模式,以及数据采样和输出的时序关系。这是理解本章知识的关键。

SPI 时钟极性与相位组合逻辑 CPOL = 0(空闲低电平) CPOL = 1(空闲高电平) CPHA = 0 CPHA = 1 CPHA = 0 CPHA = 1 Mode 0 上升沿采样 Mode 1 下降沿采样 Mode 2 下降沿采样 Mode 3 上升沿采样 关键点 CPOL 定空闲电平,CPHA 定采样边沿位置。两者组合决定数据对齐方式。

2.6 如何正确配置 CPOL 和 CPHA

实战中,配置 CPOL 和 CPHA 其实就三步。我每次调 SPI 都走这个流程,基本不会出错:

  1. 查手册:从设备的数据手册里找到 SPI 时序图,看它明确标注了支持哪种 Mode。大部分芯片会说“支持 SPI Mode 0 和 Mode 3”。
  2. 看波形:如果手册没说,用示波器或逻辑分析仪抓一下从设备的 DOUT 引脚。在空闲状态下拉高还是拉低,就能猜出 CPOL。再观察它在 SCK 的哪个边沿改变数据,就能确定 CPHA。
  3. 统一配置:主设备(比如 MCU 的 SPI 外设)的寄存器里设置 CPOL 和 CPHA,保证和从设备一致。

举个例子,STM32 的 SPI 配置代码里,通常是这样写的:

// 假设我们要配置 SPI1 为 Mode 3
SPI1->CR1 |= SPI_CR1_CPOL;  // CPOL = 1,空闲高电平
SPI1->CR1 |= SPI_CR1_CPHA;  // CPHA = 1,第二个边沿采样

一个快速判断技巧:如果你的系统只有单个从设备,而且你懒得查手册,可以直接试试 Mode 0。大多数 SPI 设备都兼容 Mode 0。如果通信失败,再试 Mode 3。这两种模式覆盖了市面上 80% 的从设备。

2.7 避坑指南

我总结了几条经验,也许能帮你少走弯路:

  • 不要想当然:同一个厂家、同一系列的芯片,SPI 模式也可能不同。每次换器件都要重新确认。
  • 注意相位偏移:如果数据错位一位,先怀疑 CPHA 设反。先用 0x55 做测试,验证位对齐。
  • 多从设备时特别小心:每个从设备可能有不同的 SPI 模式。主设备必须在片选切换后重新配置 CPOL 和 CPHA。我见过一个设计,主设备只设了一次模式,结果第二个从设备死活读不对。
  • 时钟速度的影响:CPHA 和 CPOL 本身不依赖时钟频率。但高速下,数据建立时间和保持时间会更紧张,这时相位对齐就更关键。

总之,CPOL 和 CPHA 不是玄学,是实实在在的硬件规则。把这两个参数搞明白,SPI 通信就成功了一半。