-2

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!

Tzanker
  • 93
  • 1
  • 6

2 Answers2

2

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
Greg
  • 18,111
  • 5
  • 46
  • 68
1

You are driving the same var rComStarted from two different always blocks. It cannot be implemented in hardware. Therefore it is illegal. Think of a different way of implementing your algorithm. It can only be driven by a single block.

I guess you need to do something like the following:

always @* begin
   if (SCL)
      rComStarted = ~SDAIn;
end
Serge
  • 11,616
  • 3
  • 18
  • 28
  • doesnt this cause rComStarted to change value everytime SCL is high? I need it to only trigger on SDAIn edges while high – Tzanker Sep 23 '22 at 18:46
  • Yes, it is a latch. – Serge Sep 23 '22 at 19:08
  • It doesn't cause it to change when SCL is high, it allows it to change. If SDAIn hasn't changed then rComStarted won't change. This solution does however behave differently to your problem statement as it is **level** rather than **edge** based. – George Sep 27 '22 at 08:06