I2C Verilog Code and working


I had already made a post regarding I2C long ago, however, in this post I am reposting I2C but with various changes. Some changes involve the using of Acknowledgement Bit by the Slave and Master, Same SDA line for slave address, register address as well as data. No extra data line is required to read the data from the slave. Everything can be seen on the SDA line along. This version of I2C in Verilog has the full support of adding *multiple* slaves.
Yes!! You can use multiple slaves at the same time. The only feature lacking that I am working on right now is the RW bit. The RW or better say Read/Write bit is present here but I have focussed only on the read operation here. I am working on the write operation too and will update soon for the latter.

For this I2C I had to grasp myself with the knowledge of the inout signal line in Xilinx. The SDA has to be an inout line or else it won't be a proper I2C model, despite serving the same functionality.

The Master will send 7-bit address along with RW bit on the SDA line and the corresponding slave will respond back with an ACK bit. After that Master will send the register address which will be acknowledged
by the slave with an ACK bit. Then the slave will send the 8-bit data from the received register to the Master. After receiving the data, Master will respond back with ACK bit and after a CC the I2C operation will end with the STOP bit.

The SCL line changes only when SDA is stable. The testbench I have used here only acts as a supervisor which provides a clock signal to Master. The Master is connected to the slave only with SDA and SCL line.

*DISCLAIMER: This Verilog Code only supports "Read" Operation. I'll continue with the "Write" operation later.

I have worked on this code using a different approach. If the Slave address that Master sends doesn't match with the Slave then it will keep on sending the same address. However, this approach is only applicable to 1 Slave. Consider the case where there are two slaves S1 and S2. If S1 address is matched then data exchange takes place between Master and S1. However, S2 will then inflict as the address won't match here. This will lead to an error on the SDA lines inform of X.

Thus to overcome this difficulty I have re-changed the code to NOT to send address, again and again, i.e if the address doesn't match then Master won't resend the address. Although a Master should keep on sending the address in real, my code faces a problem which I'll deal later.

As I have mentioned that I have used inout command in this code. Inout command should only be used using a tri-state buffer.

A tristate buffer is coded somewhat like this:
x <= direction?data:1'bZ;

A tristate buffer has an enable pin. When enabled (here direction == TRUE) then data will be transmitted. On the other case, when disabled (here direction == FALSE) then a high impedance is
sent thereby disconnecting the output from the input circuit. Consider A and B. When A is true then it is at higher potential. When B is false it is at a lower potential. As current flows from High to Low, this signal will blow from A(TRUE - 1) to B (FALSE Z). Similarly, if B is true and A is false then signal will flow from B to A.

While I was coding, I faced tremendous problems with switching between TRUE and FALSE in both Master and Slave. If both A and B are set to TRUE then you will get ZZZZZZZ (in blue color) as output. If both A and B are low you will get XXXXXX (in red color) as output. 

The signal line of type inout can only be a wire. It cannot be registered as reg type so to use it we have to use the "assign" keyword.

RW- 0 ACK = 1 Slave address matched

RW- 0 ACK = 0 Slave address not matched

Get Single Master Single Slave Code from here: Github I2C_Code

Master & Slave


Test Bench

NOTE - To restart the I2C transmission all you have to do is give a fork join condition
fork
#160 alpha <= 0;
#160 direction <= 1;
#162 left_bits <= 1;
join



Place this piece of code in the initial begin of the Master Code. Remember that you have to give sufficient #time condition to avoid conflict. With this you can you can pull SDA line low to restart I2C for a new data. However, data will too remain same. Thus you will have to change the data by using #time syntax like this in Master

fork
#160 alpha <= 0;
#160 direction <= 1;
#162 left_bits <= 1;
#160 register = 7'b00011001; // 00011001 = 25 in decimal
#160 reg_temp = register;
join

In Slave you will have to enter new data in the array at location 25.

Sim View of the code above in Xilinx




For Multi Slave I2C significant changes are required. Consider a case where we have two slaves named A and B. The master will send the address of A. In that case slave A will send acknowledgment bit (1 in this case) on the sda line. However, slave B will also send acknowledgment bit (0 in this case). This creates a problem as Verilog doesn't allow multiple drivers for a single wire. Even if I simulated I got ZZ as the acknowledgment because of that conflict.

It can be represented as follows


Thus to avoid this condition I used the Verilog keyword "wor". wor is logical OR of wires joint together.

In case if Slave A NACK = 0 and Slave B NACK = 1 then wor would output as 1(B) + 0(A) = 1

Similarly

0(A) + 0(B) = 0

0(A) + 1(B) = 0

1(A) + 1(B) = NOT POSSIBLE FOR I2C WITH SAME ADDRESS.


