3.21. SPI 基础

SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行总线,专为同一块电路板上一个控制器与一个或多个外设之间的短距离、高速连接而设计。它是 SD 卡、显示屏、闪存、ADC 和 DAC 以及各类传感器的标准接口。

UART 没有共享时钟,需要从数据线本身恢复时序;而 SPI 则在数据线旁边额外引出一根时钟线。控制器以任意速率驱动时钟,总线上的其他每个设备都与该时钟同步采样数据。这里既不需要猜测波特率,也没有帧开销——只有时钟边沿和数据位。

3.21.1. 四根信号线

一条全双工 SPI 总线有四根信号线:

  • SCK(串行时钟)。由控制器驱动。每个数据位都在该信号的某个边沿被移入或移出。

  • MOSI(控制器输出、外设输入)。控制器的输出线;外设从这根线上采样数据位。

  • MISO(控制器输入、外设输出)。外设的输出线;控制器从这根线上采样数据位。

  • CS(片选),有时也称作 SS(外设选择)。每个外设各有一根独立的片选线。控制器将 CS 拉低以开始一次事务,再拉高以结束事务;任何 CS 未被选中的外设都会完全忽略总线,并停止驱动其 MISO 输出。

四条信号波形上下排列:CS 在最上方,SCK 在其下方, 再往下是 MOSI 和 MISO。CS 初始为高电平(空闲), 随后跌至低电平以开始事务,接着 SCK 输出八个 脉冲,期间 MOSI 和 MISO 各自传输一个字节的数据, 之后 CS 又回到高电平。

一个 SPI 字节:CS 拉低以选中外设,SCK 输出八个时钟位,MOSI 和 MISO 沿相反方向各传输一个字节。

每个时钟边沿都会同时在两个方向上各移动一位。单个 SCK 脉冲会同时在 MOSI 上发送一位、并在 MISO 上接收一位——在物理线路层面 SPI 是 全双工 的。软件不一定要同时使用两个方向:只写和只读事务都很常见,未使用的那根线要么被忽略,要么保持高电平。

3.21.2. 时钟极性与相位

有两个配置位精确决定了在哪个时钟边沿移动数据:

  • 时钟极性polarity,有时写作 CPOL)——SCK 的空闲状态。0 表示时钟空闲为低电平、脉冲为高电平;1 表示时钟空闲为高电平、脉冲为低电平。

  • 时钟相位phase,有时写作 CPHA)——在哪个边沿采样数据。0 在每个时钟脉冲的第一个边沿(前沿)采样;1 在第二个边沿(后沿)采样。

这两者组合起来给出四种 模式,习惯上称为模式 0 到模式 3。模式 0(polarity=0, phase=0)最为常见,对于未知设备来说是个安全的默认值。

关键规则在于:两端必须就模式达成一致。即便时钟线和数据线接线正确,模式不匹配也会得到乱码数据;如果某个设备在第一次事务中返回了无意义的数据,模式就是首先要检查的对象。

3.21.3. 多个外设

只要每个外设都有一根由控制器驱动的独立 CS 线,多个外设就可以共享同一组 SCK、MOSI 和 MISO 线:

  • 所有外设看到的都是相同的时钟和数据,但每个外设只关注自己的 CS。当 CS 未被选中(高电平)时,外设会完全忽略 SCK 和 MOSI,并让 MISO 处于高阻态,从而不会与其他设备争抢这根线。

  • 控制器在同一时刻只选中一个 CS,执行事务,然后释放 CS 以让出总线。

一个只有单个硬件 SPI 模块的微控制器,有多少空闲的 GPIO 引脚可用于 CS 线,就能连接多少个外设——总线本身并不带寻址机制。

3.21.4. 优点与缺点

SPI 的优点和缺点都源自它的设计:

  • 速度快。 在短走线配合简单电平转换的情况下,可达到数十兆赫。SD 卡读卡器和 SPI 显示屏都利用了这一点。

  • 物理层面简单。 没有寻址、没有应答、没有特殊的起始/停止条件——只有与时钟同步的、走线上的数据位。

  • 占用引脚多。 三根共享线再加上每个外设一根 CS。一块带五个 SPI 设备的电路板要用掉八根引脚(三加五)。

  • 短距离。 SPI 假定边沿干净且快速,这意味着走线要短、并位于同一块电路板上。对于较长的连接,I2C 或某种带帧的总线更为合适。