2. SPI协议基础:通信原理、四线制与时钟极相

SPI 这玩意儿,说白了一根线都没有英特网那么复杂。但你要是没搞透它的时钟极性和相位,跟外设握手时很容易翻车。我最早做传感器驱动时,就因为 CPOL 配错了,读回来的数据全是乱的——查了半天才发现是采样边沿弄反了。今天咱们就把它从头捋一遍。

2.1 SPI 通信原理 – 主从对战

SPI 全称 Serial Peripheral Interface,是一种全双工、同步的串行通信协议。同步是什么意思?就是数据收发必须靠一个时钟信号来对齐。主设备(Master)负责产生这个时钟,从设备(Slave)只能被动响应。

我习惯把 SPI 通信比作两个人对话:主设备是问问题的那个人,时钟就是“啪、啪、啪”的打拍子声。每拍一下,双方同时说一个字,也同时听一个字。你做从设备时,不能自己输出时钟,只能跟着主设备的节奏走。

  • 全双工:同一时刻既能发也能收,不像 I2C 还要分时。
  • 同步:数据在时钟边沿上采样或更新。
  • 主从模式:一个主设备可以挂多个从设备,但每次只选一个。
嗯,这里要注意:SPI 没有内置的应答机制。主设备发了数据,从设备必须保证在下一个时钟周期前准备好数据,否则就丢帧。所以你得确保从设备响应时间匹配得上时钟频率。

2.2 四线制信号详解

标准 SPI 只用四根线,你想想看是不是比 I2C 多了一条?但换来的是速度能飙到几十兆赫兹。

信号名称方向作用
SCKMaster → Slave串行时钟,由主设备产生
MOSIMaster → Slave主设备输出,从设备输入
MISOSlave → Master从设备输出,主设备输入
CSMaster → Slave片选,低电平有效

我早期犯过一个低级错误:把 MOSI 和 MISO 接反,结果主设备发出去的命令全部跑到 MISO 线上去了,从设备自然收不到。后来我养成了一个习惯——画原理图时先标箭头方向,再连线。

片选(CS)这根线很关键。它告诉从设备“你现在是被选中的那个”。通常主设备会把多个从设备的 CS 引脚分别接到 GPIO 上,谁拉低谁就响应。但注意:CS 必须要在传输开始前拉低,传输结束后拉高。我之前遇到过某个 FLASH 芯片,如果 CS 在传输中途抖动了一下,整个页写操作就会失败。

2.3 时钟极性和相位(CPOL/CPHA)

这部分是 SPI 协议里最绕人的地方。说白了,CPOL 决定时钟空闲时的电平,CPHA 决定数据是在时钟上升沿还是下降沿采样。

  • CPOL = 0:空闲时时钟为低电平。
  • CPOL = 1:空闲时时钟为高电平。
  • CPHA = 0:在时钟的第一个边沿采样数据(上升沿或下降沿取决于 CPOL)。
  • CPHA = 1:在时钟的第二个边沿采样数据。

组合起来就有四种模式:Mode 0(CPOL=0, CPHA=0)、Mode 1(0,1)、Mode 2(1,0)、Mode 3(1,1)。大多数传感器默认用 Mode 0 或 Mode 3,但也不。我记得调试一个温湿度芯片时,手册上写的是 Mode 1,我按 Mode 0 配置,读出来的温度一直跳变,最后用示波器对比才发现 CPHA 没对上。

经验法则:拿到一个 SPI 外设的数据手册,先找到时序图,看 SCK 空闲时是高还是低,再找数据采样边沿是上升沿还是下降沿。千万不要只看文字描述,文字经常有笔误。
曾经踩过的一个坑:我在 STM32 上做 SPI 驱动,配置寄存器时不小心把 CPOL 和 CPHA 写反了。结果在低速 1MHz 时还能正常通信,升到 10MHz 就完全乱码。为什么?因为频率越高,时序容限越小,错误的相位会导致建立时间不足。所以调试时一定要从低速开始验证相位,再拉高频。

2.4 模式选择与避坑指南

实际项目中,主设备和从设备必须在同一个模式下工作。如果从设备只支持某一种模式,主设备就得迁就它。而主设备通常可以通过软件灵活配置 CPOL 和 CPHA。步骤如下:

  1. 查阅从设备数据手册,确认支持的 SPI 模式(一般表格里会写 “SPI Mode 0/1/2/3”)。
  2. 如果手册没明确写,就找时序图,数一下时钟空闲电平,再看数据在哪个边沿发生变化。
  3. 配置主设备的 SPI 寄存器,确保 CPOL 和 CPHA 与从设备一致。
  4. 先用 500kHz 左右的低频测试,读回一个固定的寄存器值(比如芯片 ID),确认无误后再升频。

我曾经在一个项目里,同时挂了三个 SPI 从设备——一个 FLASH、一个 ADC、一个 LCD。三个片子要求的 SPI 模式都不一样,没办法共用一条 SPI 总线。最终我只好给 FLASH 和 ADC 各配一条独立的 SPI 接口,LCD 用模拟 SPI 怼在 GPIO 上。虽然麻烦,但稳定。

SPI协议基础结构图 Master Slave SCK MOSI MISO CS Mode 0: CPOL=0 CPHA=0 Mode 1: CPOL=0 CPHA=1 Mode 2: CPOL=1 CPHA=0 Mode 3: CPOL=1 CPHA=1 CPHA=0: 第一个边沿采样;CPHA=1: 第二个边沿采样 空闲电平由 CPOL 决定:0→低电平,1→高电平