cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
fradaric
Observer
Observer
14,914 Views
Registered: ‎05-29-2012

I2C protocol

Hei friends,

 

I made a verilog code for I2C, and I need to test my design. I made a testbench and while testing, the "inout" pin can't be assign any values. Since it is I2C protocol after the start and address bits there will be a acknoledge 'high" bit from slave(assume mine is the master I2C) , so how can I test my design by providing the ack in testbench. Or let me know is there any other ways to do this......

 

regards,

Fradaric

fradaric@gmail.com

Joe
0 Kudos
13 Replies
gszakacs
Professor
Professor
14,906 Views
Registered: ‎08-14-2007

There are two ways to test this.  When you say that the "inout" pin can't be assigned,

you're only partly right.  A continuous assignment to a hard value like 0 or 1 will override

the output of your unit under test.  Therefore the inout SDA pin needs to be assigned

a Z by the testbench when it isn't driven by the testbench.  For example if your testbench

includes a signal ACK that indicates when to drive the SDA line low by the testbench,

you can have:

 

assign SDA = ACK ? 1'b0 : 1'bZ;

 

Another way to test your master code is to instantiate an I2C slave in the testbench

and just wire the SDA and SCL lines between the two.  In addition you should

add pullups to the testbench:

 

pullup (SDA);

pullup (SCL);

 

This makes sure that the unit under test and I2C slave both read a 1 on the lines

when they are not actively driven low.

 

-- Gabor

 

See also this thread:

 

http://forums.xilinx.com/t5/Spartan-Family-FPGAs/VHDL-I2C-Slave-core/td-p/2831

-- Gabor
0 Kudos
fradaric
Observer
Observer
14,884 Views
Registered: ‎05-29-2012

Dear, I really don't understand. In my design I made one reg sda_int and inout pin sda.

for passing values to slave I use sda_int and then 'assign sda    =sda_int;'

to get values from slave I am using sda. And I am still confused how to test this device. In my top module I have a reg named 'ack' it becomes high when slave acknowledges, but in test bench how can I do this??? ie testbench parameters are

I2C uut (
        .sda(sda),
        .scl(scl),
        .out(out),
        .clk(clk)
         );

 

Joe
Tags (1)
0 Kudos
avrumw
Guide
Guide
14,880 Views
Registered: ‎01-23-2009

In the I2C protocol, all drivers are "open drain". What this means is that drivers can only pull the signals low - they can never pull them high. There is also a resistor on the "board" which will pull the signals high when there is no active driver pulling them low.

 

In the simulation world, this means that (first), you need a pullup on SDA and SCL. As Gabor suggested, you can use the Verilog "pullup" primitive.

 

The clock is normally managed by the master - it pulls the clock low and then releases it more or less periodically during an operation. A slave is allowed to also pull the clock low (when it is already low) to extend a bit cycle - this is called "clock stretching" and only slow slaves do it. Lets assume for the moment that your testbench slave won't do this...

 

Now comes the SDA line. The master will drive it low and release it appropriately for the start condition as well the first data bits. At the end of the the first byte, it is time for the slave to ACK the access, or not. To do this, it will pull the SDA signal low, and release it after the ACK is compelete (based on the clock, which is controlled by the master).

 

Like the master, the slave is only allowed to pull signals low, and release them (allowing the pullupto pull them high). In simulation, this is done using a reg, but only assigning one of two values - either 1'b0 to pull the signal low, or 1'bz to allow it to float, which will cause the pullup to pull it up (assuming the other driver is not also driving it low).

 

So in your case, your slave can sample sda when it is supposed to be receiving data as long as sda_int is set to 1'bz. During the ACK time, if you want to ACK the byte, then set sda_int to 1'b0. Once the ACK is complete, return it to 1'bz.

 

Avrum

0 Kudos
fradaric
Observer
Observer
14,854 Views
Registered: ‎05-29-2012

Heyy..

 

In my design the delay time for I2C is not included.. How can I do that, the edges of SDA also appear to coincide with the clock edges of SCL,  in verilog language I am assiging slave/pointer address to sda by a always @(posedge scl) , thats y this problem occurs...... but I don't know how to solve this, ie how to make transitions 100ns prior to the clock edge (my slave device needs 100 ns setup time). 

