数据错位的典型现象

调试SPI时,最让人头疼的问题就是数据错位。我在项目中遇到过不少次这种情况——波形看着明明有数据,但读回来的值就是不对。说白了,你能看到SCK在跳,MOSI也在送信号,可MCU收到的数据就是驴唇不对马嘴。

为什么会这样?通常都是采样点选错了位置。SPI不像I2C有ACK机制,错了就是错了,软件上没有任何反馈。你只能拿着示波器慢慢找原因。

数据错位,我归纳为三种典型现象。你在调试时可以对照排查。

数据错位三种典型现象

  • 采样边沿错误 — 数据在错误的时钟边沿被捕获
  • 数据移位 — 采到的数据整体偏了1位或更多
  • CRC校验失败 — 物理层数据对不上校验值

采样边沿错误

采样边沿错误,说白了就是采样点落到了数据跳变的位置上。你想,数据在时钟边沿跳变,如果你的采样点刚好也在那个时刻,那读到的值大概率是不稳定的。

我之前调一个ADC驱动时,量程寄存器老是读到0x00或者0xFF,反复读几次结果还不一样。用示波器抓了波形才意识到:主控配置的CPHA极性跟外设要求的不一致。采样发生在时钟的下降沿,但外设是上升沿更新的数据。

你看下面的时序关系:

配置模式 采样边沿 数据更新边沿 能否对齐
模式0 (CPOL=0, CPHA=0) 上升沿 下降沿 ✓ 安全对齐
模式1 (CPOL=0, CPHA=1) 下降沿 上升沿 ✓ 安全对齐
模式2 (CPOL=1, CPHA=0) 下降沿 上升沿 ✓ 安全对齐
模式3 (CPOL=1, CPHA=1) 上升沿 下降沿 ✓ 安全对齐

排查技巧:把示波器时间刻度拉大,看看数据线是在SCK的哪个边沿前后稳定的。数据应该在采样边沿之前至少半个周期保持稳定。

数据移位

数据移位比采样边沿错误更隐蔽。采样点没错,但读到的数据整体向左或向右偏移了若干位。比如你发的0xA5(10100101),收到的是0x4D(01001101)。看出来了吗?往右移了1位。

最典型的原因是时钟极性(CPOL)配置反了。比如外设期望空闲时SCK为低电平,你配成了高电平。第一个时钟脉冲出现时,外设可能已经多移了一位数据出来。

我遇到过一种情况:用逻辑分析仪看波形,数据对齐完全正确,可就是移位。后来才发现是MCU的SPI模块在片选拉低后,额外输出了一个时钟脉冲。你想想看,多出来的这个脉冲直接把数据推出去了一位。

检查这种问题的步骤:

  1. 抓取完整的一次传输波形,从CS拉低到CS拉高
  2. 数一数实际输出的SCK脉冲个数
  3. 核对是否等于数据宽度(8/16/32位等)
  4. 检查CS与第一个SCK脉冲之间的延迟时间

特别注意:有些MCU的SPI模块在CS拉低后,默认会先输出一个"前导脉冲"。你必须在初始化时显式关闭这个功能,否则每次读数据都会移位1位。

CRC校验失败

CRC校验失败,往往是前两种问题的最终表现。你想想,数据都错位了,CRC能对上才怪。但这里有个坑:CRC失败未必都是物理层问题,也可能是外设的CRC算法和主控对不上。

我曾经排查过一个案子,SPI通信时好时坏,CRC有时对有时错。费了好大劲才发现问题出在采样边沿临界状态:示波器上看,数据抖动刚好落在采样窗口边缘,温度一高就出错,温度一低又正常了。

所以我建议,遇到CRC失败时,先别急着怀疑算法,按这个顺序排查:

  1. 用示波器确认采样点是否稳定
  2. 检查是否有数据移位(验证收发的第一个字节是否一致)
  3. 降低SPI时钟频率再试一次(排除时序余量不足)
  4. 核对CRC多项式、初始值、输出异或值是否匹配

我的经验:三步排查法。

  • 看波形 — 确认采样边沿位置
  • 对首字节 — 确认数据没有移位
  • 降频率 — 排除时序余量问题

这三步做完,90%的数据错位问题都能定位到根因。

数据错位定位流程图 数据错位现象 采样边沿错误 数据移位 CRC校验失败 调整CPHA配置 核对CPOL配置 降频+校验算法 用示波器验证采样点是否稳定 定位根因并修复 先从示波器看波形确认现象类型,再按对应分支定位,最后验证修复效果