The following piece of code has a single master and 3 slaves. One thing I came to notice that all slaves code can remain same except the module name or else any change made to any slave would result in a change is every slave.


Multi Slave Code (Works Pretty well. Comment or message for any error)
To change slave address one can change it to desired address by changing address at line 22 of Master

To fully understand my code click HERE
So Long

23 comments:

  1. Thanks It Worked buddy!!
    How soon will you do Multi Slave one?

    ReplyDelete
    Replies
    1. I am currently working on it. Will upload as soon as I finish

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Your multi slave code worked. Though I have copy pasted the code. :P
      Can you please explain the code a bit. Also why the images of sda and scl are different. Sda has a different starting point in both image

      Delete
    4. Fine, I'll do so.
      Ya there is a change in the sda line.
      In the first image there is a mistake. SDA changes when SCL was high. However in the last image I have corrected the mistake. Now SDA changes only when SCL is low (not posedge or negedge).
      I hope you got it

      Delete
  2. I want the code for multiple slave for multiple slave within a day bro it's urgent

    ReplyDelete
  3. Hi i m subramani purusuing final year i m in need of a doubt in this program i have an error named as
    ERROR:Xst:528 - Multi-source in Unit on signal
    ERROR:Xst:528 - Multi-source in Unit on signal
    This program i have worked in Xilinx ISE 9.2i .I need to overcome this error within tomorrow help me out for the project review

    ReplyDelete
    Replies
    1. Multi-Source in Unit specifies that 1. Maybe two units are trying to drive same line. (This is why I used SDA as inout using tristate buffer). Another reason could be that a line is being driven by multiple code blocks in the same module. Most of the time it is always block. Each always block with similar sensitivity must have unique signals within it.
      You can't use
      always @(posedge clk)
      reset <= 0
      always @(posedge clk)
      if (count==64)
      reset <= 0

      This is wrong. Try to keep it within the same always block. Maybe this could be the reason. Although I didn't face such type of error. Keep Exploring !!

      Delete
  4. Hi i m subramani you have said that to keep in the same always block in your code explain me how to keep line 44 always block into line 38 always block in the master code

    ReplyDelete
    Replies
    1. There is no need to do so. Line 38 and Line 40 are comparison statements of a with 0 and 1 respectively. On the contrary Line 44 inside the always block we are driving the signal a.
      Line 37 Always block does not contain any driving signal a, only comparing is taking place.

      Delete
    2. ya you are saying its just comparing but if i m leaving both those always block it is saying an error as multisource error so only i am asking how to merge that code within a single always block to avoid that error

      Delete
  5. i need the complete output of the program for my verification process of output.you can send the output to subramanian2828@gmail.com mail id .I need your help to complete this project as soon as possible.

    ReplyDelete
  6. i am getting so many warnings in the same code as you have written .in which xilinx version you have worked ,currently i m working in xilinx 9.2 version is it ok for the simulation process or work in another xilinx platform and i have another doubt as will this code work in modelsim and if it does how can i see the output with these ports .help me out as soon

    ReplyDelete
    Replies
    1. Well I am using Xilinx 14.2 Version. Yes the code will certainly work on ModelSim however, ModelSim has some limitations.

      "These Port" Which ports do you want to see ?

      You can easily select ports of any module you want from the simulation windows. To the left side you will see "Instance and Process Name". Under that click the triangle icon to get the list of all master and slave ports.

      Also I am hoping that you are using test bench which provides clock signal to the master. Do remember that you have to simulate "Test Bench" and NOT the Master code. from the Hierarchy menu on the left of Xilinx window.

      Delete
    2. While creating the test bench you will have create a new Verilog Test Fixture and NOT Verilog Module.

      Delete
  7. ya you are saying its just comparing but if i m leaving both those always block it is saying an error as multisource error so only i am asking how to merge that code within a single always block to avoid that error.This is for the always block question i have asked previously

    ReplyDelete
    Replies
    1. Well it isn't showing in my code.
      Are you trying to view the RTL Schematic ?

      Delete
  8. Hi i m subramanian i need the full complete output of multislave program with 2 different input sets within a day its urgent send that to subramanian2828@gmail.com

    ReplyDelete
  9. Hi i m subramanian i need the complete output of multislave program with 2 different input sets as one with correct slave address and the other with incorrect slave address its urgent send that to subramanian2828@gmail.com mailid

    ReplyDelete
    Replies
    1. The Screenshot is already attached with this post. In the screen shot first Slave1 address is matched and not Slave 2 hence transaction occurs. However when restarted Slave2 address is matched and not Slave 1.
      Checkout the screenshot above

      Delete
  10. Hello Shashi

    For this verilog code of i2c synthesis report generation is not being dealt easily can u help me in this issue

    ReplyDelete