2. SPI 工作模式:CPOL 与 CPHA 详解

SPI 通信的灵活性很大程度上来源于其可配置的时钟极性和相位。理解 CPOL(Clock Polarity,时钟极性)和 CPHA(Clock Phase,时钟相位)是正确配置 SPI 设备、解决通信数据错位问题的关键。本节将深入剖析这两个参数,并通过时序图和适用场景帮助你彻底掌握 SPI 的四种工作模式。

2.1 CPOL 与 CPHA 核心概念

在 SPI 总线中,SCLK(串行时钟)由主设备产生,用于同步数据的发送和接收。CPOL 和 CPHA 共同决定了 SCLK 在空闲状态时的电平以及数据采样/切换的边沿。

参数 定义 取值 说明
CPOL 时钟极性,定义 SCLK 在空闲状态(无数据传输时)的电平。 0 空闲时 SCLK 为低电平(低电平空闲)。
1 空闲时 SCLK 为高电平(高电平空闲)。
CPHA 时钟相位,定义数据在哪个时钟边沿被采样(捕获),以及在哪个边沿切换(输出)。 0 在 SCLK 的第一个边沿(上升沿或下降沿,取决于 CPOL)采样数据。
1 在 SCLK 的第二个边沿采样数据。
记忆技巧: 可以将 CPHA=0 理解为“前沿采样”,CPHA=1 理解为“后沿采样”。但具体是上升沿还是下降沿,需要结合 CPOL 的值来确定。

2.2 四种工作模式(Mode 0/1/2/3)

通过组合 CPOL 和 CPHA 的 0/1 取值,可以得到四种标准的 SPI 工作模式。绝大多数 SPI 从设备都会在其数据手册中明确指定所支持的工作模式。

模式 CPOL CPHA 空闲时钟电平 数据采样边沿 数据切换边沿
Mode 0 0 0 低电平 上升沿(第一个边沿) 下降沿
Mode 1 0 1 低电平 下降沿(第二个边沿) 上升沿
Mode 2 1 0 高电平 下降沿(第一个边沿) 上升沿
Mode 3 1 1 高电平 上升沿(第二个边沿) 下降沿

2.3 四种模式时序图(内联 SVG)

下面的 SVG 时序图直观展示了在四种模式下,SCLK、MOSI(主出从入)和 MISO(主入从出)之间的时序关系。图中以传输一个字节(例如 0x6B,二进制 0110 1011)为例,展示了数据在时钟边沿的采样与切换过程。

SPI 四种工作模式时序对比图 (CPOL/CPHA) Mode 0 (CPOL=0, CPHA=0) SCLK MOSI 0 1 1 0 1 0 1 1 ▲采样 Mode 1 (CPOL=0, CPHA=1) SCLK MOSI 0 1 1 0 1 0 1 1 ▲采样 Mode 2 (CPOL=1, CPHA=0) SCLK MOSI 0 1 1 0 1 0 1 1 ▲采样 Mode 3 (CPOL=1, CPHA=1) SCLK MOSI 0 1 1 0 1 0 1 1 ▲采样 时序图解读要点 • 蓝色波形 (SCLK):时钟信号,空闲电平由 CPOL 决定。 • 红色波形 (MOSI):主设备发送的数据,在数据切换边沿改变。 • 绿色箭头 (▲采样):从设备在数据采样边沿读取 MOSI 线上的电平。

2.4 适用场景与选型建议

不同的 SPI 工作模式适用于不同的设备和应用场景。选择合适的模式是确保通信稳定可靠的第一步。

  • Mode 0 (CPOL=0, CPHA=0):最常用模式
    • 特点: 空闲时时钟为低,在上升沿采样数据。这是最直观、最符合“时钟上升沿锁存数据”直觉的模式。
    • 适用场景: 绝大多数通用 SPI 设备,如 W25Qxx 系列 Flash、SD 卡(SPI 模式)、常见的 ADC/DAC 芯片。如果你的设备手册没有特别说明,通常默认就是 Mode 0。
  • Mode 3 (CPOL=1, CPHA=1):次常用模式
    • 特点: 空闲时时钟为高,在上升沿采样数据。与 Mode 0 相比,只是空闲电平相反,但采样边沿相同(都是上升沿)。
    • 适用场景: 一些对时钟空闲电平有特定要求的设备,例如某些 RF 模块、传感器。许多 MCU 的 SPI 外设也支持 Mode 3。
  • Mode 1 (CPOL=0, CPHA=1) 与 Mode 2 (CPOL=1, CPHA=0):较少用模式
    • 特点: 这两种模式在下降沿采样数据。Mode 1 空闲为低,下降沿采样;Mode 2 空闲为高,下降沿采样。
    • 适用场景: 主要用于一些 老式或特定厂商的 SPI 设备,例如某些 TI(德州仪器)的 DSP 或特定外设。在调试这类设备时,需要特别注意时序配置。
