低速正常、高速报错?FPGA SPI 高频故障全面复盘
2026/7/24 15:12:58 网站建设 项目流程

很多人觉得SPI比I2C简单——没有地址、没有仲裁、没有时钟拉伸,四根线随便接。确实,SPI的协议本身比I2C简单,但在FPGA里实现SPI时,有些坑反而比I2C更隐蔽,因为SPI时钟更快、对时序更敏感,而且一个不起眼的配置错误就能让数据全错。


坑一:CPOL/CPHA搞错——数据全部错位,看起来像乱码

问题现象:

SPI通信"能跑",但接收到的数据全是错的。用示波器看波形,SCK、MOSI、MISO、CS信号都在,时序看着也正常,但读回来的寄存器值就是不对。

根本原因:

SPI有4种工作模式,由CPOL(时钟极性)和CPHA(时钟相位)决定。这两个参数决定了数据在SCK的哪个边沿被采样

模式CPOLCPHA空闲SCK采样边沿典型设备
000上升沿SD卡、大部分ADC
101下降沿大部分传感器
210下降沿
311上升沿部分DAC、OLED

快速记忆法:看从设备datasheet的时序图——数据在时钟沿之前稳定,则CPHA=0;数据在时钟沿之后变化,则CPHA=1。CPOL看SCK空闲电平(高=1,低=0)。

关键点:主从设备的CPOL/CPHA必须一致。一个在上升沿发送、一个在下降沿采样,数据必然错位。

错误做法:

verilog

// 错误:硬编码Mode 0,不看从设备的datasheet

always @(posedge clk) begin

if (sck_edge) begin

rx_data[bit_idx] <= miso;

bit_idx <= bit_idx + 1;

end

end

正确做法:

verilog

parameter CPOL = 0, CPHA = 0;

// SCK输出

assign SCK = (CPOL == 1) ? ~sck_reg : sck_reg;

// 采样边沿与移位边沿(generate块,避免语法错误)

wire sample_edge, shift_edge;

generate

if (CPHA == 0) begin

assign sample_edge = (CPOL == 0) ? sck_reg : ~sck_reg; // 第一个边沿

assign shift_edge = ~sample_edge;

end else begin

assign shift_edge = (CPOL == 0) ? sck_reg : ~sck_reg; // 第一个边沿

assign sample_edge = ~shift_edge;

end

endgenerate

// 采样(电平判断,实际工程建议用边沿检测)

always @(posedge clk) begin

if (cs_active && sample_edge)

rx_data[bit_idx] <= miso;

end

自检方法:

  1. 打开从设备datasheet,搜索"SPI timing"或"SPI mode"

  2. 确认CPOL和CPHA的值

  3. 示波器抓MOSI和SCK,确认数据在正确的边沿稳定


坑二:CS拉高时机太早——最后一个字节丢失或损坏

问题现象:

SPI多字节传输时,前N-1个字节都正确,最后一个字节总是错。有时候读到0x00,有时候差一个bit。

根本原因:

CS不仅仅是“选中”信号,还定义了一次传输的边界。很多从设备在CS拉高时才锁存最后一位数据。如果在最后一个bit还没传输完就拉高CS,从设备会认为传输提前结束。

错误做法:

verilog

// 错误:最后一个bit采样完立即拉高CS

if (sample_edge && bit_cnt == 7)

cs_reg <= 1'b1; // 太早了

正确做法:

verilog

// 最后一个bit采样完成后,等待半个SCK周期再拉高CS

if (sample_edge && bit_cnt == 7) begin

state <= POST_WAIT;

post_cnt <= 0;

end

if (state == POST_WAIT) begin

post_cnt <= post_cnt + 1;

if (post_cnt == SCK_HALF_PERIOD) begin

cs_reg <= 1'b1;

state <= IDLE;

end

end

关键点:

  • 最后一个bit采样完成后,至少等待半个SCK周期再拉高CS

  • 保守一点不会出错


坑三:SPI时钟过快+信号完整性差——高频下概率性丢数据

问题现象:

SPI通信在低速(1MHz)时完全正常,提高到目标速率(20~50MHz)后开始概率性丢数据或读错。错误不固定,用逻辑分析仪不一定能抓到(采样率不足或缓存深度不够)。

