Verilog时钟沿等待与SD卡初始化延时失效问题求助
解决Verilog Always块中SD卡初始化延时被忽略的问题
看起来你在SD卡初始化的时序控制上踩了Verilog仿真/综合里的常见坑——行为级延时语句没按预期工作,甚至连信号边沿等待都被忽略。我来帮你拆解问题原因,再给你靠谱的解决方法:
核心问题:行为级延时的“隐形陷阱”
你用repeat或for循环做延时却没效果,大概率是因为这些循环没有绑定到时钟沿上。比如如果你的代码是这样的:
always @(posedge clk) begin cs_n <= 1'b0; // 空循环,仿真里会瞬间执行完,不会产生真实延时 repeat(74) begin end cmd <= CMD0; end
这种写法只是在仿真进程里做了空循环,没有等待时钟沿,自然不会产生74个周期的延时。哪怕你展开循环,本质还是一样的——没有和时钟同步的行为级语句,仿真器会直接跳过延时逻辑。
另外,@(posedge writeRDY)被忽略,通常是因为这个信号在进入always块时已经处于高电平,或者信号本身没有正确产生上升沿(比如是组合逻辑输出的毛刺,或者驱动逻辑有问题)。
靠谱的解决方法
1. 用显式计数器实现延时(仿真+综合双兼容)
综合工具对行为级循环的支持有限,而且仿真时容易出问题,最稳妥的方式是用计数器来实现固定周期的延时,这种写法无论仿真还是综合都能准确产生时序:
// 假设clk是你的系统时钟,rst_n是复位信号 reg [6:0] cs_delay_cnt; // 7位寄存器,足够计数0~73(对应74个周期) reg cs_delay_done; reg cs_n; reg [31:0] cmd; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cs_n <= 1'b1; // 复位时CS拉高 cs_delay_cnt <= 7'd0; cs_delay_done <= 1'b0; cmd <= 32'h00000000; end else begin if (!cs_delay_done) begin cs_n <= 1'b0; // 拉低CS开始延时 if (cs_delay_cnt == 7'd73) begin // 计数到第74个周期时完成延时 cs_delay_done <= 1'b1; cmd <= 32'h40000000; // 发送CMD0(根据SD卡协议调整) end else begin cs_delay_cnt <= cs_delay_cnt + 1'b1; end end // 后续初始化逻辑可以放在cs_delay_done为高之后 end end
这种写法通过计数器明确跟踪时钟周期,完全符合SD卡要求的“CS拉低至少74个时钟周期”的时序,仿真波形里能清晰看到延时效果,综合后也能在硬件里正确实现。
2. 修复@(posedge writeRDY)的等待逻辑
如果writeRDY是一个同步信号,建议先确保它处于低电平,再等待上升沿,避免因为信号初始状态为高而直接跳过等待:
always @(posedge clk) begin // 先等待writeRDY变低(确保我们捕捉的是下一个上升沿) while (writeRDY != 1'b0) begin @(posedge clk); end // 再等待writeRDY的上升沿 @(posedge writeRDY); // 后续逻辑... end
同时,记得在仿真里检查writeRDY的波形,确认它是否在预期的时间点产生有效的上升沿——如果信号本身没有翻转,等待语句自然不会生效。
额外注意事项
- 阻塞/非阻塞赋值:时序逻辑里一定要用非阻塞赋值
<=,避免产生竞争冒险;组合逻辑用阻塞赋值=。 - 仿真类型:如果是功能仿真,有些工具可能对行为级延时的处理比较宽松,但时序仿真(Post-Synthesis Simulation)会更贴近硬件实际情况,建议用时序仿真验证最终的初始化时序。
内容的提问来源于stack exchange,提问作者Matthew Dickson
相关产品推荐
相关产品推荐

