3、SPI 工作模式:模式 0/1/2/3 详解、全双工通信机制、主从设备配置

SPI(Serial Peripheral Interface)总线在网关嵌入式系统中承担着高速、全双工的片间通信任务。理解其四种工作模式(CPOL/CPHA 组合)、全双工数据流以及主从拓扑结构,是编写正确 SPI 设备驱动的核心前提。本节将从时序参数、模式对比、数据交换机制和配置要点四个维度展开。

3.1 SPI 模式 0/1/2/3 的时序本质

SPI 模式由时钟极性(CPOL)和时钟相位(CPHA)两个参数唯一确定。CPOL 决定空闲时 SCK 的电平,CPHA 决定数据采样发生在 SCK 的第一个还是第二个边沿。

模式CPOLCPHA空闲 SCK 电平数据采样边沿数据输出边沿
模式 000低电平上升沿(第一个边沿)下降沿
模式 101低电平下降沿(第二个边沿)上升沿
模式 210高电平下降沿(第一个边沿)上升沿
模式 311高电平上升沿(第二个边沿)下降沿
驱动适配提示: 绝大多数 SPI 从设备(如 Flash、ADC、传感器)默认使用模式 0 或模式 3。在 Linux 内核中,通过 spi_device->mode 字段设置 SPI_MODE_0 至 SPI_MODE_3 宏。务必核对从设备数据手册中的时序图,错误的模式会导致数据移位或 CRC 错误。
SPI 四种工作模式时序对比(CPOL / CPHA) 模式 0 (CPOL=0, CPHA=0) SCK MOSI 采样 模式 1 (CPOL=0, CPHA=1) SCK MOSI 采样 模式 2 (CPOL=1, CPHA=0) SCK MOSI 采样 模式 3 (CPOL=1, CPHA=1) SCK MOSI 采样 图例: SCK 时钟线 模式 0 数据 采样点 注意:模式 0 和模式 3 采样边沿相同(第一个边沿),但空闲电平相反;模式 1 和模式 2 采样边沿相同(第二个边沿)。

3.2 全双工通信机制

SPI 的全双工特性源于其独立的发送和接收数据路径:主设备通过 MOSI 线发送数据,同时通过 MISO 线接收从设备数据。一个时钟周期内,主从双方各移出一位数据并移入对方的一位数据,形成“交换式”传输。

核心机制: SPI 没有独立的应答信号,主设备必须主动发起时钟才能读取从设备数据。因此,读操作通常需要先发送一个“空字节”(0x00 或 0xFF)来产生时钟,从设备在相同字节时间内返回数据。
SPI 全双工数据交换机制 主设备 (Master) 从设备 (Slave) MOSI 主 → 从 数据 MISO 从 → 主 数据 SCK(时钟由主设备驱动) 关键点: • 每个时钟周期同时完成一位发送和一位接收,数据移位寄存器在主设备中称为 SPI_DR。 • 从设备无法主动发起传输,必须等待主设备提供时钟。

3.3 主从设备配置与片选管理

SPI 总线采用一主多从的拓扑结构。主设备通过独立的片选信号(CS/SS)选择目标从设备,每次只与一个从设备通信。在 Linux 内核中,主从配置通过 struct spi_device 和 struct spi_board_info 完成。

3.3.1 硬件连接要点

  • SCK:主设备输出,所有从设备共享。
  • MOSI:主设备输出,所有从设备数据输入引脚共享。
  • MISO:从设备输出,所有从设备数据输出引脚共享(从设备未选中时需输出高阻态)。
  • CS:每个从设备独立占用一个主设备 GPIO 或专用片选线,低电平有效。

3.3.2 内核配置示例

/* 板级文件或设备树中的 SPI 从设备声明 */
static struct spi_board_info my_spi_devices[] = {
    {
        .modalias = "mcp2515",        /* 驱动名称 */
        .max_speed_hz = 10 * 1000 * 1000, /* 10 MHz */
        .bus_num = 1,                 /* SPI 控制器编号 */
        .chip_select = 0,             /* 片选索引 */
        .mode = SPI_MODE_0,           /* 工作模式 */
        .platform_data = &mcp2515_pdata,
    },
};
避坑指南: 多个从设备共享 MISO 线时,必须确保未选中的从设备 MISO 引脚为高阻态(三态),否则会造成总线冲突。部分从设备不支持三态输出,此时需要为每个从设备增加一个三态缓冲器或使用独立的 SPI 控制器。
SPI 一主多从拓扑与片选连接 主设备 (Master) SCK / MOSI / MISO 从设备 1 CS0 从设备 2 CS1 从设备 3 CS2 SCK MOSI MISO CS0 CS1 CS2 配置要点: • 每个从设备独立 CS 引脚 • 未选中从设备 MISO 高阻 • 时钟频率以最慢从设备为准

3.4 驱动开发中的模式与配置校验

在 Linux SPI 子系统驱动中,模式配置和全双工通信通过 spi_transfer 结构体实现。以下是一个典型的读写操作片段:

struct spi_transfer t = {
    .tx_buf = tx_buffer,      /* 发送数据缓冲区 */
    .rx_buf = rx_buffer,      /* 接收数据缓冲区(全双工) */
    .len = 4,                 /* 传输字节数 */
    .speed_hz = 5000000,      /* 5 MHz 传输速率 */
    .bits_per_word = 8,       /* 8 位数据宽度 */
    .cs_change = 0,           /* 传输完成后是否释放片选 */
};

struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
spi_sync(spi_device, &m);     /* 同步阻塞传输 */
模式校验清单:
  1. 确认从设备数据手册中 CPOL 和 CPHA 的时序图,而非仅看模式编号。
  2. 检查 SPI 控制器硬件是否支持所需模式(部分控制器只支持模式 0 和模式 3)。
  3. 验证片选极性:大多数从设备使用低电平有效,但部分设备要求高电平有效。
  4. 测试全双工回环:将 MOSI 与 MISO 短接,发送已知数据并验证接收是否一致。

3.5 常见问题与调试方法

现象可能原因排查方向
数据全部为 0xFF 或 0x00片选未正确拉低 / MISO 未连接用示波器检查 CS 和 MISO 电平
数据移位(如 0x55 变成 0xAA)CPOL/CPHA 配置错误核对时序图,调整模式参数
偶尔通信失败时钟频率过高 / 信号反射降低 max_speed_hz,增加串联电阻
多从设备数据冲突未选中设备 MISO 未高阻检查从设备三态特性或增加缓冲器