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)的传输波形。图中清晰标注了时钟边沿、数据切换点与采样点。
数据有效性分析: 从波形图可以看出,数据在上升沿(第一个边沿)被发送端更新,在下降沿(第二个边沿)被接收端采样。这种“先切换后采样”的机制确保了数据在采样时刻已经稳定,避免了数据竞争。
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 模式时,建议遵循以下步骤:
- 使用逻辑分析仪或示波器:同时抓取 CS、SCLK、MOSI 和 MISO 信号,验证波形是否符合预期。
- 检查空闲电平:确认 CS 为高时,SCLK 是否为低电平。如果 SCLK 空闲时为高,说明 CPOL 配置错误。
- 验证采样点:观察数据变化是否发生在上升沿,采样是否发生在下降沿。如果数据在下降沿变化,说明 CPHA 配置错误。
- 测试回环:将 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 设备调试的基础。