Joe
0 Kudos
fradaric
Observer
Observer
14,850 Views
Registered: ‎05-29-2012

 

 

I have attached the timing digram below, which shows the problem that I asked before. i.e my scl and sda transitions occures at the same time. How can I add the setup time(100ns).  I was doing the slave address assignments , pointer addressins with a always @(posedge scl). 

`timescale 1ns / 1ps
// Fradaric Joseph
// Indian Institute of Technology Guwahati
// Ph: 09401015142

module I2C( 
	inout sda,
	output scl,
	output [15:0] temperature_out,
	input clk,
	output [2:0] ack_out,
	output [1:0] ack_count1,
	input reset
	);

parameter clock_div=500; //  I2C clock 50MHz/(500)=100KHz
//---------------------------I2C State Machine Variables----------------------
parameter Rxidle	=0;
parameter Rxstart	=1;
parameter RxPointeraddr	=2;
parameter Rxstart1=3;
parameter Rxdata	=4;
parameter Rxstop	=5;
//-----------------------------------------------------------------------------
reg chk=0;
reg [2:0] ack;
reg [1:0] ack_count=0;
//reg poiter2=0;
//reg ack2=0;
//reg ack3=0;
//------------------------------------------------------------------------------
reg I2Cclk			=1;  // I2C clock 
reg [8:0] clkclk=clock_div; // in order to divide 50MHz clock 
reg sda_int			=1; // making SDA high in initial state
reg [15:0] outreg	=0;
reg [3:0] I2C_counter=0;  // for giving the pointer address (000000-00(P1P0))
reg [3:0] bitaddrs7=4'b0001; // initializing via giving slave address(1001000-0(R/W))
reg [3:0] Rxcount=0;
reg [3:0] slaveaddrs=0; //receiving data from TMP 100
/// ----------------------------------------------------------------------------
	reg [2:0] state 	=Rxidle ; // For State machine starting
	assign scl	=I2Cclk;// Generated Clock for I2C
	assign  temperature_out = outreg;  // output from TMP 100
	assign sda	=sda_int; // Using SDA pin
	assign ack_out=ack;
	assign ack_count1=ack_count;
////------------------------------
always @ (posedge clk) /// --------------------- scl generation-----------------
begin
if(!chk)
	begin
		clkclk=clkclk - 1; 
		if(clkclk==0)
		begin
		I2Cclk=~I2Cclk;
		clkclk		=clock_div;
		end
end 
else I2Cclk=1'b1; end
////.............................................................................
always @(posedge  I2Cclk )
if(reset)
begin
 chk				<=0;
 outreg			<=0;
 I2C_counter	<=0;  
 bitaddrs7		<=4'b0001;
 Rxcount			<=0;
 slaveaddrs		<=0;
 ack				<=0;
 ack_count		<=0;
 I2Cclk			<=1;
 sda_int			<=1;
 clkclk			<=clock_div;
end

always @(posedge  I2Cclk )
begin


////....................................state machine............................
 
case (state)
//-------------------------------------------------------------------------------
Rxidle: 
				begin  		sda_int=1'b0;	//---------------------start sda = 0
				state			=Rxstart;end
//-------------------------------------------------------------------------------				
Rxstart:
begin
		case(bitaddrs7)
		// initial frame 1001000 Initializing slave address
			1:	begin 
				sda_int				=1'b1;//---------------------sda 1
				bitaddrs7=bitaddrs7+1; end
				
			2:	begin  sda_int		=1'b0;//---------------------sda 0
				bitaddrs7=bitaddrs7+1; end
				
			3:	begin  sda_int		=1'b0;//---------------------sda 0
				bitaddrs7=bitaddrs7+1; end
				
			4:	begin  sda_int		=1'b1;//---------------------sda 1
				bitaddrs7=bitaddrs7+1; end
				
			5: begin	 sda_int		=1'b0;//---------------------sda 0
				bitaddrs7=bitaddrs7+1; end
			
			6: begin	 sda_int		=1'b0;//---------------------sda 0
				bitaddrs7=bitaddrs7+1; end
				
			7: begin sda_int		=1'b0;//---------------------sda=0 	
				bitaddrs7=bitaddrs7+1; end
				
			8:	begin  sda_int		=1'b0;
				ack_count=2'b00; 
				bitaddrs7=bitaddrs7+1;  // R/W  bit
											  end
			9: begin if(sda==1'b0)
				ack[0]=1;
				state=RxPointeraddr;			// Checking ack 
				end
	endcase
end
//---------------------------------------------------------------------------------		
RxPointeraddr: 
	// Pointer Address 000000-00(P1P0) for temperature register
begin
		case(I2C_counter)
						//---------------------sda = 0
			0: begin	 sda_int		=1'b0;
				I2C_counter=I2C_counter+1;end
						//---------------------sda = 0
			1:	begin sda_int		=1'b0;
				I2C_counter=I2C_counter+1;end
						//---------------------sda = 0
			2:	begin  sda_int		=1'b0;
				I2C_counter=I2C_counter+1; end
						//---------------------sda = 0
			3:	begin  sda_int		=1'b0;
				I2C_counter=I2C_counter+1; end
						//---------------------sda = 0
			4: begin	 sda_int		=1'b0;
				I2C_counter=I2C_counter+1;end
						//---------------------sda = 0
			5:	begin  sda_int		=1'b0;
				I2C_counter=I2C_counter+1;end
						//---------------------sda = 0
			6:	begin  sda_int		=1'b0;
				I2C_counter=I2C_counter+1;end
						//---------------------sda = 0
			7:	begin   sda_int		=1'b0;  
				ack_count=2'b01;  
				I2C_counter=I2C_counter+1;end
			8:	begin	if(sda==1'b0) 
				ack[1]=1'b0; state=Rxstart1;end // after pointer register sda line acknoledged by a low	pulse	
			endcase
end 
//-----------------------------------start+ slave address byte---------------------
Rxstart1:
begin
 		
		case(slaveaddrs)
		// initial frame 1001000 Initializing slave address including start  (case 0:)
			0: begin 			sda_int=1'b0; 
				slaveaddrs=slaveaddrs+1; end
			1:	begin  sda_int		=1'b1;//---------------------sda 1
				slaveaddrs=slaveaddrs+1; end
				
			2:	begin  sda_int		=1'b0;//---------------------sda 0
				slaveaddrs=slaveaddrs+1; end
				
			3:	begin  sda_int		=1'b0;//---------------------sda 0
				slaveaddrs=slaveaddrs+1; end
				
			4:	begin  sda_int		=1'b1;//---------------------sda 1
				slaveaddrs=slaveaddrs+1; end
				
			5: begin	 sda_int		=1'b0;//---------------------sda 0
				slaveaddrs=slaveaddrs+1; end
			
			6: begin	 sda_int		=1'b0;//---------------------sda 0
				slaveaddrs=slaveaddrs+1; end
				
			7: begin  sda_int		=1'b0;//---------------------sda=0 	
				slaveaddrs=slaveaddrs+1; end
				
			8:	begin  sda_int		=1'b1;
				slaveaddrs=slaveaddrs+1;   // R/W  bit  high
				ack_count=2'b10;      end
			9: begin if(sda==1'b0)
				ack[2]=1;
				state=Rxdata;			// Checking ack 
				end
	endcase
end


//----------------------------------Receiving Temperature Data --------------------------
Rxdata:
begin
	case(Rxcount)
		0: begin  outreg[15]=sda;
			Rxcount=Rxcount+1;end
		1: begin  outreg[14]=sda;
			Rxcount=Rxcount+1;end
		2: begin  outreg[13]=sda;
			Rxcount=Rxcount+1;end
		3: begin  outreg[12]=sda;
			Rxcount=Rxcount+1;end
		4: begin  outreg[11]=sda;
			Rxcount=Rxcount+1;end
		5: begin  outreg[10]=sda;
			Rxcount=Rxcount+1;end
		6: begin  outreg[9]=sda;
			Rxcount=Rxcount+1;end
		7: begin  outreg[8]=sda;
			Rxcount=Rxcount+1;
			ack_count=2'b11;   end
									// low pulse acknoledgment from TMP100
		8: begin  outreg[7]=sda; 
			if(!sda) ack[2]=1;
			Rxcount=Rxcount+1;end
			
		9: begin outreg[6]=sda ;
			Rxcount=Rxcount+1;end
		10: begin outreg[5]=sda ;
			Rxcount=Rxcount+1;end
		11: begin  outreg[4]=sda;
			Rxcount=Rxcount+1;end
		12: begin  outreg[3]=sda;
			Rxcount=Rxcount+1;end
		13: begin outreg[2]=sda;
			Rxcount=Rxcount+1;end
		14: begin  outreg[1]=sda;
			Rxcount=Rxcount+1;end
			   
		15: begin sda_int=1'b0; 
		 // checking low pulse acknoledge frm TMP 100
		state=Rxstop; end 
		endcase
end
//-----------------------------------------------------------------------------------------
Rxstop:
begin  chk=1; sda_int=1'b1;  end  


endcase
end
endmodule 

 

Joe
Capture.PNG
0 Kudos
eteam00
Instructor
Instructor
14,842 Views
Registered: ‎07-21-2009

I have attached the timing digram below, which shows the problem that I asked before. i.e my scl and sda transitions occures at the same time.   How can I add the setup time(100ns).

 

You have a 50MHz clock at your disposal.  This should allow you to set timing with 20nS (or even 10nS) granularity.

 

I was doing the slave address assignments , pointer addressins with a always @(posedge scl).

 

Why use SCL as a clock, when you can use the 50MHz clock (which generates SCL) as a clock?

 

You have multiple problems in plain view.

 

From the I2C specification, here is an excerpt:

 

3.1.3 Data validity
The data on the SDA line must be stable during the HIGH period of the clock. The HIGH or LOW state of the data line can only change when the clock signal on the SCL line is LOW (see Figure 4). One clock pulse is generated for each data bit transferred.

 

If you are going to use SCL as a clock to generate SDA output for data transfer (rather than START or STOP), then your use of the positive edge of SCL to generate SDA is a clear violation of the I2C specification, and represents a fundamental misunderstanding of the signal sequencing requirements.

 

Keep in mind that START and STOP requires SDA to change state when SCL is high, and data transfer requires SDA to change state when SCL is low.  Combined, these requirements prevent you from using SCL as a clock for generating SDA.

 

 

Please re-read some of the previous posts in this thread.  Your SDA implementation is not compliant with I2C electrical requirements.  You need to understand "open-drain" (or "open-collector") signaling.  Avrum's post in this thread emphasises quite clearly this same point.  Gabor includes a Verilog example of inferring open-drain signaling in his post in this thread. 

 

 

Finally, your code will not synthesise in ISE.  One of the rules is that any single register can be defined (assigned a value) in only one process.  SDA_IN is the "output" of more than one process, for example.  You should be getting "multiple drivers" error messages from ISE.

 

 

From the New Users Forum README thread:

Common Interfaces and FPGA techniques:

I2C basics link#1 link#2 code examples    I2C spec Rev 4  wiki articles: I2C  SMBus  MDIO  SPD  EDID

 

So, you have multiple problems to overcome.  You should work with your instructor to learn the additional lessons in Verilog, hardware design, logic design, and state machine design you need to complete this project.  And you need to read and understand the I2C specification.

 

An I2C controller is an excellent project for learning these basic lessons.  Suggest you work on a single target device (e.g. TMP100 sensor) to keep the problem simple, and then add support for additional devices when the basic logic is verified to be working.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
fradaric
Observer
Observer
14,796 Views
Registered: ‎05-29-2012

Hii.. I got a new problem, while synthesising it shows an errer like

 

 

ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <chk1> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <I2C_counter> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <initialframe> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <Rxcount> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <slaveaddrs> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <sda_init> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <S_machine> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[15]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[14]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[13]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[12]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[11]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[10]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[9]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[8]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[7]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[6]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[5]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[4]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[3]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[2]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[1]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.
ERROR:Xst:899 - "i2Ccore.v" line 146: The logic for <outreg[0]> does not match a known FF or Latch template. The description style you are using to describe a register or latch is not supported in the current software release.

 

How can I solve this ...here is my I2C code

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    09:57:41 08/28/2012 
// Design Name: 
// Module Name:    i2Ccore 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module i2Ccore(
    inout sda,
    output scl,
    input reset,
    input clk,
    output [15:0] outputt
    );
	 
//----------------------------------------------------------------------------
parameter clock_div=500; //  I2C clock 50MHz/(500)=100KHz
parameter clock_div1=250;
//-----------------------------------------------------------------------------
reg I2Cclk				=1'b1;  // I2C clock 
reg [8:0] clkclk		=clock_div; // in order to divide 50MHz clock 
reg sda_init				=1'b1; // making SDA high in initial state
reg [15:0] outreg		=0;
reg [7:0] countdly	=0;
reg  dly					=0;
reg [7:0] clkclk1=250;
reg I2Cclk1				=1'b1; 	
reg chk					=0;
reg chk1					=0;
reg scl1					=1;
reg str					=0;
wire sda_int_start=1;

//-----------------------------------------------------------------------------
reg [3:0] I2C_counter=0;  // for giving the pointer address (000000-00(P1P0))
reg [3:0] initialframe	=0; // initializing via giving slave address(1001000-0(R/W))
reg [4:0] Rxcount		=0; // counter for data 
reg [3:0] slaveaddrs	=0; // TMP 100 10010001

//---------------------------I2C State Machine Variables----------------------

parameter Rxreset			=0;
parameter RxPointeraddr	=1;
parameter RxConfig		=2;
parameter Rxstart1		=3;
parameter Rxdata			=4;
parameter Rxstop			=5;


//----------------------------------------------------------------------------

reg [2:0] S_machine 		=0; // For State machine starting
assign scl					=I2Cclk;  // Generated Clock for I2C
assign  outputt		   =outreg;  // output from TMP 100
assign sda					=sda_init; // Using SDA pin as inout

//----------------------------------------------------------------------------	
	




//----------------------------------------------------------------------------
always @(posedge clk)
begin	
if(!str)	 
	begin
	dly=0;
	countdly=countdly+1; 
	if(countdly==250)
		begin
			dly=1;
		end
	end
end


//----------------------------------------------------------------------------
always @(posedge clk)	
begin	
	if(chk) 
		begin
			scl1=~I2Cclk  & I2Cclk1;
		end
	else if(!chk) 
		begin
			scl1=I2Cclk1;
		end
end
//------------------------------------------------------------------------------
always @(posedge clk)
begin
	clkclk1 = clkclk1 - 1;
	if (!clkclk1) 
		begin
			I2Cclk1=~I2Cclk1;
			clkclk1 = clock_div1;
      end
end
//-------------------------------------------------------------------------------
always @(posedge clk)
begin
if(chk)
	begin
	clkclk		=clkclk - 1; 
		if(clkclk==0)
			begin
				I2Cclk		=~I2Cclk;
				clkclk		=clock_div;
			end
	end 
 else if(chk1==1)  I2Cclk	=1'b1; 
end
//------------------------------------------------------------------------------
always @(posedge clk)	
begin
if(dly)
	begin
		//sda_int    =1'b0;
		chk         =1;
		str			=1;
	end
end



//-----------------------------------------------------------------------------
	

always @(posedge scl1 or posedge chk)
begin
	
case (S_machine)
Rxreset:
//if(scl1)
			begin
			if(reset) 
				begin
					chk1				=0;
					I2C_counter		=0;  
					initialframe	=0;
					Rxcount			=0;
					slaveaddrs		=0; 
				end	
		if(dly) begin
				sda_init   				=1'b0; 
				S_machine				=RxPointeraddr;	
				  end	
		end		
RxPointeraddr:
	begin
	case(initialframe)
						// initial frame 1001000 Initializing slave address
						
					0: begin 	sda_init				=1'b1;//---------------------sda 1
						initialframe=1; end
				   1: begin  sda_init		=1'b0;//---------------------sda 0
						initialframe=2; end
					2:	begin  sda_init		=1'b0;//---------------------sda 0
						initialframe=3; end
					3:	begin  sda_init		=1'b1;
						sda_init		=1'b1;
						sda_init		=1'b1;//---------------------sda 1
						initialframe=4; end		
					4: begin	 sda_init		=1'b0;//---------------------sda 0
						initialframe=5; end				
					5: begin	 sda_init		=1'b0;//---------------------sda 0
						initialframe=6; end		
					6: begin sda_init		=1'b0;//---------------------sda=0 	
						initialframe=7; end			
					7:	begin sda_init		=1'b0;// R/W  bit
						initialframe=8; end											
					8: begin if(sda==1'b0)
						S_machine=RxConfig;   end// Checking ack 										
		endcase
end
RxConfig: 
		// Pointer Address 000000-00(P1P0) for temperature register
		begin
		
				case(I2C_counter)
								//---------------------sda = 0
					0: begin	 sda_init		=1'b0;
						I2C_counter=I2C_counter+1;end
								//---------------------sda = 0
					1:	begin sda_init		=1'b0;
						I2C_counter=I2C_counter+1;end
								//---------------------sda = 0
					2:	begin  sda_init		=1'b0;
						I2C_counter=I2C_counter+1; end
								//---------------------sda = 0
					3:	begin  sda_init		=1'b0;
						I2C_counter=I2C_counter+1; end
								//---------------------sda = 0
					4: begin	 sda_init		=1'b0;
						I2C_counter=I2C_counter+1;end
								//---------------------sda = 0
					5:	begin  sda_init		=1'b0;
						I2C_counter=I2C_counter+1;end
								//---------------------sda = 0
					6:	begin  sda_init		=1'b0;
						I2C_counter=I2C_counter+1;end
								//---------------------sda = 0
					7:	begin   sda_init		=1'b0;  
						//ack_count=2;  
						I2C_counter=I2C_counter+1;end
					8:	begin	if(sda==1'b0) 
						S_machine=Rxstart1;           end // after pointer register sda line acknoledged by a low	pulse	
					endcase
			end
Rxstart1:
		begin
		case(slaveaddrs)
				// initial frame 1001000 Initializing slave address including start  (case 0:)
					0: begin 			sda_init=1'b0; 
						slaveaddrs=slaveaddrs+1; end
					1:	begin  sda_init		=1'b1;//---------------------sda 1
						slaveaddrs=slaveaddrs+1; end
						
					2:	begin  sda_init		=1'b0;//---------------------sda 0
						slaveaddrs=slaveaddrs+1; end
						
					3:	begin  sda_init		=1'b0;//---------------------sda 0
						slaveaddrs=slaveaddrs+1; end
						
					4:	begin  sda_init		=1'b1;//---------------------sda 1
						slaveaddrs=slaveaddrs+1; end
						
					5: begin	 sda_init		=1'b0;//---------------------sda 0
						slaveaddrs=slaveaddrs+1; end
					
					6: begin	 sda_init		=1'b0;//---------------------sda 0
						slaveaddrs=slaveaddrs+1; end
						
					7: begin  sda_init		=1'b0;//---------------------sda=0 	
						slaveaddrs=slaveaddrs+1; end
						
					8:	begin  sda_init		=1'b1;
						slaveaddrs=slaveaddrs+1; end // R/W  bit  high
							
					9: begin if(sda==1'b0)
						S_machine=Rxdata;				 end	// Checking ack 
				endcase
		end
Rxdata:
begin

		
			case(Rxcount)
				0: begin  outreg[15]=sda;
					Rxcount=Rxcount+1;end
				1: begin  outreg[14]=sda;
					Rxcount=Rxcount+1;end
				2: begin  outreg[13]=sda;
					Rxcount=Rxcount+1;end
				3: begin  outreg[12]=sda;
					Rxcount=Rxcount+1;end
				4: begin  outreg[11]=sda;
					Rxcount=Rxcount+1;end
				5: begin  outreg[10]=sda;
					Rxcount=Rxcount+1;end
				6: begin  outreg[9]=sda;
					Rxcount=Rxcount+1;end
				7: begin  outreg[8]=sda;
					Rxcount=Rxcount+1;end 							
				// low pulse acknoledgment from TMP100
				8: begin  outreg[7]=sda; 
					if(sda==1'b0) 
					Rxcount=Rxcount+1;end
				9: begin outreg[6]=sda ;
					Rxcount=Rxcount+1;end
				10: begin outreg[5]=sda ;
					Rxcount=Rxcount+1;end
				11: begin  outreg[4]=sda;
					Rxcount=Rxcount+1;end
				12: begin  outreg[3]=sda;
					Rxcount=Rxcount+1;end
				13: begin outreg[2]=sda;
					Rxcount=Rxcount+1;end
				14: begin  outreg[1]=sda;
					Rxcount=Rxcount+1;end
				15: begin outreg[0]=sda;
					Rxcount=Rxcount+1;end
				16: begin if(sda==1'b0)
					S_machine=Rxstop; 		end 
				 // checking low pulse acknoledge frm TMP 100
			endcase 
		
		end	
Rxstop:
		begin    chk1=1; 
		   sda_init=1'b1; 
			S_machine = Rxreset; 
		end  	
	
endcase
end	

endmodule

 

Joe
0 Kudos
fradaric
Observer
Observer
14,794 Views
Registered: ‎05-29-2012

Here is the wave form i've obtained...with the above code

Joe
Capture.PNG
0 Kudos
eteam00
Instructor
Instructor
14,787 Views
Registered: ‎07-21-2009

I got a new problem

 

Yes, you do have a new problem!

What was going through your mind when you wrote the following line of code?

 

always @(posedge scl1 or posedge chk)

 

This is a common newbie error by students who know very little about real FPGA hardware.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
fradaric
Observer
Observer
6,486 Views
Registered: ‎05-29-2012

Thanks for the reply,

 

I need to provide the start sgnal as per the protocol, the reg chk will change only once in my code ( becomes high after startup which will  provide  a delay for changing sda to low I guess  ) that is why I put like that. What  can I do now.

 

I dunno where to start what to do , there is no instructer for me to work on FPGA. If you don't mind provid me few resourses. I would be grateful to you if you could help me.

 

Fradaric.

 

Joe
0 Kudos
eteam00
Instructor
Instructor
6,482 Views
Registered: ‎07-21-2009

always @(posedge scl1 or posedge chk)

 

Another problem:

 

  • The unbuffered output of a LUT or a register is not suitable for use as a clock.  Normal logic interconnect has too much skew for clocking purposes.  You must use a clock buffer to distribute a low-skew clock.

But this does not suggest that the use of sc11 and chk signals as a clock is a good idea -- it is not a good idea.  You should be clocking everything with a single clock.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
eteam00
Instructor
Instructor
6,479 Views
Registered: ‎07-21-2009

I need to provide the start sgnal as per the protocol, the reg chk will change only once in my code ( becomes high after startup which will  provide  a delay for changing sda to low I guess  ) that is why I put like that. What  can I do now.

 

One of the lessons you should learn is called synchronous single-clock logic design.  This means you use a single clock (and a single edge of this clock) to clock everything.  Your job, as designer, is to use this one clock to provide all the controls and generate all the outputs you need, in the proper sequence.

 

Accept this as a challenge:  Re-design your controller logic to use the one 50MHz clock at your disposal.

 

Returning to your original problem, you need to understand that individual FPGA registers are not capable of using multiple clocks.  Only one clock signal -- and one clock edge -- can be used to clock any single FPGA register.  The synthesiser complained because you described a hardware circuit which does not exist: registers with two clocks (scl1 and chk, in this case).

 

I dunno where to start what to do , there is no instructer for me to work on FPGA. If you don't mind provid me few resourses. I would be grateful to you if you could help me.

 

How does the prospect of 30 or 50 different forum folks giving you advice at the same time, all with different styles and ideas?  How do you like the idea of having 30 or 50 wives, and they are all giving you (different) advice on what to eat for breakfast and which colour shirt to wear?

 

  • Take some courses.
  • Get a job near folks who can teach or guide you.

Learning how to design logic hardware on a user forum works about as well as learning how to drive an auto on a user forum.  It is little fun, it is frustrating, and it takes forever.  If you don't value your time (or ours), the cost is pretty cheap.

 

Your friends and family are probably relieved that you aren't trying to learn medicine or dentistry on an online user forum, just hardware logic design.

 

I shouldn't be discouraging you, I should be encouraging you.  For this, I apologise.  If you are clever, persistent, and eager to learn, you will succeed.  You won't get a 5000 word lecture essay in response to every one of your posts.   But if you ask specific questions, you should not lack for brief but useful answers.

 

Have you read the New Users Forum README thread?  There are some links to tutorial sites and beginners projects which might be helpful or interesting...

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
inflector
Observer
Observer
2,975 Views
Registered: ‎08-29-2017

In case anyone finds this thread five years later...

I found the four tutorials on i2c with Vivado by Tom Briggs to be quiet excellent. https://www.youtube.com/watch?v=skkyudHHSWY&t=978s

He does not discuss how to do the pulldowns but he covers clocks quite nicely and shows how to make a clock-divider module that outputs a 100khz output for i2c from another starting system synchronous clock like the 100Mhz default for the Artix Arty I'm using for my learning. He also shows how to use dual-clock Xilinx IP for buffered writes to i2c which is useful for many other things when crossing clock domains.

For testing the pulldown acknowledge, I implemented an i2c test slave as per the suggestions by @gszakacshere above by that I instantiate and connect to sda and scl which pulls down sda for the ack:

`timescale 1ns / 1ps

 
module i2c_test_slave(
    input wire reset,
    input wire scl,
    inout wire sda
    );

 

