摘要:SPI 通讯成功,但 MISO 一直返回 0xFF 或 0x00?不是从机坏了,而是主从机的时钟极性(CPOL)和相位(CPHA)不匹配。本文用示波器教你 30 秒定乾坤。


一、问题描述(现象)

**示波器看 SCK 有波形,MOSI 也有数据;

但 MISO 一直是高电平(0xFF)或低电平(0x00)。**

很多工程师的排查方向是:

  1. 线接反了?

  2. 从机没供电?

  3. 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 秒定案(最靠谱)

不要猜,直接看波形。

步骤:

  1. 触发 CS 下降沿。

  2. 观察 MISO 数据相对于 SCK 的位置。

  3. 对照下表调整主设备模式。

口诀:

  • 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; // 推荐

四、选型避坑建议

  1. Flash 芯片:几乎都是 Mode 0 或 Mode 3

  2. ADC 芯片:TI 的很多 ADC 是 Mode 1

  3. 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 的四种模式绕晕过,欢迎在评论区交流。

原创文章,转载请注明出处。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