[THIS POST IS OUTDATED. VISIT NEW POST FOR I2C HERE ]
I2C PROTOCOL
Hola Amigos
I2C devices have been around us for a long time. If you have done any arduino projects with any peripherals such as Bluetooh (HC-05) or Gyroscope (MPU6050) or Barometer etc you might be surprised you have already used I2C devices. Yes
I2C devices have been around us for a long time. If you have done any arduino projects with any peripherals such as Bluetooh (HC-05) or Gyroscope (MPU6050) or Barometer etc you might be surprised you have already used I2C devices. Yes
An I2C basically consists of a master microcontroller and a slave device which responds to the requests of the master. A slave cannot operate on its own. It can't even communicate with other slaves without having any permission from the master.
You may have come across multi-master schematic but it becomes much more complex to handle such situation because of data leakage and also it requires more than 1 microcontrollers. So if you are using an I2C you cannot use any other non-I2C device on the same bus as both SDA and SCL lines are in conjunction with the I2C module. If you find this facility somewhere you are being fooled seriously !!!
I2C works on 2 signals as SCL and SDA
SCL - Serial Clock
SDA- Serial Data
When SDA is having negedge and SCL is positive level triggered then we have start signal and with every SCL clock a bit is transferred. Combining up to eight bit the slave receives an address. Then come the R/W signal means whether the slave has to read or write from/to address. AT the very moment after R/W bit the last bit known as acknowledgment bit is sent. Then the slave sends bit by bit data and finalizing by the acknowledge bit and the process comes to a STOP.
Do remember that when SDA changes the SCL lines must remain stable hence SDA doesn't change at posedge or nedge of SCL and only on the level of SCL i.e. either 1 or 0.
Do remember that when SDA changes the SCL lines must remain stable hence SDA doesn't change at posedge or nedge of SCL and only on the level of SCL i.e. either 1 or 0.
Here is a demonstration
Pic Credit- Google
You can easily see the working as I have explained in comparison to the diagrams.
Ok Coming down to the code
Starting with Master module and with its inputs
clk = Normal clock
sda = serial data
scl = serial clock
data_wr = data that has to be written if rw = 0;
address = address of slave
register = address of register which has to be read
rw = read or write pin
Next, we move to the declaration of internal variables
temp = to copy address incoming
register2 = to copy register value
scl2x = clock with which sda works to change sda while scl is 0
i = internal counter
n = single counter for start and stop conditions
One must note that initially, we have sda and scl = 1
After 5ns we turn sda to 0 to introduce start bit condition
From Line 28 to 30 :- we use n as a flag to start scl and scl2x to start bit transmitting
At Line 33 :- Temp stores the concatenated value of the address of slave then rw bit and acknowledge bit
At Line 34:- Incoming register address is stored in register2 internal variable because further we will be using shift operators which doesn't work on wires and always does on reg data type.
At Line 36 :- If n==1 means start condition and if rw=1 means we have to read register thus scl will run upto 50 times
Similarly, for rw=1 means, we have to write scl will run 64 times.
The value 50 and 64 can be obtained by self-coding
This piece of code is for stop bit condition.
At Line 55 :- Till value of i reaches 9 we will grab bit by bit from temp
Here temp is having 6 bit slave address and 2 bits of rw and ack. Thus each bit is being read by shifting temp one by one and reading its MSB
Same is happening after Line 60 to get the address of the register
At Line 65 :- if rw ==0 we will receive data which has to be written hence the same process is followed too.
Here is the full code -:
Master Code-:
module master(data,address,clk,rw,sda,scl,register,data_wr);
output reg sda;
input [7:0] data;
input [7:0] data_wr;
reg [7:0]data_wr_dup;
input clk;
input rw;
output reg scl;
input [6:0] address;
input [7:0] register;
reg [8:0] temp;
reg [7:0] register2;
reg pstate;
reg scl2x;
reg ack;
reg a;
integer i;
integer n;
initial begin
i = 0;
n = 0;
scl2x = 0;
ack = 1'b1;
sda = 1;
scl = 1;
#5 sda = 0; //START BIT condition starts here
end
always @(negedge sda)
if(scl==1)
n=1;
always @(posedge clk)begin
ack = 0;
temp = {address,rw,ack};
register2 = register;
data_wr_dup = data_wr;
if(n==1 && rw==1)
repeat(50)begin
#2 scl <= !scl;n=0;
#1 scl2x <= !scl2x;n=0;
end
else if(n==1 && rw==0)
repeat(64) begin
#2 scl = !scl;
#1 scl2x = !scl2x;n=0;
end
end
always @(posedge clk)begin
if(i==25 && rw==1)
repeat(2)
#1 scl2x = !scl2x;
else if(i==32 && rw==0)
repeat(2)
#1 scl2x = !scl2x;end
always @(posedge scl2x)begin
if(i<=9)begin
sda = temp[8];
temp = temp<<1;
end
else if(i==12 || i==13)
sda = 1'b0;
else if(i>=14)begin
sda = register2[7];
register2 = register2<<1;
end
if(rw==0 && i>=23)begin
sda = data_wr_dup[7];
data_wr_dup = data_wr_dup<<1;
end
i = i + 1;
if(i>32 && rw ==0)
sda= 1;
else if(i>25 && rw==1)
sda = 1;
end
slave slv(data,sda,scl);
endmodule
And here is the code for Slave-:
module slave(out,sda,scl);
input sda;
input scl;
output reg [7:0]out;
integer j = 0;
reg [6:0]temp;
reg [7:0]add;
reg rw;
reg [7:0]register_address;
reg bitin;
reg [7:0]storage[0:38];
initial
storage[37]=16;
parameter address = 7'b1101001;
always @(posedge scl)begin
//if({sda,scl}==2'b01)begin
bitin = sda;
if(j<8)
temp = {temp,bitin};
if(j==8)
if(bitin==0)
rw = 0;
else
rw = 1;
j = j +1 ;
if(temp==address && (j>15 && j<24) && rw==1)begin
add = {add,bitin};
end
if(temp==address && rw == 0 && j>15 && j!=24 && j<33)begin
add = {add,bitin};
end
else if(j==24)
register_address = add;
if(j==33 && rw==0)
storage[register_address]=add;
out = storage[add];
end
endmodule
And here is the testbench _-:
module tbmast;
// Inputs
reg [6:0] address;
reg [7:0] register;
reg [7:0] data;
reg [7:0] data_wr;
reg clk;
reg rw;
// Outputs
wire sda;
wire scl;
// Instantiate the Unit Under Test (UUT)
master uut (
.address(address),
.register(register),
.clk(clk),
.rw(rw),
.sda(sda),
.scl(scl),
.data(data),
.data_wr(data_wr)
);
initial begin
// Initialize Inputs
address = 105;
register = 7'b0100101;
clk = 0;
rw = 0;
data_wr = 20;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
end
always
#1 clk = !clk;
endmodule
Here is the waveform for rw==0 means write a data to register
Better ZOOM it
Master Model
Slave ModelSo Long
Can it be restarted ?
ReplyDeleteIndeed just put sda=0 in test bench but after certain time
Deletewhat is j in slave code?
ReplyDeleteHello,
ReplyDeleteJ is used here as a counter to initiate operations at approprite timings.
/* input data */ in the master program where it is used???
ReplyDeletewhy input data is declared in master code?
ReplyDeleteHello @Ajisha, @anonymous,
ReplyDeleteSlave devices never have any third connection (out[7:0]) as I have used here. They transfer data back on the SDA line which is read by the master. This would make the code very complicated. Thus for simplicity, we used a separate out[7:0] register to output the data.
The input[7:0] data in the master is a used line. It will receive data back from the slave if the rw bit is meant to read data. It won't work if data is meant to be written. It is connected with the out[7:0] from slave so that the data can be read back in the master. This is how real I2C devices work.The data that will be sent to the slave by the master is processed by data_wr wire which is incorporated into test bench.
ThankYou,
Have a nice day
Eva
Awesome article. Worked perfectly with Xilinx. Had issues with ModelSim. Did you try on Model Sim ?
ReplyDeleteHi Tesla,
DeleteThanks for the compliment. Well yes, Shashi had many issues regarding ModelSim while he was working on I2C. Also the RTL viewer in Xilinx provided a bonus to work upon.
If the transmission of the slave address is successful and recognized by the device, it should send the ACK as 0. But in the snippet of the simulation that you have given, the 9th bit, i.e the ACK bit is high. Does that mean it is a NACK? If so, why is it not re-transmitting the slave address and instead sending the register address? Also why do we have a stream of 0's after the 9th bit? And why is 'data' declared as an input in the master module and not used anywhere except in the port declaration of the slave?
ReplyDeleteQ Why do we have a stream of 0's after the 9th bit?
DeleteA: For a Naive Reason. To make it visually easy and understandable I used a stream of 0's. It can be modified.
Q: Why is 'data' declared as an input in the master module and not used anywhere except in the port declaration of the slave?
A: Because I have used a separate line as out from slave that connects to the input data in master. To avoid complexity and reading data back from slave on the same SDA line increased the complexity. It is just a wire connected between master and slave to read the data.
Q: If the transmission of the slave address is successful and recognized by the device, it should send the ACK as 0. But in the snippet of the simulation that you have given, the 9th bit, i.e the ACK bit is high. Does that mean it is a NACK?
A: No it is an ACK. Actually I hardcoded ack bit in the code because while my team was implementing this code on Basys2 FPGA, we had to face bit conflict issue i.e different bit at the same when Master tried to resend the address. That is why we used hard coded ACK in the code. Also its a mistake here. ACK = 0 and not 1. Thanks for pointing out.
Have a nice day.
Thanks a Lot! :)
DeleteYou are welcome. Do follow us :)
DeleteThanks for the article!
ReplyDeleteCan you tell me how to communicate with slave? How do we check the read operation? Since, the test bench is written for the master, how do we know if the value sent from the master is being written to the slave or not?
Also, how do we read from the slave?
Thank you.
Hi There HiThere,
DeleteNice username by the way.
You will have to select open the slave file on the left panel of simulator. Then right click on any of the wires and select "add to wave". This will instantaneously appear on the wave. Restart the simulation. You will certainly see the data stored inside the array of registers inside slave.
To communicate with slave just pull the SDA line to zero in the test bench after a desired time.
To read operation, firstly, you will have to send the RW bit as 1. Then mention the address of the register. The slave will send the data stored at that address on the out[7:0] line. However you will have to add that line to the wave by the same methid I described above.
Thanks a lot for the quick reply.
DeleteI meant, How do you include the slave instantiation inside the master's testbench and connect it to master and what are the connections that are to be made while doing that?
Slave is not instantiated inside test bench. It is instantiated at line no.75
DeleteIt is a basic connection. Output from one module is input for another module. SDA and SCL are output in master. These are joined with slave as inputs. Similarly output from slave is output which is connected with master as input.
Do check carefully while you are instantiating a module for correct order.
Ex- Slave connections are Slave (output, input, input). The order inside is very important or else you may connect wrong wires.
So instantiating slave in master at line no75 is Slave slv(data, sda, scl)
Master__________________________Slave
data(input)<---------------------- out(output)
SDA (output)-----------------------> SDA (input)
SCL (output) -----------------------> SCL (input)
Thanks a lot! That was really useful!!
Delete:D ;D
DeleteI am new to verilog. I have a few doubts in the code of slve module. Could you pleas help me
ReplyDelete1. What is the significance of bitin in the slave module. Why are we using it and what is it doing
reg bitin;
2. What does the following expression does. Could you give a few examples with the input and output
temp = {temp,bitin};
Hi,
DeleteFirst
temp = {temp,bitin} This line will concatenate the bitin bit to the end of temp.
Example if temp = 101011 and bitin = 0, then {temp,bitin} = 010110 and this will be stored in the temp itself.
bitin helps to gather the data or address on SDA line which is to be stored for useful purposes.
Example for(i<7) temp will store every bitin values repeatedly by concatenating it at the end of temp. This will be the address sent by the master. Similarly at i==8 SDA value is again stored in bitin which tells us whether rw is enabled or not.
Actually I was having difficulties working with SDA wire hence I had to store the wire value locally to perform operations.
Regards
subbu
ReplyDeleteHi I want to know the code for multi slave with single master
How to communicate multiple slave with the same logic as you mentioned
ReplyDeleteHola,
DeleteYou will have to copy the code of slave and recreate a module named slave1 or anything different from previous one.
Then you will have to change the line that says
parameter address = **Unique Address**; in that particular slave code.
Finally in the test bench set address = **Unique Address**.
The if statement in each slave will first match the incoming address and only then it will start communication.
Do remember to instantiate all slaves in master.
Hello Thanks for the reply and if i want to communicate with one slave at a time and stop the operation of others how can i do it using the same logic even if the address does not match as you mentioned
ReplyDeleteThis code will work with only one slave at a time ONLY if you have assigned different address to each slave . If the address doesn't match then the variable in Slave module named "Register_address" will be equal to XXXXXX.
DeleteSince the address won't match therefore, this if loop
if(temp==address && (j>15 && j<24) && rw==1)begin
will not execute.
No need to worry. As long as Slave address is not matched, it will remain in a stop condition.
Just remember to give different address to each slave and you are good to go.
Hi i have a small error like
ReplyDeleteERROR:Xst:871 - "step 1.v" line 73: Invalid use of input signal as target.
This is while instaniating slave code in master in Xilinx 9.2 version so say me how to fix that error.
Hi the error is i m using data while instating slave as output in master code in the same way as you mentioned like Slave slv(data, sda, scl) but here the xilionx is saying that invalid use of data as target.
ReplyDeleteYou can't use data terminal for target. After contacting with slave, slave will send a data. Instead of keeping this data on SDA line, I have kept this information on *DATA* line for ease of use and visibility. So whenever communicated, the slave will send the data stored in it's arrays on the data line by *ITSELF*. If you want to see any particular data then store your data in the arrays inside the slave code.
DeleteThis is the line in slave that consists of an array to store data. -->
reg [7:0]storage[0:38];
storage[5] = "Your Data"
Hi Shashi ,
ReplyDeleteI wanted to read data from the slave .I updated rw and placed the register address after that. But I am unable to pull down SDA to low.Could you tell me how to do this ?
Can you tell me how to pull the sda line to low for sending next data.
ReplyDeleteHi.
DeleteFollow this link
http://www.hellocodings.com/2018/02/updated-i2c-verilog-code-and-working.html
Follow the note at the end of post where I have explained it.
Hi Jishnu
DeleteFollow this post where I have explained the working my code.
LINK: http://www.hellocodings.com/2017/04/i2c-verilog-code.html
Hi, 50 in line number 37, 64 in 42line,25 in 48th line ,32 in 51st line how do we get these values??
ReplyDeleteThese values were taken by trial and error because in real I2C there is no delay in clock cycles between Slave address, RW, ACK, Register Address. However, I preferred to use delay in order to increase the visibility and ease to find where is the Slave address, RW, ACK, Register Address.
DeleteFollow this link for updated code....
http://www.hellocodings.com/2018/02/updated-i2c-verilog-code-and-working.html
Hi sir , we would like write the data into slave can you provide us logic
ReplyDeletethanking you sir.
Hi,
DeleteWill do so soon.
can you please explain clearly the code from line 31 to 64 in master.How you adjusted the clock and the use of scl2,alpha,direction,How that address and data shifting from slave to master
ReplyDeleteThis comment has been removed by the author.
DeleteHi Sindhu
DeleteFollow this post where I have explained the working my code.
LINK: http://www.hellocodings.com/2017/04/i2c-verilog-code.html
sir we would like to interface fpga as master and lcd as a slave by using I2C communication protocol...could u please suggest us how to proceed further ....
ReplyDeleteHELLO iam facing error in the 73 line in xilinx 14.5 version so please provide me the proper working code completly
ReplyDeleteCheck the link to new post at the top of this post
DeleteSlave slv ( data ,SDA,scl) in this line we r getting error as unable to target the input signal ie data .please rectify error because I have project on this within 2days ..my mail id is : jayanthkumar12131012@gmail.com
DeleteKindly post your code here.
DeleteWhat error are you getting exactly?
This comment has been removed by the author.
ReplyDeletedo we need to include testbench? for viewing the RTL schematic diagram?becose for viewing the rtl schematic diagram we getting error in the 73 line as target input signal "data"is not found..
ReplyDeleteAs far as I have coded in Verliog RTL can be viewed without testbench. It selects the top module for RTL schematic
DeleteSignal data_wr_dup[7] in unit master is connected to following multiple drivers:
ReplyDeletethis is the error
unable to get master RTL DIAGRAM
ReplyDeleteAs I said visit the new I2C code. I have made a new post. Search it in project above or you can find the link at the top of this post.
ReplyDeleteAlso simulation and implementation on FPGA (RTL) is different. Not every simulatio supports RTL because of some syntax like fork join etc. in the comment section of new post you can find *edited* code to view RTL schematic
Here is the link
http://www.hellocodings.com/2018/02/i2c-verilog-code-and-working.html
So Long
hi i am getting this error how to rectify it.
ReplyDeleteERROR:Xst:871 - "i2c_master1.v" line 98: Invalid use of input signal as target.