localparam STATE_WAIT_START = 0;
localparam STATE_ADDRESS = 1;
localparam STATE_RW_BIT = 2;
localparam STATE_WAIT_ACK = 3;
localparam STATE_DATA = 4;
localparam STATE_WAIT_ACK_2 = 5;
localparam STATE_STOP = 6;

 
localparam HIGH = 1;
localparam LOW = 0;
localparam TRUE = 1;
localparam FALSE = 0;

 
localparam READ = LOW;
localparam WRITE = HIGH;

 
reg[4:0]    state;
reg[3:0]    bit_count;
reg[6:0]    address;
reg         read_write_bit;
reg[7:0]    data;

 
reg write_ack = FALSE;

 
assign sda  = write_ack ? LOW : 1'bz;

 
always @(negedge sda) begin
    if (reset == HIGH) begin
        state <= STATE_WAIT_START;
        bit_count <= 0;
    end else begin
        if (state == STATE_WAIT_START) begin
            state <= STATE_ADDRESS;
            bit_count <= 6;
            address = 7'bx;
        end
    end
end

 
always @(posedge sda) begin
   if (reset == HIGH) begin
       state <= STATE_WAIT_START;
       bit_count <= 0;
   end else begin
       if (state == STATE_STOP && scl == HIGH)
           state <= STATE_WAIT_START;
   end
