SPI接口时序分析与逻辑分析仪故障定位实战 - 第1节

1.1 SPI 总线概述

SPI,全称 Serial Peripheral Interface,串行外设接口。这玩意儿是 Motorola 公司在八十年代搞出来的,到现在快四十年了,依然活跃在各种嵌入式系统里。为什么?说白了就三个字——简单、快。

我刚开始做嵌入式那会儿,接触的第一个同步串行总线就是 SPI。当时觉得这协议也太直白了,不像 I2C 还有地址、应答那些弯弯绕。SPI 就是主设备发时钟,数据随时钟走,一收一发,干净利落。

SPI 是同步、全双工、主从结构的串行通信总线。同步意味着有独立的时钟线;全双工意味着同一时刻既能发也能收;主从结构则意味着总线上只有一个主设备控制时钟,其他都是小弟。

SPI 的核心特点:
  • 同步串行通信——有时钟线同步
  • 全双工——同时收发
  • 主从模式——一个 Master,多个 Slave
  • 无设备地址——靠片选线选通
  • 传输速率高——通常可达几十 MHz

你想想看,SPI 为什么能跑那么快?因为它没有 I2C 那种开漏输出和上拉电阻的限制,用的是推挽输出,信号边沿陡峭,速率自然就上去了。我见过 SPI 跑到 80MHz 的场景,当然那是短距离板内通信。

1.2 四线制功能详解

标准的 SPI 是四根线,名字分别是 SCLK、MOSI、MISO、CS。每一根线都有明确的职责,咱们一条一条说。

SCLK —— 串行时钟

SCLK 由主设备产生,决定了数据传输的节奏。每一个时钟脉冲,主从设备之间就交换一个比特。时钟频率直接决定了 SPI 的传输速率。我个人习惯在设计时先看从设备支持的最高时钟频率,再留 20%~30% 的余量。

MOSI —— 主出从入

MOSI 全称 Master Output Slave Input。主设备通过这根线向从设备发送数据。记住这个名字的逻辑——主设备输出,从设备输入,所以叫 MOSI。

MISO —— 主入从出

MISO 全称 Master Input Slave Output。从设备通过这根线向主设备回传数据。SPI 是全双工的,所以 MOSI 和 MISO 可以同时传输数据,互不干扰。

CS —— 片选

CS 也叫 SS(Slave Select),由主设备控制,低电平有效。当 CS 拉低时,对应的从设备被选中,开始参与通信;CS 拉高时,从设备释放总线,MISO 变为高阻态。

这里有个坑,我踩过。多个从设备共用 MOSI、MISO、SCLK 时,CS 必须严格互斥。如果两个从设备的 CS 同时被拉低,它们的 MISO 输出会打架,数据就全乱了。嗯,这个一定要注意。

信号线 全称 方向 功能
SCLK Serial Clock 主→从 提供同步时钟
MOSI Master Out Slave In 主→从 主设备发送数据
MISO Master In Slave Out 从→主 从设备回传数据
CS Chip Select 主→从 选通从设备

1.3 SPI 的 4 种工作模式

SPI 的四种模式,是很多新手容易搞混的地方。其实没那么复杂,核心就两个参数:CPOL(时钟极性)和 CPHA(时钟相位)。

CPOL —— 时钟极性

CPOL 决定了 SCLK 在空闲状态时的电平:

  • CPOL = 0:空闲时 SCLK 为低电平
  • CPOL = 1:空闲时 SCLK 为高电平

CPHA —— 时钟相位

CPHA 决定了数据采样发生在哪个时钟边沿:

  • CPHA = 0:在第一个时钟边沿采样数据
  • CPHA = 1:在第二个时钟边沿采样数据

CPOL 和 CPHA 组合起来,就是四种模式。我刚开始做 SPI 驱动时,经常搞混 Mode 0 和 Mode 3,后来总结了一个记忆方法:Mode 0 是默认模式,CPOL=0、CPHA=0,空闲低电平,第一个边沿采样。大多数 SPI 器件默认都支持 Mode 0。

模式 CPOL CPHA 空闲时钟电平 数据采样边沿
Mode 0 0 0 低电平 上升沿(第一个边沿)
Mode 1 0 1 低电平 下降沿(第二个边沿)
Mode 2 1 0 高电平 下降沿(第一个边沿)
Mode 3 1 1 高电平 上升沿(第二个边沿)
避坑指南: 主设备和从设备的 SPI 模式必须一致。我曾经在一个项目里,主控用 Mode 0,传感器用 Mode 3,结果读出来的数据全是乱的。用逻辑分析仪一看才发现,采样边沿完全对不上。所以,拿到一个新器件,第一件事就是看数据手册里 SPI 模式的说明。

1.4 SPI 时序与模式图解

光说理论不够直观,咱们画个图看看。下面这张 SVG 展示了 Mode 0 和 Mode 3 的时序差异,这是实际调试中最容易搞混的两个模式。

SPI Mode 0 与 Mode 3 时序对比 SPI Mode 0 与 Mode 3 时序对比 Mode 0 (CPOL=0, CPHA=0) SCLK ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 MOSI D7 D6 D5 D4 Mode 3 (CPOL=1, CPHA=1) SCLK ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 ▲ 采样 MOSI D7 D6 D5 D4 关键区别: • Mode 0:空闲低电平,上升沿采样数据,下降沿切换数据 • Mode 3:空闲高电平,下降沿采样数据,上升沿切换数据 • 两种模式采样边沿不同,但数据采样点相对于时钟边沿的位置是相同的(都是第二个边沿)

从图上可以看得很清楚:Mode 0 和 Mode 3 的时钟极性相反,但采样边沿都是第二个边沿。Mode 0 在上升沿采样,Mode 3 在下降沿采样。如果你把主设备配成 Mode 0,从设备配成 Mode 3,那采样点就完全错位了,数据肯定不对。

调试小技巧: 如果你不确定器件的 SPI 模式,可以用逻辑分析仪抓一下 CS 拉低后 SCLK 的第一个边沿。如果第一个边沿是上升沿,那大概率是 Mode 0 或 Mode 2;如果是下降沿,那就是 Mode 1 或 Mode 3。再结合空闲电平,就能确定具体模式了。

1.5 SPI 通信流程

一次完整的 SPI 通信,流程其实很简单:

  1. 主设备拉低 CS,选通目标从设备
  2. 主设备产生 SCLK 时钟,同时通过 MOSI 发送数据
  3. 从设备在 SCLK 驱动下,从 MOSI 接收数据,同时通过 MISO 回传数据
  4. 数据传输完成后,主设备拉高 CS,释放从设备

这里有个细节很多人会忽略:SPI 是全双工的,所以每次传输,主设备发出去一个字节的同时,也会收到一个字节。如果你只想读从设备的数据,主设备必须发送一个 dummy byte(通常是 0x00 或 0xFF)来产生时钟。我见过有人忘了发 dummy byte,结果 MISO 上一直没数据,折腾了半天才发现。