4. 时钟极性(CPOL)配置:CPOL=0与CPOL=1的波形区别、空闲时钟电平、适用场景
时钟极性(Clock Polarity, CPOL)决定了 SPI 总线在空闲状态(即片选 CS 无效、无数据传输时)下时钟信号(SCLK)的默认电平。CPOL 是 SPI 通信双方必须匹配的首要参数,配置错误将导致数据采样错位或通信完全失败。
4.1 CPOL 定义与空闲时钟电平
| CPOL 值 | 空闲时钟电平 | 有效时钟边沿方向 | 典型应用场景 |
|---|---|---|---|
| CPOL = 0 | 低电平(GND) | 上升沿采样 / 下降沿切换 | 低速传感器、EEPROM、SD 卡(默认模式) |
| CPOL = 1 | 高电平(VCC) | 下降沿采样 / 上升沿切换 | 高速 ADC、射频模块、FPGA 配置 |
关键记忆点:CPOL 决定的是“空闲时”的电平,而非数据采样边沿。采样边沿由 CPHA(时钟相位)配合 CPOL 共同决定。本章仅聚焦 CPOL 对空闲电平及波形外观的影响。
4.2 CPOL=0 与 CPOL=1 的波形对比
下图展示了在相同 8-bit 数据(0xA5,二进制 1010_0101)传输过程中,CPOL=0 与 CPOL=1 的 SCLK 波形差异。注意 CS 低有效期间,时钟开始跳变;CS 释放后,时钟回到空闲电平。
4.3 适用场景分析
4.3.1 CPOL=0 的典型场景
- 低功耗传感器(如温度、湿度、压力):空闲时 SCLK 保持低电平,减少动态功耗,适合电池供电设备。
- EEPROM / Flash 存储器:多数 SPI 存储器默认支持 CPOL=0,兼容性最广。
- SD 卡 SPI 模式:SD 卡规范中 SPI 模式默认使用 CPOL=0、CPHA=0(模式 0)。
- MCU 内部 SPI 外设默认配置:大部分 MCU 复位后 SPI 模块默认 CPOL=0,减少初始化遗漏风险。
4.3.2 CPOL=1 的典型场景
- 高速 ADC / DAC:部分高速转换器要求时钟空闲为高,以利用下降沿进行快速采样,减少建立时间。
- 射频收发模块(如 CC1101、nRF24L01):射频芯片常要求 CPOL=1 以匹配其内部时序逻辑。
- FPGA 配置接口:Xilinx/Altera 的 SPI 配置模式常使用 CPOL=1,与配置时钟相位配合。
- 隔离型 SPI 通信:使用光耦或磁隔离时,空闲高电平有助于维持隔离器输出端确定状态,防止误触发。
实战经验:在驱动开发中,优先查阅器件数据手册的“SPI Timing Characteristics”章节,找到 SCLK 空闲电平的描述(通常标注为“SCLK idle low”或“SCLK idle high”)。切勿仅凭经验猜测 CPOL 值,否则可能导致数据错位或 CRC 校验失败。
4.4 CPOL 配置的驱动代码示例(基于 STM32 HAL)
以下代码展示了在 STM32 HAL 库中如何分别配置 CPOL=0 和 CPOL=1。注意 SPI_CPOL_Low 对应 CPOL=0,SPI_CPOL_High 对应 CPOL=1。
/* SPI 句柄定义 */
SPI_HandleTypeDef hspi1;
/* CPOL=0 配置(空闲低电平) */
void SPI_Config_CPOL0(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_1EDGE; /* CPHA = 0,模式0 */
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
HAL_SPI_Init(&hspi1);
}
/* CPOL=1 配置(空闲高电平) */
void SPI_Config_CPOL1(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_HIGH; /* CPOL = 1 */
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; /* CPHA = 0,模式2 */
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
HAL_SPI_Init(&hspi1);
}
常见错误:在 Linux 内核 SPI 驱动中,CPOL 通过
spi_mode 的 SPI_CPOL 位控制。若在设备树中遗漏 spi-cpol 属性,内核默认使用 CPOL=0。如果从机要求 CPOL=1,通信将完全失败,且示波器上会看到 SCLK 空闲时处于错误电平。
4.5 CPOL 选择决策流程
调试技巧:当不确定从机 CPOL 时,先用逻辑分析仪或示波器抓取从机在 CS 拉低后 SCLK 的第一个边沿方向。若第一个边沿是上升沿,则 CPOL=0;若第一个边沿是下降沿,则 CPOL=1。这是最可靠的逆向推断方法。