Verilog中的I2C从模块未确认

Verilog中的I2C从模块未确认,verilog,i2c,Verilog,I2c,我用Verilog编写了这个I2C从模块: module I2CSlave( input iSCL, input iI2C_CLK, inout bSDA, output reg [7:0] odata, output reg oread, output wire oactive ); reg incycle = 1'b0; reg pSDA; reg pSCL; always @(posedge iI2C_CLK) begin if ((pSCL) && (i

我用Verilog编写了这个I2C从模块:

module I2CSlave(
input iSCL,
input iI2C_CLK,
inout bSDA,
output reg [7:0] odata,
output reg oread,
output wire oactive
);    

reg incycle = 1'b0;
reg pSDA;
reg pSCL;
always @(posedge iI2C_CLK) begin
    if ((pSCL) && (iSCL) && (pSDA) && (~bSDA)) begin
        incycle <= 1;
    end
    if ((pSCL) && (iSCL) && (~pSDA) && (bSDA)) begin
        incycle <= 0;
    end
    pSDA <= bSDA;
    pSCL <= iSCL;
end

assign oactive = incycle;

localparam STATE_IDLE = 0;
localparam STATE_ADDR = 1;
localparam STATE_RW = 2;
localparam STATE_ACK = 3;
localparam STATE_DATA = 4;
localparam STATE_ACK2 = 5;

reg [7:0] i = 0;
reg [7:0] state = STATE_IDLE;
reg [6:0] addr = 7'h03;
reg addr_match = 1;
reg rw;

reg lSDA;
always @(posedge iSCL) lSDA <= bSDA;

assign bSDA = ((state == STATE_ACK) || (state == STATE_ACK2)) ? 0 : 1'bz;
assign oread = (state == STATE_ACK2);
assign ostate = i;

always @(negedge iSCL or negedge incycle) begin
    if (~incycle) begin
        state <= STATE_IDLE;
        addr_match <= 1;
    end
    else if (addr_match) begin
        case (state)
            STATE_IDLE: begin               
                state <= STATE_ADDR;
                i <= 7;
            end
            STATE_ADDR: begin
                if (addr[i-1] != lSDA) addr_match <= 0;
                if (i == 1) begin
                    state <= STATE_RW;
                    i <= i - 1;
                end
                else i <= i - 1;
            end
            STATE_RW: begin
                rw <= lSDA;
                state <= STATE_ACK;
            end
            STATE_ACK: begin
                state <= STATE_DATA;
                i = 7;
            end
            STATE_DATA : begin
                odata[i] <= lSDA;
                if (i == 0) state <= STATE_ACK2;
                else i <= i - 1;
            end
            STATE_ACK2: begin
                state <= STATE_DATA;
                i = 7;
            end
        endcase
    end
end

endmodule
模块I2CSlave(
输入iSCL,
输入iI2C_时钟,
inout bSDA,
输出寄存器[7:0]odata,
输出reg oread,
输出线有源
);    
reg incycle=1'b0;
注册会计师协会;
注册pSCL;
始终@(posedge iI2C_CLK)开始
如果((pSCL)&(iSCL)&&(pSDA)&&(~bSDA))开始

incycle您的代码有几个问题,可能会导致模拟和合成中的行为不匹配。例如,以下内容是不可合成的,并且被合成工具忽略。所以,你的初始状态会有所不同。检查日志中的警告。不要对
regs
使用声明分配。(适用于电线)

上述情况意味着您的初始化不起作用

你把状态机中的阻塞和非阻塞分配搞砸了。确保在“i=7”的所有地方使用NBA。应该是

i <= 7;

i在实际硬件上运行时出现随机故障的一个可能原因是您没有同步输入

您正在对缓慢变化的信号进行采样(i2c总线将有一个很长的斜率),这些信号与您的设计时钟完全异步。取决于您的运气,您的fpga的d-FLOP的设置/保持时间将随机违反,这将导致亚稳定性问题。寄存器中的相同值在芯片的多个部分中可能会得到不同的处理。这将严重破坏i2c从机的逻辑


您必须同步异步输入,在最简单的情况下,在将其馈送至模块的fsm之前,将其通过两个寄存器传递。

测试台仅尝试通过发送地址来启动通信,然后发送1字节的数据。此外,必须在模拟中加快通信速度,因为在Quartus Lite中只有100个us可用。为什么不能合成呢?是的,在ASIC中,您必须显式重置寄存器,但基于sram的fpga肯定会将寄存器初始化为指定值,合成器也不会抱怨。或者可能只有Altera/Xilinx允许这样做?好的,找到了一个很好的答案:谢谢你的提示。我将错误的阻塞分配替换为非阻塞分配。然后,我删除了不必要的初始化,并将所需的初始化移到初始块中。所以未初始化的寄存器应该等于0,对吗?问题是,FPGA仍然以相同的方式工作。我还应该在模拟中测试什么?@Vlad我正在使用Altera,所以它可能会像我在原始设计中使用的那样工作,正如你所写,但我也试图避免它,正如Serge所写,不过,在这两种情况下,它的行为都是相同的。@MartinSchmied您必须记住,初始块也不是可合成的。您需要创建一个重置条件,以便初始化变量。
i <= 7;