You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog实现I2C遇多常量驱动错误,求排查及实现方案

错误原因分析

Error (10028)的核心问题是同一个寄存器rComStarted被两个独立的always块同时驱动。Verilog综合规则明确要求:一个寄存器变量只能由一个always块赋值,多个驱动源会让综合器无法确定该寄存器的最终状态,因此抛出冲突错误。

你的代码里,第一个always块在SDAIn下降沿触发时给rComStarted置1,第二个always块在SDAIn上升沿触发时给它置0,这就违反了“单驱动源”规则。

实现预期功能的最佳方案

修正思路

  1. 将两个触发条件合并到同一个always块中,用posedge SDAIn or negedge SDAIn作为敏感列表,同时捕获SDA的上升沿和下降沿。
  2. 时序逻辑中必须使用非阻塞赋值<=,避免仿真和综合结果不一致的问题(你之前用的阻塞赋值=更适合组合逻辑)。
  3. 在块内判断当前触发的是上升沿还是下降沿,结合SCL的电平完成寄存器的置位/复位。

修正后的代码

module SafeI2CSlave(input SDAIn, output SDAOut, input SCL);

reg rComStarted;
reg rChipSelect;
assign SDAOut = rComStarted;

// 合并触发条件到一个always块,使用非阻塞赋值
always@(posedge SDAIn or negedge SDAIn)
begin 
    if(SCL) begin // 仅当SCL为高时处理SDA边沿
        if(negedge SDAIn) begin // SDA下降沿:置位rComStarted
            rComStarted <= 1'h1;
        end else begin // SDA上升沿:拉低rComStarted
            rComStarted <= 1'h0;
        end
    end
end
endmodule

兼容性优化说明

部分仿真器对always块内直接判断negedge/posedge的支持有限,可通过缓存SDA前一状态的方式准确识别边沿,修改后代码如下:

module SafeI2CSlave(input SDAIn, output SDAOut, input SCL);

reg rComStarted;
reg rChipSelect;
reg rSDAIn_prev; // 缓存SDAIn的上一拍状态
assign SDAOut = rComStarted;

// 实时更新SDAIn的前一状态
always@(posedge SCL or posedge SDAIn or negedge SDAIn)
begin
    rSDAIn_prev <= SDAIn;
end

always@(posedge SDAIn or negedge SDAIn)
begin 
    if(SCL) begin
        if(rSDAIn_prev && !SDAIn) begin // 从高到低:识别下降沿
            rComStarted <= 1'h1;
        end else if(!rSDAIn_prev && SDAIn) begin // 从低到高:识别上升沿
            rComStarted <= 1'h0;
        end
    end
end
endmodule

内容的提问来源于stack exchange,提问作者Tzanker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:55:20