4. SPI 总线协议详解:物理层、4线制、CPOL/CPHA 模式与全双工通信
SPI(Serial Peripheral Interface,串行外设接口)由 Motorola 公司于 20 世纪 80 年代提出,是一种高速、全双工、同步的串行通信总线。本章深入剖析 SPI 的物理层特性、4线制信号定义、时钟极性与相位配置,以及全双工通信的底层机制,为后续结合 DMA 实现高性能传输奠定基础。
4.1 物理层与 4 线制信号定义
SPI 总线采用主从(Master-Slave)架构,通常由 1 个主设备控制多个从设备。物理层通过 4 根信号线实现同步全双工通信:
| 信号线 | 全称 | 方向(主→从) | 功能描述 |
|---|---|---|---|
| SCK | Serial Clock | 主 → 从 | 由主设备产生,同步数据传输的时钟信号 |
| MOSI | Master Out Slave In | 主 → 从 | 主设备发送数据至从设备的数据线 |
| MISO | Master In Slave Out | 从 → 主 | 从设备发送数据至主设备的数据线 |
| CS | Chip Select | 主 → 从 | 片选信号,低电平有效,选中特定从设备 |
关键概念:SPI 的物理层没有定义固定的数据包格式、地址或应答机制,这些完全由上层协议(如设备数据手册)规定。这种简洁性使得 SPI 的吞吐量远高于 I²C,但同时也要求驱动开发者对时序有更精确的控制。
下图展示了 SPI 单主多从的典型拓扑结构,其中 CS 线独立控制每个从设备,SCK、MOSI、MISO 则共享于所有从设备:
硬件设计要点:在高速 SPI(≥10 MHz)布线时,SCK 应尽量短且远离其他数字信号线,以减少串扰。MOSI 与 MISO 应保持等长,避免数据线与时钟线之间的时序偏移(Skew)。CS 线建议使用 GPIO 直接控制,以获得最快的片选切换速度。
4.2 CPOL 与 CPHA:SPI 的四种工作模式
SPI 协议通过 时钟极性(CPOL, Clock Polarity) 和 时钟相位(CPHA, Clock Phase) 两个参数定义数据采样与切换的时序关系。这两个参数组合出 4 种标准模式:
| 模式 | CPOL | CPHA | SCK 空闲电平 | 数据采样边沿 | 数据切换边沿 |
|---|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低电平 | 上升沿 | 下降沿 |
| Mode 1 | 0 | 1 | 低电平 | 下降沿 | 上升沿 |
| Mode 2 | 1 | 0 | 高电平 | 下降沿 | 上升沿 |
| Mode 3 | 1 | 1 | 高电平 | 上升沿 | 下降沿 |
常见错误:主设备与从设备的 CPOL/CPHA 配置必须完全一致,否则会导致数据移位错位。例如,若主设备配置为 Mode 0(上升沿采样),而从设备配置为 Mode 1(下降沿采样),则主设备采样到的数据将是前一位的旧值,通信完全失败。
下图以 Mode 0(CPOL=0, CPHA=0)和 Mode 3(CPOL=1, CPHA=1)为例,展示 SCK、MOSI 与 MISO 的时序关系:
4.3 全双工通信机制
SPI 的核心优势在于其 全双工(Full-Duplex) 通信能力:在每个 SCK 时钟周期内,主设备通过 MOSI 发送一位数据,同时从设备通过 MISO 发送一位数据。这种同时收发机制使得 SPI 的吞吐量是相同时钟频率下 I²C 的两倍。
全双工通信的底层实现依赖于主从双方的 移位寄存器(Shift Register):
- 初始化:主设备将待发送数据加载到发送移位寄存器,从设备也将待发送数据加载到其发送移位寄存器。
- 时钟驱动:每个 SCK 边沿,主从双方同时将移位寄存器中的最高位(MSB-first 或 LSB-first)移出到数据线上,同时从数据线上移入一位新数据。
- 交换完成:经过 8 个(或 16 个)时钟周期后,主设备的接收移位寄存器中存储了从设备发送的完整数据,反之亦然。
性能指标:在 20 MHz SCK 频率下,SPI 的理论单向数据速率为 20 Mbps,全双工双向总吞吐量可达 40 Mbps。实际应用中,受限于 GPIO 中断响应延迟和 CPU 轮询开销,裸机驱动通常只能达到 60%~70% 的理论速率。这正是后续章节引入 DMA 传输的核心动机。
下图展示了 SPI 全双工通信中移位寄存器的数据交换过程:
4.4 SPI 通信流程与代码示例
一个完整的 SPI 数据传输周期包含以下步骤:
- 片选拉低:主设备将目标从设备的 CS 引脚拉低,激活从设备。
- 时钟启动:主设备开始产生 SCK 时钟信号,频率由 SPI 时钟分频器配置决定。
- 数据移位:在每个 SCK 边沿(取决于 CP