3.21. SPI 基础

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

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

3.21.1. 四根信号线

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

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

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

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

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

Four signal traces stacked: CS at top, SCK below it, then MOSI and MISO. CS starts high (idle), drops low to begin the transaction, then SCK clocks out eight pulses while MOSI and MISO carry one byte of data each, then CS returns high.

一个 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 或某种带帧的总线更为合适。