4. CPOL=0, CPHA=1 模式详解:空闲时SCLK为低电平,数据在第二个时钟边沿(下降沿)采样

CPOL=0, CPHA=1 是 SPI 四种模式中应用较为广泛的一种组合。理解该模式的关键在于把握两个核心特征:时钟空闲电平为低,以及数据采样发生在第二个时钟边沿(即下降沿)。这种配置下,数据在时钟的下降沿被主设备或从设备捕获,而在上升沿进行数据切换。

4.1 模式特征与信号时序

在 CPOL=0, CPHA=1 模式下,SPI 总线的行为可以归纳为以下要点:

  • 时钟极性 (CPOL=0):当 SPI 总线处于空闲状态(无数据传输,CS 为高)时,SCLK 信号线保持为低电平。
  • 时钟相位 (CPHA=1):数据采样(捕获)动作发生在第二个时钟边沿。由于 CPOL=0,第一个边沿是上升沿,第二个边沿即为下降沿。
  • 数据切换:数据发送端(主设备输出 MISO 或从设备输出 MOSI)在第一个时钟边沿(上升沿)切换数据,为下一个下降沿的采样做好准备。
  • 建立与保持时间:数据在下降沿被采样,因此数据必须在下降沿到来之前保持稳定(建立时间),并在下降沿之后保持一段时间(保持时间)。
关键记忆点: CPOL=0, CPHA=1 模式常被称为“下降沿采样”模式。数据在上升沿准备好,在下降沿被读取。

4.2 波形图与数据有效性分析

下图展示了 CPOL=0, CPHA=1 模式下,一个 8 位数据帧(例如 0xA5,二进制 1010_0101)的传输波形。图中清晰标注了时钟边沿、数据切换点与采样点。

CPOL=0, CPHA=1 模式 SPI 波形图 CPOL=0, CPHA=1 模式 SPI 波形图(数据 0xA5) t CS SCLK MOSI Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 ▼ 采样 ▼ 采样 ▼ 采样 ▼ 采样 ▼ 采样 ▼ 采样 ▲ 切换 ▲ 切换 ▲ 切换 ▲ 切换 ▲ 切换 ▲ 切换 ▲ 切换 图例: SCLK MOSI ▼ 采样点(下降沿) ▲ 切换点(上升沿)
数据有效性分析: 从波形图可以看出,数据在上升沿(第一个边沿)被发送端更新,在下降沿(第二个边沿)被接收端采样。这种“先切换后采样”的机制确保了数据在采样时刻已经稳定,避免了数据竞争。

4.3 数据采样与切换的详细流程

为了更清晰地理解数据在 CPOL=0, CPHA=1 模式下的传输过程,下表列出了每个时钟边沿对应的操作:

时钟边沿序号 边沿类型 操作 说明
1 上升沿 数据切换 发送端更新数据线,准备下一个数据位。此时数据可能不稳定。
2 下降沿 数据采样 接收端捕获数据线上的稳定电平。这是数据被锁存的时刻。
3 上升沿 数据切换 发送端切换到下一个数据位。
4 下降沿 数据采样 接收端采样第二个数据位。
... ... ... ... 重复直到所有位传输完成。

4.4 驱动适配要点

在 Linux 内核或 RTOS 中配置 SPI 设备时,需要正确设置模式参数。以下是在 Linux 设备树和驱动代码中的典型配置方法。

4.4.1 Linux 设备树配置

在设备树中,通过 spi-cpol 和 spi-cpha 属性来指定模式。对于 CPOL=0, CPHA=1,需要设置 spi-cpha 属性,而不设置 spi-cpol。

&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_spi1>;

    spidev@0 {
        compatible = "spidev";
        reg = <0>;
        spi-max-frequency = <10000000>;  /* 10 MHz */
        spi-cpha;                         /* CPHA = 1 */
        /* spi-cpol 未定义,默认为 0 */
    };
};

4.4.2 Linux 驱动代码配置

在驱动代码中,通过 spi_mode 字段设置模式。使用宏 SPI_MODE_1 即可快速配置 CPOL=0, CPHA=1。

#include <linux/spi/spi.h>

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

    /* 设置 SPI 模式为 CPOL=0, CPHA=1 */
    spi->mode = SPI_MODE_1;
    
    /* 设置最大时钟频率 */
    spi->max_speed_hz = 10 * 1000 * 1000;  /* 10 MHz */
    
    /* 将配置写入 SPI 控制器 */
    ret = spi_setup(spi);
    if (ret < 0) {
        dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
        return ret;
    }

    dev_info(&spi->dev, "SPI mode 1 (CPOL=0, CPHA=1) configured\n");
    return 0;
}

4.4.3 RTOS (如 FreeRTOS) 驱动配置

在 RTOS 中,通常通过结构体成员或函数参数来配置 SPI 模式。以下是一个典型的配置示例:

/* FreeRTOS + HAL 库示例 */
SPI_HandleTypeDef hspi1;

void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;      /* CPOL = 0 */
    hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;           /* CPHA = 1 */
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 10;
    
    if (HAL_SPI_Init(&hspi1) != HAL_OK)
    {
        Error_Handler();
    }
}

4.5 常见问题与调试建议

常见错误: 初学者容易混淆 CPHA=1 与 CPHA=0 的采样点。请牢记:CPHA=1 时,采样发生在第二个边沿。对于 CPOL=0,第二个边沿是下降沿。如果误配置为 CPHA=0,则会在上升沿采样,导致数据错位一个时钟周期。

调试 CPOL=0, CPHA=1 模式时,建议遵循以下步骤:

  1. 使用逻辑分析仪或示波器:同时抓取 CS、SCLK、MOSI 和 MISO 信号,验证波形是否符合预期。
  2. 检查空闲电平:确认 CS 为高时,SCLK 是否为低电平。如果 SCLK 空闲时为高,说明 CPOL 配置错误。
  3. 验证采样点:观察数据变化是否发生在上升沿,采样是否发生在下降沿。如果数据在下降沿变化,说明 CPHA 配置错误。
  4. 测试回环:将 MOSI 与 MISO 短接,发送已知数据并验证接收是否一致。这是验证 SPI 模式配置是否正确的快速方法。

4.6 与其他模式的对比

下表将 CPOL=0, CPHA=1 模式与其他三种 SPI 模式进行对比,帮助理解其差异:

模式 CPOL CPHA 空闲 SCLK 电平 采样边沿 数据切换边沿
模式 0 0 0 低 上升沿(第一个边沿) 下降沿
模式 1 0 1 低 下降沿(第二个边沿) 上升沿
模式 2 1 0 高 下降沿(第一个边沿) 上升沿
模式 3 1 1 高 上升沿(第二个边沿) 下降沿
总结: CPOL=0, CPHA=1(模式 1)的特点是“空闲低电平,下降沿采样”。这种模式在许多常见的 SPI 从设备(如某些 ADC、传感器和存储器)中被广泛使用。理解其波形特征和驱动配置方法,是进行 SPI 设备调试的基础。