3. SPI 总线协议详解:物理层与时序核心
SPI(Serial Peripheral Interface,串行外设接口)是一种由 Motorola 公司提出的全双工、同步、主从式串行通信总线。本章深入剖析 SPI 的物理层信号定义、四线制工作机制、时钟极性(CPOL)与相位(CPHA)的配置逻辑,以及由此衍生的四种数据传输模式。理解这些底层细节是后续驱动开发和传感器适配的基础。
3.1 SPI 物理层与四线制信号
SPI 总线在物理层上通过四条信号线实现主设备(Master)与从设备(Slave)之间的数据交换。与 I2C 的开漏极架构不同,SPI 使用推挽输出,因此支持更高的传输速率(通常可达数十 MHz)。
| 信号线 | 全称 | 方向(主→从) | 功能描述 |
|---|---|---|---|
| SCLK | Serial Clock | 主 → 从 | 由主设备产生的同步时钟,决定数据传输速率 |
| MOSI | Master Out Slave In | 主 → 从 | 主设备发送数据至从设备的数据线 |
| MISO | Master In Slave Out | 从 → 主 | 从设备发送数据至主设备的数据线 |
| CS | Chip Select | 主 → 从 | 片选信号,低电平有效,用于选中特定的从设备 |
关键概念:SPI 是全双工通信。在每个时钟周期内,主设备通过 MOSI 发送一位数据,同时从设备通过 MISO 发送一位数据。这意味着一次时钟脉冲即可完成一次双向数据交换。
下图展示了 SPI 四线制的基本连接拓扑。主设备通过独立的 CS 线分别控制多个从设备,而 SCLK、MOSI、MISO 则共享连接。
3.2 时钟极性(CPOL)与相位(CPHA)
SPI 协议的核心灵活性体现在时钟极性(CPOL)和时钟相位(CPHA)的配置上。这两个参数决定了数据采样和切换的时序边界。
- CPOL(Clock Polarity):定义 SCLK 在空闲状态(无数据传输时)的电平。
CPOL = 0:空闲时 SCLK 为低电平。CPOL = 1:空闲时 SCLK 为高电平。
- CPHA(Clock Phase):定义数据采样发生在 SCLK 的哪个边沿。
CPHA = 0:在第一个时钟边沿(上升沿或下降沿,取决于 CPOL)采样数据。CPHA = 1:在第二个时钟边沿采样数据。
驱动开发提示:CPOL 和 CPHA 必须与从设备的数据手册严格匹配。配置错误将导致数据移位或采样错误,表现为读取到的传感器数据全为 0xFF 或 0x00。
3.3 四种 SPI 数据传输模式
根据 CPOL 和 CPHA 的组合,SPI 定义了四种标准传输模式(Mode 0 ~ Mode 3)。这是嵌入式工程师必须熟记的配置表。
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 | 数据输出边沿 |
|---|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低电平 | 上升沿 | 下降沿 |
| Mode 1 | 0 | 1 | 低电平 | 下降沿 | 上升沿 |
| Mode 2 | 1 | 0 | 高电平 | 下降沿 | 上升沿 |
| Mode 3 | 1 | 1 | 高电平 | 上升沿 | 下降沿 |
下图以 Mode 0 和 Mode 3 为例,展示了 SCLK、MOSI 和 MISO 的时序关系。注意数据在采样边沿必须保持稳定。
3.4 数据传输流程与代码示例
一次完整的 SPI 数据传输遵循以下步骤:
- 片选使能:主设备将对应从设备的 CS 引脚拉低,选中从设备。
- 时钟启动:主设备开始产生 SCLK 时钟信号。
- 数据移位:在每个时钟周期,主设备通过 MOSI 发送一位数据,同时从设备通过 MISO 发送一位数据。数据通常以 MSB(最高有效位)先行。
- 传输完成:发送完指定字节数后,主设备停止 SCLK,并将 CS 拉高,释放从设备。
以下是一个 Linux 内核 SPI 驱动中配置模式和传输数据的典型代码片段:
#include <linux/spi/spi.h>
/* 配置 SPI 设备 */
static int sensor_spi_setup(struct spi_device *spi)
{
int ret;
/* 设置 SPI 模式:Mode 0 (CPOL=0, CPHA=0) */
spi->mode = SPI_MODE_0;
/* 设置最大时钟频率:1 MHz */
spi->max_speed_hz = 1000000;
/* 设置每字位数:8 位 */
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0) {
pr_err("SPI setup failed\n");
return ret;
}
return 0;
}
/* 发送和接收数据 */
static int sensor_spi_transfer(struct spi_device *spi,
u8 *tx_buf, u8 *rx_buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = len,
.speed_hz = 1000000,
.bits_per_word = 8,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
常见错误:在配置 SPI 时,如果
spi->mode 设置错误(例如传感器要求 Mode 1 但配置为 Mode 0),会导致数据采样边沿错位。此时应使用逻辑分析仪抓取 SCLK 和 MOSI/MISO 波形,对比数据手册确认时序。