驱动开发建议: 在编写 SPI 设备驱动时,务必首先查阅目标设备的数据手册(Datasheet),找到 SPI 时序章节,确认设备支持的 SPI 模式。通常手册中会给出类似“SPI Mode 0, 3”或“CPOL=0, CPHA=0”的明确说明。在 Linux 内核中,通过 spi_device->mode 字段设置模式,例如 spi->mode = SPI_MODE_0。

2.5 常见配置错误与调试方法

SPI 通信失败最常见的原因之一就是主从设备的工作模式不匹配。以下是几种典型的错误现象和调试思路。

错误现象 可能原因 调试方法
数据全部为 0 或 0xFF 主设备模式与从设备模式完全相反(例如主设备用 Mode 0,从设备用 Mode 2)。 使用逻辑分析仪或示波器抓取 SCLK 和 MOSI/MISO 波形,对比数据手册中的时序图,确认采样边沿是否正确。
数据错位(例如发送 0x55,收到 0xAA) CPHA 配置错误,导致数据在错误的边沿被采样,相当于整体移位了一个时钟周期。 检查 CPHA 配置。如果怀疑是 CPHA 问题,可以尝试在驱动中切换 CPHA 值(0 和 1)进行测试。
通信偶尔成功,偶尔失败 时钟极性(CPOL)不匹配,导致从设备在空闲时检测到错误的电平,状态机紊乱。 确保主从设备的 CPOL 一致。检查从设备是否对时钟空闲电平有严格要求。
第一个字节总是错误 CPHA=0 模式下,从设备在第一个时钟边沿之前可能尚未准备好数据。 对于 CPHA=0 的模式,确保在第一个时钟边沿到来之前,MOSI 数据已经稳定。有时需要在传输前增加一个微小的延时。
调试利器:逻辑分析仪 在调试 SPI 时序问题时,逻辑分析仪是必不可少的工具。它可以同时捕获 SCLK、MOSI、MISO 和 CS 信号,让你直观地看到数据在时钟边沿的采样情况,快速定位模式不匹配、极性错误或时序违规问题。建议在驱动开发初期就养成抓取波形的习惯。

2.6 Linux 内核中 SPI 模式配置示例

在 Linux 内核的 SPI 设备驱动中,配置工作模式通常通过设置 spi_device 结构体的 mode 字段完成。以下是一个典型的配置代码片段。

#include <linux/spi/spi.h>

static int my_spi_probe(struct spi_device *spi)
{
    int ret;

    /* 设置 SPI 时钟频率,单位 Hz */
    spi->max_speed_hz = 10000000; // 10 MHz

    /* 设置 SPI 工作模式为 Mode 0 (CPOL=0, CPHA=0) */
    spi->mode = SPI_MODE_0;

    /* 如果需要,可以设置其他标志,例如 SPI_CS_HIGH (片选高电平有效) */
    // spi->mode |= SPI_CS_HIGH;

    /* 将配置写入 SPI 控制器 */
    ret = spi_setup(spi);
    if (ret) {
        dev_err(&spi->dev, "SPI setup failed: %d\n", ret);
        return ret;
    }

    dev_info(&spi->dev, "SPI device configured in Mode 0, speed %d Hz\n",
             spi->max_speed_hz);

    /* ... 其他初始化代码 ... */
    return 0;
}

Linux 内核预定义了四种 SPI 模式的宏,可以直接使用:

  • SPI_MODE_0 (CPOL=0, CPHA=0)
  • SPI_MODE_1 (CPOL=0, CPHA=1)
  • SPI_MODE_2 (CPOL=1, CPHA=0)
  • SPI_MODE_3 (CPOL=1, CPHA=1)
设备树配置: 在支持设备树(Device Tree)的平台上,SPI 工作模式也可以在设备树节点中指定,例如 spi-max-frequency = <10000000>; 和 spi-cpol; / spi-cpha; 属性。驱动可以通过读取设备树属性来动态配置模式,提高代码的通用性。