根本原因:

当速率超过10MHz后,信号反射、时钟抖动、建立/保持时间不足等问题开始显现。

错误做法:

verilog

// 错误:计数器分频产生SCK,无约束

assign SCK = sck_reg;

正确做法:

verilog

// 使用ODDR输出SCK(提高边沿质量)

ODDR #(.DDR_CLK_EDGE("SAME"), .INIT(1'b0)) sck_oddr (

.Q(SCK), .C(clk_2x), // clk_2x需用PLL产生,频率为SCK的2倍

.D1(1'b0), .D2(1'b1)

);

// 添加时序约束(XDC)

set_max_delay -from [get_pins sck_reg/C] -to [get_ports SCK] 2.0

硬件改进:

  • SCK走线加串联电阻(22~33Ω)抑制振铃

  • 高速SPI(>20MHz)建议用ODDR输出SCK


坑四:多从设备CS管理混乱——总线冲突和数据串台

问题现象:

系统有多个SPI从设备(如ADC + Flash + DAC),单独测试每个都正常,同时使用时偶尔出现数据串台

根本原因:

CS管理不当会导致:

  1. 两个CS同时拉低→ 两个从设备同时驱动MISO → 总线冲突

  2. CS切换间隔太短→ 前一个从设备没释放MISO,后一个就开始驱动

  3. 速率差异大的从设备共用SCK→ 慢设备拖累快设备,或信号质量恶化

错误做法:

verilog

// 错误:直接切换CS,无间隔

assign cs_adc = (sel == 0) ? 1'b0 : 1'b1;

assign cs_flash = (sel == 1) ? 1'b0 : 1'b1;

正确做法:

verilog

// CS切换必须经过全高中间态

localparam DESELECT_WAIT = 4; // 等待周期数(查从设备datasheet)

always @(posedge clk) begin

case (cs_state)

CS_ACTIVE: if (transfer_done) cs_state <= CS_DESELECT;

CS_DESELECT: begin

if (deselect_cnt >= DESELECT_WAIT)

cs_state <= CS_IDLE;

else

deselect_cnt <= deselect_cnt + 1;

end

endcase

end

// 输出CS:任何时候最多只有一个为低

assign cs_adc = (cs_state == CS_ACTIVE && sel == 0) ? 1'b0 : 1'b1;

assign cs_flash = (cs_state == CS_ACTIVE && sel == 1) ? 1'b0 : 1'b1;

额外提示:如果从设备速率差异很大(如50MHz ADC和1MHz EEPROM),建议使用独立SCK或临时降频,避免共用。


调试自检清单

检查项通过条件
CPOL/CPHA匹配主从设备一致,datasheet确认
CS时序正确最后一个bit采样后再拉高CS
高速信号完整无振铃、MOSI/SCK延迟在约束内
多从设备CS无重叠切换时经过全高中间态
SCK时钟源合理使用PLL/ODDR而非计数器分频
示波器验证全速率下波形干净、边沿陡峭

FAQ

Q:SPI最大速率能跑多少?
A:板上10cm以内可达50~80MHz,更长走线建议降到20MHz以下。

Q:CPOL/CPHA搞混了会怎样?
A:大概率全部错,因为每个bit采样点都偏了半个周期。

Q:为什么要用ODDR输出SCK?
A:计数器分频产生的SCK边沿抖动大,ODDR利用专用寄存器,输出边沿质量更好。

Q:多从设备能否共用SCK?
A:可以,但要求所有设备支持相同的SPI模式和相近的速率。


⚠️ 注意事项

  1. CPOL/CPHA是SPI调试的第一排查项。90%的SPI通信问题都是模式配置错误。

  2. CS不是开关,是协议的一部分。CS的setup/hold时间同样重要。

  3. 高速SPI必须用示波器。逻辑分析仪采样率(100~200MHz)在50MHz以上不够用。

  4. 先用低速跑通,再逐步提速,同时用示波器监控信号质量。


关注我,本期接口协议避坑,FPGA定制开发、项目调试、IP定制,开发服务可私。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询