3. CPOL=0 与 CPOL=1 的区别:空闲时钟电平的定义、波形对比图、对从设备逻辑电平的影响
在 SPI 协议中,时钟极性(CPOL,Clock Polarity)决定了 SCLK 线在空闲状态(即无数据传输时)的逻辑电平。CPOL 只有两个取值:0 和 1。理解 CPOL 的本质是区分 SPI 模式的第一步,也是正确配置主从设备通信的基础。
3.1 空闲时钟电平的定义
空闲时钟电平是指 SPI 总线在 CS(片选)信号无效 或 两次数据传输之间,SCLK 线保持的固定逻辑电平。CPOL 直接定义了这个电平:
| CPOL 值 | 空闲时钟电平 | 有效时钟边沿极性 | 典型应用场景 |
|---|---|---|---|
| 0 | 低电平(0V / GND) | 上升沿为有效边沿(采样/移位) | 多数低速传感器、EEPROM |
| 1 | 高电平(VCC / 3.3V) | 下降沿为有效边沿(采样/移位) | 部分高速 ADC、射频模块 |
记忆口诀:“CPOL=0,空闲躺地上(低电平);CPOL=1,空闲挂天上(高电平)”。这个简单的物理比喻可以帮助你在调试时快速判断当前配置的极性。
3.2 波形对比图:CPOL=0 vs CPOL=1
下面两张 SVG 波形图分别展示了 CPOL=0 和 CPOL=1 在传输一个字节(0xA5,即二进制 1010 0101)时的 SCLK 与 MOSI 信号时序。注意观察空闲状态下的电平差异。
图 3-1:CPOL=0 波形(空闲低电平)
图 3-2:CPOL=1 波形(空闲高电平)
波形对比要点:
- 空闲电平差异:CPOL=0 时 SCLK 在空闲时保持低电平;CPOL=1 时保持高电平。这是两者最直观的区别。
- 有效边沿差异:CPOL=0 时,第一个时钟边沿是上升沿;CPOL=1 时,第一个时钟边沿是下降沿。注意:有效边沿的具体作用(采样还是移位)由 CPHA 决定,但边沿的极性由 CPOL 决定。
- 数据线不受影响:MOSI/MISO 的数据电平由发送数据决定,与 CPOL 无关。CPOL 只改变 SCLK 的极性。
3.3 对从设备逻辑电平的影响
CPOL 的选择直接影响从设备内部逻辑的输入阈值和时序窗口。错误的 CPOL 配置会导致从设备无法正确识别时钟边沿,从而造成通信失败。
3.3.1 从设备输入阈值匹配
每个 SPI 从设备的数据手册都会明确标注其支持的 CPOL 模式。从设备内部的输入缓冲器通常设计为在特定边沿触发采样:
- CPOL=0 设备:内部逻辑期望在 SCLK 的上升沿采样数据。如果主设备配置为 CPOL=1,从设备会在下降沿采样,导致采样到错误的数据位。
- CPOL=1 设备:内部逻辑期望在 SCLK 的下降沿采样数据。如果主设备配置为 CPOL=0,从设备会在上升沿采样,同样导致数据错位。
常见调试陷阱:很多工程师在调试时只关注数据线(MOSI/MISO)的波形,而忽略了 SCLK 的极性。如果从设备输出数据看起来“移位”或“乱码”,首先检查 CPOL 是否与从设备数据手册一致。使用示波器同时观察 SCLK 和 MOSI,确认采样边沿是否对齐。
3.3.2 对从设备功耗的影响
CPOL 的选择还会影响从设备的静态功耗:
| CPOL 配置 | 空闲时 SCLK 电平 | 对从设备输入引脚的影响 | 功耗考量 |
|---|---|---|---|
| CPOL=0 | 低电平 | 从设备 SCLK 引脚输入为低,CMOS 输入无静态电流 | 低功耗场景更优 |
| CPOL=1 | 高电平 | 从设备 SCLK 引脚输入为高,CMOS 输入无静态电流 | 与 CPOL=0 相当 |
实际上,对于 CMOS 输入,只要电平稳定在 VCC 或 GND,静态电流几乎为零。因此 CPOL 对功耗的影响微乎其微,主要考虑的还是时序兼容性。
3.3.3 对从设备复位状态的影响
某些 SPI 从设备在复位后,其内部状态机依赖于 SCLK 的初始电平来识别起始条件:
- CPOL=0 设备:复位后 SCLK 为低,从设备等待第一个上升沿作为起始标志。
- CPOL=1 设备:复位后 SCLK 为高,从设备等待第一个下降沿作为起始标志。
如果主设备在初始化时先输出错误的 CPOL 电平,从设备可能会误判起始条件,导致后续通信完全错乱。这也是为什么在 SPI 驱动初始化时,必须先配置 CPOL,再使能 SPI 控制器。
3.4 CPOL 配置的代码示例
以下是在 Linux 内核 SPI 控制器驱动中配置 CPOL 的典型代码片段:
/* 在 SPI 控制器配置函数中设置 CPOL */
static void spi_master_set_cpol(struct spi_master *master, u8 cpol)
{
u32 regval;
/* 读取当前控制寄存器 */
regval = readl(master->base + SPI_CR);
/* 清除 CPOL 位(假设 CPOL 位在 bit1) */
regval &= ~SPI_CR_CPOL_MASK;
/* 设置 CPOL 值 */
if (cpol)
regval |= SPI_CR_CPOL_HIGH; /* CPOL=1: 空闲高电平 */
else
regval |= SPI_CR_CPOL_LOW; /* CPOL=0: 空闲低电平 */
/* 写入控制寄存器 */
writel(regval, master->base + SPI_CR);
/* 等待配置生效(某些控制器需要同步) */
while (readl(master->base + SPI_SR) & SPI_SR_BUSY)
cpu_relax();
}
调试建议:在驱动初始化阶段,使用示波器探头测量 SCLK 引脚,确认空闲电平是否符合预期。如果空闲电平与配置不符,检查寄存器位定义是否正确,或者控制器是否存在硬件 bug(某些早期 SPI 控制器需要额外的时钟周期才能稳定输出)。
3.5 本章小结
CPOL 定义了 SPI 时钟在空闲状态下的逻辑电平:
- CPOL=0:空闲低电平,有效边沿为上升沿(配合 CPHA 决定采样/移位)。
- CPOL=1:空闲高电平,有效边沿为下降沿(配合 CPHA 决定采样/移位)。