SPI四种工作模式:CPOL与CPHA详解

做SPI接口设计,绕不开的就是这四种工作模式。我记得刚入行那会儿,看到数据手册里CPOL、CPHA这两个参数,说实话有点懵。后来自己动手调了几次波形,才真正搞明白它们到底在说什么。

说白了,SPI的四种模式就是时钟极性和时钟相位的四种组合。你想想看,主设备和从设备要通信,总得约定好什么时候采样数据、什么时候切换数据吧?这就是CPOL和CPHA干的事。

CPOL:时钟极性

CPOL决定的是时钟信号在空闲时的电平状态。

  • CPOL = 0:空闲时时钟为低电平
  • CPOL = 1:空闲时时钟为高电平

嗯,这里要注意:空闲状态指的是没有数据传输的时候。我见过不少新手把空闲状态和传输过程中的电平搞混,结果波形怎么调都不对。

CPHA:时钟相位

CPHA决定的是数据在时钟的哪个边沿被采样。

  • CPHA = 0:在时钟的第一个边沿采样数据
  • CPHA = 1:在时钟的第二个边沿采样数据

为什么会这样设计?其实就是为了给不同需求的从设备提供灵活性。有些从设备需要在时钟上升沿采样,有些需要在下降沿采样,CPHA就是用来控制这个的。

四种模式的完整组合

模式 CPOL CPHA 空闲时钟电平 采样边沿 数据切换边沿
模式0 0 0 低电平 上升沿 下降沿
模式1 0 1 低电平 下降沿 上升沿
模式2 1 0 高电平 下降沿 上升沿
模式3 1 1 高电平 上升沿 下降沿
核心要点:模式0和模式3是最常用的两种模式。我个人习惯优先用模式0,因为大多数SPI从设备都支持它。但如果遇到一些特殊的传感器或ADC,就得仔细看数据手册了。

时序差异详解

光看表格可能还不够直观。我画了一张时序图,帮你把四种模式的区别看清楚。

SPI四种工作模式时序对比 模式0 CPOL=0, CPHA=0 模式1 CPOL=0, CPHA=1 模式2 CPOL=1, CPHA=0 模式3 CPOL=1, CPHA=1 MOSI D0 D1 D2 D3 ...... 采样点(模式0/2) 采样点(模式1/3) 绿色圆点 = 上升沿采样 | 橙色圆点 = 下降沿采样 模式0和模式3采样边沿相同,但空闲电平不同

模式匹配的重要性

这一点我必须强调:主设备和从设备的模式必须完全一致。听起来很简单对吧?但我在项目中遇到过好几次因为模式不匹配导致的通信失败。

⚠️ 避坑指南:我曾经调试一个温湿度传感器,折腾了两天就是读不到正确数据。后来用示波器一看,从设备数据手册里写的是模式2,但我代码里配的是模式0。CPOL和CPHA全反了,能通才怪。

为什么会这样?因为模式不匹配会导致采样点落在数据切换的边沿上。你想想看,数据正在变化的时候你去采样,采到的值可能是0也可能是1,完全不可靠。

如何判断从设备的工作模式

拿到一个SPI从设备的数据手册,怎么快速判断它用哪种模式?我教你一个方法:

  1. 看时序图:找到数据手册里的SPI时序图,看空闲时SCK是高还是低(确定CPOL)
  2. 看采样边沿:看数据是在SCK的上升沿还是下降沿被采样(确定CPHA)
  3. 对照表格:用上面那张表一查就知道是模式几了
💡 小技巧:有些数据手册会直接写"SPI mode 0"或"SPI mode 3",那就省事了。但有些手册只给时序图,你得自己判断。我个人习惯是先按模式0试,不行再换模式3,因为这两个最常用。

代码实现中的模式配置

在Verilog里配置SPI模式其实不复杂。核心就是控制两个东西:时钟空闲电平和采样边沿。


// SPI模式配置示例
reg sck_idle;      // 时钟空闲电平
reg sample_edge;   // 采样边沿:0=上升沿,1=下降沿

// 根据模式配置
case (spi_mode)
  2'b00: begin  // 模式0
    sck_idle    <= 1'b0;  // 空闲低
    sample_edge <= 1'b0;  // 上升沿采样
  end
  2'b01: begin  // 模式1
    sck_idle    <= 1'b0;  // 空闲低
    sample_edge <= 1'b1;  // 下降沿采样
  end
  2'b10: begin  // 模式2
    sck_idle    <= 1'b1;  // 空闲高
    sample_edge <= 1'b1;  // 下降沿采样
  end
  2'b11: begin  // 模式3
    sck_idle    <= 1'b1;  // 空闲高
    sample_edge <= 1'b0;  // 上升沿采样
  end
endcase

// 生成SCK时钟
always @(posedge clk or negedge rst_n) begin
  if (!rst_n)
    sck <= sck_idle;
  else if (spi_en)
    sck <= ~sck;  // 时钟翻转
  else
    sck <= sck_idle;
end

// 数据采样逻辑
always @(posedge clk) begin
  if (spi_en && (sck == sample_edge))
    data_in <= miso;  // 在指定边沿采样
end

这段代码我用了很多年,基本没出过问题。唯一要注意的是:时钟使能信号spi_en的时序要处理好,不然第一个时钟周期可能会多一个毛刺。

实际项目中的模式选择建议

说了这么多,到底该用哪种模式?我的建议是:

  • 优先用模式0:兼容性最好,大部分SPI从设备都支持
  • 模式3也不错:和模式0的采样边沿一样,只是空闲电平不同
  • 模式1和模式2:除非从设备强制要求,否则尽量少用

嗯,这里还要提醒一点:如果你在做FPGA和MCU之间的SPI通信,两边都要配成一样的模式。我见过有人FPGA配了模式0,MCU配了模式3,结果数据全是乱的。

总结一下:SPI的四种模式其实就是CPOL和CPHA的排列组合。搞懂了时钟空闲电平和采样边沿这两个概念,模式匹配就不再是难题。记住:主从设备的模式必须一致,这是SPI通信能正常工作的前提。

好了,关于SPI的四种工作模式就讲到这里。这些内容看起来简单,但实际项目中踩坑的人真不少。希望你能把这些基础打牢,后面做SPI控制器设计的时候会轻松很多。