end

 
always @(posedge scl) begin
    if (reset == HIGH) begin
        state <= STATE_WAIT_START;
        bit_count <= 0;

 
    end else begin
        case (state)
            STATE_WAIT_START: ;
                // Set in negedge sda above
    
            STATE_ADDRESS: begin
                address[bit_count] <= sda;
                if (bit_count == 0) 
                    state <= STATE_RW_BIT;
                bit_count <= bit_count - 1;
            end
    
            STATE_RW_BIT: begin
                read_write_bit <= sda;
                state <= STATE_WAIT_ACK;
                write_ack <= TRUE;
            end
    
            STATE_WAIT_ACK: begin
                write_ack <= FALSE;
                state <= STATE_DATA;
                bit_count <= 7;
                data = 8'bx;
            end
    
            STATE_DATA: begin
                data[bit_count] <= sda;
                if (bit_count == 0) begin
                    state <= STATE_WAIT_ACK_2;
                    write_ack <= TRUE;
                end
                bit_count <= bit_count - 1;
            end
    
            STATE_WAIT_ACK_2: begin
                write_ack <= FALSE;
                state <= STATE_STOP;
            end
    
            STATE_STOP: begin
            // state <= STATE_IDLE;
            // this is set above checking posedge sda
            end
    
        endcase
    end // not reset
end // on rising clock

endmodule

 

0 Kudos