Search code examples
verilogfpgai2cquartus

How to drive outputs in Verilog


I am trying to implement I2C in a FPGA to learn verilog, i am a complete beginner and am having trouble with an error:

 Error (10028): Can't resolve multiple constant drivers for net "rComStarted" at I2CModule.v(14)

I am currently just trying to implement the start and end conditions for I2C and as a half way point just want to connect the rComStarted value to the output just to see it working (also you can ignore the face that i have an input and output sda I'm just seperating them for now because im worried about frying something)

To be clearer about what I expect from this code:

  • If SDAIn has negative edge and SCL is high I want to enable rComStarted
  • if SDAOut has posedge and SCL is high i want to pull rComStarted low
  • rComStarted should be connected to SDAOut

code:

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

reg rComStarted;
reg rChipSelect;
assign SDAOut = rComStarted;
always@(negedge SDAIn)
begin 
    if(SCL)
    begin
        rComStarted = 1'h1;
    end
end

always@(posedge SDAIn)
begin 
    if(SCL)
    begin
        rComStarted = 1'h0;
    end
end
endmodule

why am i getting this errors? What is the best way to implement the functionality i want?

Thanks so much!


Solution

  • You need two separate registers for each edge. The example bellow toggles the rComStarted_p and rComStarted_n on there respected edges, then XORs them to rComStarted. The first negedge SDAIn will raise rComStarted (p:0 ^ n:1 = 1). The first posedge will lower rComStarted ( p:1 ^ n:1 = 0). The second negedge will raise rComStarted (p:1 ^ n:0 = 0). Finally, the second posedge will lower rComStarted and will bring rComStarted_p and rComStarted_n back to there initial state.

    module SafeI2CSlave(input SDAIn, output SDAOut, input SCL);
      reg rComStarted_p = 1'b0;
      reg rComStarted_n = 1'b0;
      reg rChipSelect;
      wire rComStarted = rComStarted_p ^ rComStarted_n;
      assign SDAOut = rComStarted;
      always@(negedge SDAIn) begin 
        if(SCL && !rComStarted) begin
          rComStarted_n <= !rComStarted_n;
        end
      end
      always@(posedge SDAIn) begin 
        if(SCL && rComStarted) begin
          rComStarted_p <= !rComStarted_p;
        end
      end
    endmodule