SPI 读回来全是 0xFF?别只换线,看看 CPOL 与 CPHA
摘要:SPI 通讯成功,但 MISO 一直返回 0xFF 或 0x00?不是从机坏了,而是主从机的时钟极性(CPOL)和相位(CPHA)不匹配。本文用示波器教你 30 秒定乾坤。
一、问题描述(现象)
**示波器看 SCK 有波形,MOSI 也有数据;
但 MISO 一直是高电平(0xFF)或低电平(0x00)。**
很多工程师的排查方向是:
-
线接反了?
-
从机没供电?
-
CS 片选没拉低?
二、原理分析
1. 物理模型
SPI 是全双工同步总线。
MISO 的数据是在 SCK 的某个边沿 被采样。
SCK: ___|‾‾‾|___|‾‾‾|___
MISO: ===X===X===X===X===
↑ ↑ ↑
采样点
2. 核心参数
-
CPOL (Clock Polarity):SCK 空闲时的电平。
-
CPHA (Clock Phase):在第几个边沿采样。
|
模式 |
CPOL |
CPHA |
采样边沿 |
|---|---|---|---|
|
Mode 0 |
0 |
0 |
上升沿 |
|
Mode 1 |
0 |
1 |
下降沿 |
|
Mode 2 |
1 |
0 |
下降沿 |
|
Mode 3 |
1 |
1 |
上升沿 |
3. 反直觉真相
主从机模式不一致,SPI 不会报错,只会返回垃圾数据。
从机(如 Flash、LCD 控制器)通常固定在 Mode 0 或 Mode 3。
如果你配成 Mode 1,MISO 刚好在无效边沿采样。
三、工程级解决方案
方案 1:示波器 30 秒定案(最靠谱)
不要猜,直接看波形。
步骤:
-
触发 CS 下降沿。
-
观察 MISO 数据相对于 SCK 的位置。
-
对照下表调整主设备模式。
口诀:
-
MISO 在 SCK 第一个跳变前就有效 → CPHA = 0
-
MISO 在 SCK 跳变后才有效 → CPHA = 1
方案 2:软件暴力枚举
如果手头没有示波器,写一个小循环测试。
uint8_t test_mode(uint8_t mode)
{
SPI_InitStructure.SPI_CPOL = (mode >> 1) & 1;
SPI_InitStructure.SPI_CPHA = mode & 1;
SPI_Init(SPI1, &SPI_InitStructure);
CS_LOW();
Send_Dummy();
uint8_t ret = Read_Reg();
CS_HIGH();
return ret;
}
// 遍历 4 种模式
for (int i = 0; i < 4; i++) {
if (test_mode(i) != 0xFF) break;
}
方案 3:注意 NSS 硬件管理
如果使用硬件 NSS,确保它不是被拉高了。
SPI_InitStructure.SPI_NSS = SPI_NSS_SOFT; // 推荐
四、选型避坑建议
-
Flash 芯片:几乎都是 Mode 0 或 Mode 3。
-
ADC 芯片:TI 的很多 ADC 是 Mode 1。
-
LCD 屏:ILI9341 支持 Mode 0/3,但有些国产屏只支持 Mode 3。
五、总结 Checklist
-
[ ] 是否用示波器看过 MISO 与 SCK 的相对相位?
-
[ ] 主从机的 CPOL/CPHA 是否一致?
-
[ ] 是否排除了 CS 片选信号异常?
-
[ ] 是否尝试过 4 种模式暴力测试?
💡 注意区分:本文讨论的是 SPI 模式不匹配。
若你的问题是 SPI 速度上不去,请检查 IO 速度与上拉,详见《SPI 速度上不去?别怪芯片》。
References
-
SPI Block Guide (Motorola)
-
STM32 Reference Manual – SPI main features
如果你曾被 SPI 的四种模式绕晕过,欢迎在评论区交流。
原创文章,转载请注明出处。
更多推荐


所有评论(0)