2. SPI协议基础:通信原理、四线制与时钟极相
SPI 这玩意儿,说白了一根线都没有英特网那么复杂。但你要是没搞透它的时钟极性和相位,跟外设握手时很容易翻车。我最早做传感器驱动时,就因为 CPOL 配错了,读回来的数据全是乱的——查了半天才发现是采样边沿弄反了。今天咱们就把它从头捋一遍。
2.1 SPI 通信原理 – 主从对战
SPI 全称 Serial Peripheral Interface,是一种全双工、同步的串行通信协议。同步是什么意思?就是数据收发必须靠一个时钟信号来对齐。主设备(Master)负责产生这个时钟,从设备(Slave)只能被动响应。
我习惯把 SPI 通信比作两个人对话:主设备是问问题的那个人,时钟就是“啪、啪、啪”的打拍子声。每拍一下,双方同时说一个字,也同时听一个字。你做从设备时,不能自己输出时钟,只能跟着主设备的节奏走。
- 全双工:同一时刻既能发也能收,不像 I2C 还要分时。
- 同步:数据在时钟边沿上采样或更新。
- 主从模式:一个主设备可以挂多个从设备,但每次只选一个。
2.2 四线制信号详解
标准 SPI 只用四根线,你想想看是不是比 I2C 多了一条?但换来的是速度能飙到几十兆赫兹。
| 信号名称 | 方向 | 作用 |
|---|---|---|
| SCK | Master → Slave | 串行时钟,由主设备产生 |
| MOSI | Master → Slave | 主设备输出,从设备输入 |
| MISO | Slave → Master | 从设备输出,主设备输入 |
| CS | Master → 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 没对上。
2.4 模式选择与避坑指南
实际项目中,主设备和从设备必须在同一个模式下工作。如果从设备只支持某一种模式,主设备就得迁就它。而主设备通常可以通过软件灵活配置 CPOL 和 CPHA。步骤如下:
- 查阅从设备数据手册,确认支持的 SPI 模式(一般表格里会写 “SPI Mode 0/1/2/3”)。
- 如果手册没明确写,就找时序图,数一下时钟空闲电平,再看数据在哪个边沿发生变化。
- 配置主设备的 SPI 寄存器,确保 CPOL 和 CPHA 与从设备一致。
- 先用 500kHz 左右的低频测试,读回一个固定的寄存器值(比如芯片 ID),确认无误后再升频。
我曾经在一个项目里,同时挂了三个 SPI 从设备——一个 FLASH、一个 ADC、一个 LCD。三个片子要求的 SPI 模式都不一样,没办法共用一条 SPI 总线。最终我只好给 FLASH 和 ADC 各配一条独立的 SPI 接口,LCD 用模拟 SPI 怼在 GPIO 上。虽然麻烦,但稳定。