2. SPI时序与模式:CPOL与CPHA详解

SPI(Serial Peripheral Interface)是一种同步、全双工、主从架构的串行通信协议。其核心在于主设备(Master)通过时钟信号(SCLK)控制数据采样与切换的时机。理解时钟极性(CPOL)和时钟相位(CPHA)是掌握SPI时序的关键,也是配置SPI设备驱动的基础。

2.1 CPOL与CPHA核心概念

CPOL(Clock Polarity)和CPHA(Clock Phase)共同决定了SPI总线的四种工作模式。这两个参数定义了时钟信号在空闲状态的电平以及数据采样/切换的边沿。

参数 含义 取值 说明
CPOL 时钟极性 0 空闲状态时SCLK为低电平(0)
1 空闲状态时SCLK为高电平(1)
CPHA 时钟相位 0 数据在SCLK的第一个边沿被采样(数据在第一个边沿之前准备好)
1 数据在SCLK的第二个边沿被采样
关键记忆点: CPOL决定空闲电平,CPHA决定采样边沿是第一个还是第二个。两者组合形成Mode 0~3。

2.2 SPI Mode 0/1/2/3 定义与组合

根据CPOL和CPHA的不同组合,SPI定义了四种标准模式。每种模式都有其特定的时序波形特征。

SPI Mode CPOL CPHA 空闲时钟电平 数据采样边沿 数据切换边沿
Mode 0 0 0 低电平 上升沿(第一个边沿) 下降沿
Mode 1 0 1 低电平 下降沿(第二个边沿) 上升沿
Mode 2 1 0 高电平 下降沿(第一个边沿) 上升沿
Mode 3 1 1 高电平 上升沿(第二个边沿) 下降沿
常见设备兼容性: 大多数SPI外设(如Flash、传感器、ADC)默认支持Mode 0或Mode 3。Mode 0是最常用的模式,因为其采样边沿(上升沿)与大多数逻辑电路的默认行为一致。

2.3 四种模式的时序图(SVG)

以下SVG图展示了SPI Mode 0~3的典型时序波形,包含SCLK、MOSI(主出从入)和SS(从设备选择)信号。

SPI Mode 0/1/2/3 时序波形对比 SPI Mode 0/1/2/3 时序波形对比 Mode 0 (CPOL=0, CPHA=0) SCLK MOSI 采样 采样 Mode 1 (CPOL=0, CPHA=1) SCLK 采样 Mode 2 (CPOL=1, CPHA=0) SCLK 采样 Mode 3 (CPOL=1, CPHA=1) SCLK 采样 SCLK MOSI 采样点

2.4 时钟极性与相位配置

在嵌入式Linux驱动中,SPI模式的配置通常在设备树(Device Tree)或板级文件中完成。内核通过读取这些配置来初始化SPI控制器。

2.4.1 设备树中的配置示例

以下是在设备树中为SPI从设备指定模式的典型配置:

&spi0 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_spi0>;

    spidev@0 {
        compatible = "spidev";
        reg = <0>;                 /* 片选CS0 */
        spi-max-frequency = <1000000>; /* 1MHz */
        spi-cpol;                  /* CPOL = 1 */
        spi-cpha;                  /* CPHA = 1 */
        /* 上述两个属性组合为 Mode 3 */
    };
};
配置说明: 如果设备树中同时设置了 spi-cpol 和 spi-cpha,则对应 Mode 3。如果只设置其中一个,则对应 Mode 1 或 Mode 2。如果两者都未设置,则默认为 Mode 0。

2.4.2 内核驱动中的配置方式

在SPI设备驱动中,可以通过 spi_setup() 函数或直接修改 spi_device 结构体成员来配置模式:

#include <linux/spi/spi.h>

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

    /* 配置SPI模式为 Mode 0 */
    spi->mode = SPI_MODE_0;
    /* 或者使用位操作 */
    /* spi->mode = SPI_CPOL | SPI_CPHA; // 对应 Mode 3 */

    /* 设置最大频率 */
    spi->max_speed_hz = 5000000; /* 5MHz */

    /* 应用配置 */
    ret = spi_setup(spi);
    if (ret < 0) {
        dev_err(&spi->dev, "spi_setup failed\n");
        return ret;
    }

    /* 后续通信 */
    return 0;
}

2.5 典型波形分析

在实际调试中,使用逻辑分析仪或示波器抓取波形是验证SPI配置是否正确的最直接方法。以下是一个典型的SPI Mode 0波形分析案例。

SPI Mode 0 典型波形分析 SPI Mode 0 典型波形分析(读取Flash ID) SS 片选拉低 片选拉高 SCLK MOSI 1 0 0 1 1 1 1 1 MISO 1 1 1 0 1 1 1 1 分析:主机发送命令 0x9F(读取JEDEC ID),从机在8个时钟后开始返回数据 0xEF(制造商ID)、0x40(容量)、0x18(型号)。
常见调试陷阱:
  • 模式不匹配: 主设备配置为Mode 0,但从设备要求Mode 3,会导致数据错位或通信失败。务必查阅从设备数据手册确认其支持的SPI模式。
  • 时钟频率过高: 即使模式正确,如果SCLK频率超过从设备的最大支持频率,也会导致采样错误。
  • 片选信号毛刺: 在模式切换或初始化阶段,片选信号可能出现毛刺,导致从设备误触发。建议在片选线上加10kΩ上拉电阻。

2.6 模式选择与驱动配置总结

下表总结了不同SPI模式在驱动开发中的典型应用场景和注意事项:

SPI Mode 典型应用 驱动配置宏 注意事项
Mode 0 大多数SPI Flash、SD卡、传感器 SPI_MODE_0 最常用,兼容性最好
Mode 1 某些TI ADC、音频编解码器 SPI_MODE_1 较少见,需确认设备手册
Mode 2 某些Microchip外设、LCD控制器 SPI_MODE_2 空闲高电平,注意电平转换
Mode 3 多数SPI NOR Flash、W25Q系列 SPI_MODE_3 与Mode 0一样常见,采样边沿不同
驱动开发最佳实践: 在编写SPI设备驱动时,不要硬编码模式。应该从设备树或平台数据中读取模式配置,或者提供模块参数让用户在加载时指定。这样可以提高驱动的可移植性和灵活性。