Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] [moved] Can't get data from I2C slave register with FPGA

Status
Not open for further replies.

tumkayaonur

Junior Member level 2
Joined
Nov 24, 2015
Messages
22
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
186
I wrote a verilog code for I2C and tested it. It works properly in simulation results but i can't get any data from slave device's register.

Can anyone help me ?


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
module i2cio2(
        input wire clk,
        input wire reset,
        output reg sda,
        output wire scl,
        output reg [7:0] data,
        output reg [7:0] state
        
    );
    localparam STATE_IDLE   =0;
    localparam STATE_START  =1;
    localparam STATE_ADDR   =2;
    localparam STATE_RW     =3;
    localparam STATE_WACK   =4;
    localparam STATE_DATA   =5;
    localparam STATE_WACK2  =6;
    localparam STATE_STOP   =7;
     
     
    reg [6:0] addr;
    reg [7:0] count;
    reg ack1;
    reg ack2;
    
    reg scl_enable;
    reg rw;
    initial scl_enable<=0;
    
 
    i2c_clk_divider instance_name (
    .clk(clk), 
    .reset(reset), 
    .i2c_clk(i2c_clk)
    );
    
    
    
    assign scl=(scl_enable==0) ? 1:~i2c_clk;
    
 
 
 
    
    
    
    
    always @ (posedge i2c_clk)begin
        if(reset==1)begin
        scl_enable<=0;
        sda<=1;
        state<=STATE_IDLE;
        addr<=7'h0x96;
        rw<=1;
        count<=8'd0;
        data<=8'b01010101;
        ack1<=0;
        ack2<=0;
        end
        else begin
            case(state)
            
                STATE_IDLE: 
                    begin   //IDDLE
                        sda<=1;
                        state<=STATE_START;
                        scl_enable<=0;
                    end         
                    
                STATE_START:
                    begin       //START
                        sda<=0;
                        state<=STATE_ADDR;
                        scl_enable<=0;
                        count<=6;
                    end
                    
                STATE_ADDR: 
                    begin       //MSB ADDRESS BIT
                        sda<=addr[count];
                        scl_enable<=1;
                        if(count==0) state<=STATE_RW;
                        else count<=count-1;
                    end
                    
                STATE_RW:
                    begin       //BIT 5
                        sda<=1;
                        count<=7;
                        state<=STATE_WACK;
                        scl_enable<=1;
                    end
                
                STATE_WACK:
                    begin
                            //BIT 4
                        sda<=0;
                        state<=STATE_DATA;
                        scl_enable<=1;
                    end
            
                STATE_DATA:
                    begin
                        scl_enable<=1;
                        sda<=data[count];
                        if(count==0) state<=STATE_WACK2;
                        else count<=count-1;
                    end
                
                STATE_WACK2:
                    begin
                        sda<=0;
                        scl_enable<=1;
                        state<=STATE_STOP;
                        
                    end
                    
                STATE_STOP:
                    begin
                        sda<=1;
                        scl_enable<=0;
                        state<=STATE_IDLE;
                    end
            endcase
        end//end else
    
    end // end always
    
 
 
 
 
endmodule

 

Hi,

maybe there is no slave device connected.

If connected, what device?

Or is the FPGA the I2C slave?

Klaus
 

There's a light sensor connected to FPGA.

FPGA is the master and Sensor is slave.

Probably, SDA line is not working bidirectionally. I can't communicate with slave.
 

Hi,

check with a scope. Dual channel, SDA and SCL.

Klaus
 

There's a light sensor connected to FPGA.

FPGA is the master and Sensor is slave.

Probably, SDA line is not working bidirectionally. I can't communicate with slave.

Code:
output reg sda,

Probably? most definitely it's not bi-directional, you can only write to a slave given the code you've written.
 

Hi,

check with a scope. Dual channel, SDA and SCL.

Klaus


I checked with scope. There isn't any problem at sending data.

I measured voltage and current values of slave. Its operation conditions are suitable.
 

Code:
output reg sda,

Probably? most definitely it's not bi-directional, you can only write to a slave given the code you've written.

I changed sda and scl to inout. Still can't access register and get data.

Is there anything can you suggest ?
 

Hi,

Both SCL and SDA need to be open collector style, and both need a pullup resistor.

Open collector style: only two valid states, either "output low" or "high impedance" = input.
No other state. Never drive it high.

Can you show us the scope pictures.
Or verify ACK state. And what is happening on the bus in times when you expect to receive data? Is SDA high or low?

Klaus
 

Excuse me, I am new at FPGA and I2C.

Here's the output of scope.
top=SDA
bottom=SCL


DSC_0146.jpg
I have two main problems.

First, How can I read ACK from slave ? I wanna made SDA bidirectionally. But I can't estimate how can I get it. Because SDA is bidirectionally, I must send data and read data. How can I read data and send data at the same time ?

Second, For communicatiıon with IC Sensor may require sending control byte before the addres byte.


Declaring pull up resistor like sda<='H' ?

Here is the datasheet of sensor: **broken link removed**
 

Here's the output of scope.
top=SDA
bottom=SCL
Unlikely, looks like 2x SDA probed differently. No signal looks like a valid I2C clock. Levels seem incorrect. What's I2C voltage level, 3.3 or 5 volt?

Declaring pull up resistor like sda<='H' ?
No, needs real pull-up resistors.

- - - Updated - - -

First, How can I read ACK from slave ? I wanna made SDA bidirectionally. But I can't estimate how can I get it. Because SDA is bidirectionally, I must send data and read data. How can I read data and send data at the same time ?
That's a very general I2C question, not specific to this sensor. I suggest to read a basic I2C specification or tutorial, e.g. the I2C specification from NXP.

Second, For communicatiıon with IC Sensor may require sending control byte before the addres byte.
Unfortunately. Taos/AMS didn't manage to give an example of the complete I2C communication sequence. We can just guess that the addressing is similar to accessing I2C EEPROMS

Start
Send I2C Device-Address (Write)
Send Register Adress
Send optional write data (one or more bytes)

Repeated Start
Send I2C Device-Address (Read)
Receive one or more data bytes (all but the last with ACK bit active)
Stop

Hopefully AMS has example code or an application note.

- - - Updated - - -

I notice that your code in post #1 doesn't send the I2C device address.
 
That's the latest scope output
**broken link removed**

Sensor's I2C Voltage = 3.3 V
SDA=1.78 V
SCL=1.92 V(when doesn't connect IC), 0.4V (when connect IC)
 

SDA looks like correct 3.3V level, 1.78 is apparently a meaningless average value. 5V oscilloscope scaling of SCL seems wrong, looks like actual 2V. Do you operate the I2C lines (at least SDA) with pull-up resistor and open drain driver?
 

Hi,

the level of CH1 = SDA seems to be 3V3.
the level of CH2 = SCL seem to be 7V, this makes no sense. Check on this.

after the first byter ACK is not asserted
after the second byte ACK is asserted

I wonder about the fast low-to-high transition with both signals. Your scope picture shows about 100kHz SCL frequency..and with the scope setup of 50us/div i expect to see a faster fall rate than a rise rate caused by the pullup. It seems you drive both SCL and SDA activley high. Don´t do this, only LOW or HIGH-Z.

Some devices need a time gap before they can be accessed again. Check device datasheet on this.

Klaus
 

I don't operate the I2C line with pull-up resistor and open drain. I get I2C signals directly from FPGA to sensor.

Uptaded scope picture:
**broken link removed**

My major problem is that I can't giving address bits to sensor. Address ACK=1.
I want to send 0x98 address bits but it seems 0010110 on scope then it gets data ACK=1 and data ACK = 0.

How can I pass this trouble ?
Is driving SCL and SDA LOW or HIGH-Z required ?

Code:
module i2cio2(
		input wire clk,
		input wire reset,
		inout wire sda,
		output wire scl,
		output reg [7:0] data,
		output reg [7:0] state,
		output wire i2c_clk
		
    );
	localparam STATE_IDLE	=0;
	localparam STATE_START	=1;
	localparam STATE_ADDR	=2;
	localparam STATE_RW		=3;
	localparam STATE_WACK	=4;
	localparam STATE_DATA	=5;
	localparam STATE_WACK2	=6;
	localparam STATE_STOP	=7;
	 
	 
	reg [6:0] addr;
	reg [7:0] count;
	reg ack1;
	reg ack2;
	reg sda_reg;
	
	reg scl_enable;
	reg rw;
	initial scl_enable<=0;
	

	i2c_clk_divider instance_name (
    .clk(clk), 
    .reset(reset), 
    .i2c_clk(i2c_clk)
    );
	
	
	
	assign scl=(scl_enable==0) ? 1:~i2c_clk;
	assign sda=sda_reg;
	



	
	
	
	
	always @ (posedge i2c_clk)begin
		if(reset==1)begin
		scl_enable<=0;
		sda_reg<=1;
		state<=STATE_IDLE;
		addr<=7'h0x96;
		rw<=1;
		count<=8'd0;
		data<="00000000";
		ack1<=0;
		ack2<=0;
		end
		else begin
			case(state)
			
				STATE_IDLE:	
					begin 	//IDDLE
						sda_reg<=1;
						state<=STATE_START;
						scl_enable<=0;
					end 		
					
				STATE_START:
					begin		//START
						sda_reg<=0;
						state<=STATE_ADDR;
						scl_enable<=0;
						count<=6;
					end
					
				STATE_ADDR:	
					begin		//MSB ADDRESS BIT
						sda_reg<=addr[count];
						scl_enable<=1;
						if(count==0) state<=STATE_RW;
						else count<=count-1;
					end
					
				STATE_RW:
					begin		//BIT 5
						sda_reg<=rw;
						count<=7;
						state<=STATE_WACK;
						scl_enable<=1;
					end
				
				STATE_WACK:
					begin
							
						if(sda_reg==0)begin
							state<=STATE_DATA;
						end else begin
							state<=STATE_START;
						end
						scl_enable<=1;	
					end
			
				STATE_DATA:
					begin
						scl_enable<=1;
						sda_reg<=data[count];
						if(count==0) state<=STATE_WACK2;
						else count<=count-1;
					end
				
				STATE_WACK2:
					begin
						sda_reg<=0;
						scl_enable<=1;
						state<=STATE_STOP;
						
					end
					
				STATE_STOP:
					begin
						sda_reg<=1;
						scl_enable<=0;
						state<=STATE_IDLE;
					end
			endcase
		end//end else
	
	end	// end always
	




endmodule
 

I don't operate the I2C line with pull-up resistor and open drain. I get I2C signals directly from FPGA to sensor.
Yes I see, this gives you nice waveforms but no chance to receive a response from the slave. There's even a risk of damaging the I2C slave or the FPGA output if the FPGA is driving 1 and the slave 0.

You absolutely need a real pull-up resistor and the FPGA SDA line operated as open drain. This can be described in Verilog by assigning either 0 or z to the pin. Presumed the slave doesn't perform clock stretching, it's O.K. to operate SCL as regular push-pull output with no resistor.
 

Why I need use pull up resistor ? Input voltage of sensor is enough to communicate.

Is that necessary to get data in address ? I must point address, and I made it wrongly.

For instance in SDA line, I send address value to sensor as 0x98 but in scope outgoing address vallue seems different from address value I expect.
What's wrong in state ADDR and State DATA ?
 

I want to send 0x98 address bits but it seems 0010110
The actual code is this
Code:
addr<=7'h0x96;
0x96 (or 0x98, whatsoever) isn't the 7-Bit I2C device address, it's a 8-Bit register address. 0x96 doesn't fit into a 7-Bit value, 7'h0x96 comes out as 7'h0x16.

The I2C device address is 0x29 or 0x39, see datasheet page 29.

Why I need use pull up resistor ? Input voltage of sensor is enough to communicate.
I feel a bit helpless facing your denial of accepting the I2C basics. That's the bus topology according to the NXP specification:

i2c.png
 
I've an evaluation kit and I'm implementing code on this:
evkit.png
Evaluation kit has already pull up resistor. I checked connections between FPGA and evalkit.
I'd revised verilog code and written I2C address into code. But there is no change in data, still can not get any value.
I tried to send register address both 7bit and 8bit.
Code:
module i2cio3(
		input wire clk,
		input wire reset,
		inout wire sda,
		output wire scl,
		output reg [7:0] data,
		output reg [7:0] state,
		output wire i2c_clk
		
    );
	localparam STATE_IDLE	=0;	//	0000
	localparam STATE_START	=1;	//	0001
	localparam STATE_ADCALL	=2;	//	0010
	localparam STATE_RW1		=3;	//	0011
	localparam STATE_ACK1	=4;	//	0100
	localparam STATE_ADDR   =5;	//	0101
	localparam STATE_RW2 	=6;	//	0110
	localparam STATE_ACK2	=7;	//	0111
	localparam STATE_DATA	=8;	//	1000
	localparam STATE_ACK3	=9;	//	1001
	localparam STATE_STOP	=10;	//	1010
	
	 
	 
	reg [6:0] addr;
	reg [6:0] adcall;
	reg [7:0] count1;
	reg [7:0] count2;
	reg [7:0] count3;
	reg ack1;
	reg ack2;
	reg ack3;
	reg sda_reg;
	
	reg scl_enable;
	reg rw1;
	reg rw2;
	initial scl_enable<=0;
	

	i2c_clk_divider instance_name (
    .clk(clk), 
    .reset(reset), 
    .i2c_clk(i2c_clk)
    );
	
	
	
	assign scl=(scl_enable==0) ? 1:~i2c_clk;
	assign sda=sda_reg;
	



	
	
	
	
	always @ (posedge i2c_clk)begin
		if(reset==1)begin
		scl_enable<=0;
		sda_reg<=1;
		state<=STATE_IDLE;
		adcall<=7'h0x29;
		addr<=7'h0x96;
		rw1<=0;
		rw2<=1;
		data<=8'b10101010;
		end
		else begin
			case(state)
			
				STATE_IDLE:	
					begin 	//IDDLE
						sda_reg<=1;
						state<=STATE_START;
						scl_enable<=0;
					end 		
					
				STATE_START:
					begin		//START
						sda_reg<=0;
						state<=STATE_ADCALL;
						scl_enable<=0;
						count1<=6;
						count2<=6;
						count3<=7;
					end
				
				STATE_ADCALL:
					begin
						sda_reg<=adcall[count1];
						scl_enable<=1;
						if(count1==0) state<=STATE_RW1;
						else count1<=count1-1;	
					end
				STATE_RW1:
					begin
						sda_reg<=rw1;
						state<=STATE_ACK1;
						scl_enable<=1;
						
					end
					
				STATE_ACK1:
					begin
						sda_reg<=1'bx;
						state<=STATE_ADDR;
						scl_enable<=1;
					end
					
				STATE_ADDR:	
					begin		//MSB ADDRESS BIT
						sda_reg<=addr[count2];
						scl_enable<=1;
						if(count2==0) state<=STATE_RW2;
						else count2<=count2-1;
					end
					
				STATE_RW2:
					begin		//BIT 5
						sda_reg<=rw2;
						state<=STATE_ACK2;
						scl_enable<=1;
					end
				
				STATE_ACK2:
					begin
							//BIT 4
						//if(sda_reg<=0)begin
							sda_reg<=1'bx;
							state<=STATE_DATA;
						//end else begin
							//state<=STATE_START;
						//end
						scl_enable<=1;	
					end
			
				STATE_DATA:
					begin
						scl_enable<=1;
						data[count3]<=sda_reg;
						if(count3==0) state<=STATE_ACK3;
						else count3<=count3-1;
					end
				
				STATE_ACK3:
					begin
						sda_reg<=1'bx;
						scl_enable<=1;
						state<=STATE_STOP;
						
					end
					
				STATE_STOP:
					begin
						sda_reg<=1;
						scl_enable<=0;
						state<=STATE_IDLE;
					end
			endcase
		end//end else
	
	end	// end always
	




endmodule

TestBench results:
testbench.png
 
Last edited:

There are still errors in your I2C transaction.
- an I2C byte frame should have 9 clock cycles. ACK is read during the 9th clock
- the address register value sent after the device address is a 8-Bit value. There should be a H state for the MSB of 0x96 after ACK.
- the overall sequence is wrong, see my post #10. You are trying to read data without sending a repeated start and the I2C read address.
 

I revised verilog code according to your post.
Code:
module i2cio3(
		input wire clk,
		input wire reset,
		inout wire sda,
		output wire scl,
		output reg [7:0] data,
		output reg [7:0] state,
		output wire i2c_clk
		
    );
	localparam STATE_IDLE				=0;	//	
	localparam STATE_START_WRITE		=1;	//	
	localparam STATE_I2C_ADD_CALL1	=2;	//	
	localparam STATE_RW1					=3;	//	
	localparam STATE_ACK1				=4;
	localparam STATE_REG_ADD1			=5;
	localparam STATE_ACK2				=6;	//
	localparam STATE_START_READ		=7;
	localparam STATE_I2C_ADD_CALL2	=8;	//	
	localparam STATE_RW2 				=9;	//	
	localparam STATE_ACK3				=10;	//	
	localparam STATE_DATA				=11;	//	
	localparam STATE_ACK4				=12;	//	
	localparam STATE_STOP				=13;	//
	localparam STATE_REG_ADD			=14;
	
	 
	 
	reg [7:0] addr;
	reg [6:0] adcall;
	reg [7:0] count;
	reg ack1;
	reg ack2;
	reg ack3;
	reg sda_reg;
	
	reg scl_enable;
	reg rw1;
	reg rw2;
	initial scl_enable<=0;
	

	i2c_clk_divider instance_name (
    .clk(clk), 
    .reset(reset), 
    .i2c_clk(i2c_clk)
    );
	
	
	
	assign scl=(scl_enable==0) ? 1:~i2c_clk;
	assign sda=sda_reg;
	



	
	
	
	
	always @ (posedge i2c_clk)begin
		if(reset==1)begin
		scl_enable<=0;
		sda_reg<=1;
		state<=STATE_IDLE;
		adcall<=8'b00101001;
		addr<=8'b10011000;//'h0x98;
		rw1<=0;
		rw2<=1;
		data<=8'b10101010;
		end
		else begin
			case(state)
			
				STATE_IDLE:	
					begin 	//IDDLE
						sda_reg<=1;
						state<=STATE_START_WRITE;
						scl_enable<=0;
					end 		
					
				STATE_START_WRITE:
					begin		//START
						sda_reg<=0;
						state<=STATE_I2C_ADD_CALL1;
						scl_enable <= 0;
						count<=6;
					end
				
				STATE_I2C_ADD_CALL1:
					begin
						sda_reg<=adcall[count];
						scl_enable<=1;
						if(count==0) state<=STATE_RW1;
						else count<=count-1;	
					end
				STATE_RW1:
					begin
						sda_reg<=rw1;
						state<=STATE_ACK1;
						scl_enable<=1;
						count<=7;
						
					end
					
				STATE_ACK1:
					begin
						sda_reg<=1'bz;
						state<=STATE_REG_ADD1;
						scl_enable<=1;
					end
					
				STATE_REG_ADD1:
					begin
						sda_reg<=addr[count];
						scl_enable<=1;
						if(count==0) state<=STATE_ACK2;
						else count<=count-1;
					end
							
				STATE_ACK2:
					begin
						sda_reg<=1'bz;
						state<=STATE_START_READ;
						scl_enable<=1;	
					end
					
				STATE_START_READ:
					begin
						sda_reg<=0;
						state<=STATE_I2C_ADD_CALL2;
						scl_enable<=0;
						count<=6;
					end
					
				STATE_I2C_ADD_CALL2:	
					begin		//MSB ADDRESS BIT
						sda_reg<=addr[count];
						scl_enable<=1;
						if(count==0) state<=STATE_RW2;
						else count<=count-1;
					end
					
				STATE_RW2:
					begin		//BIT 5
						sda_reg<=rw2;
						state<=STATE_ACK3;
						scl_enable<=1;
					end
				
				STATE_ACK3:
					begin
						sda_reg<=1'bz;
						state<=STATE_DATA;
						scl_enable<=1;
						count<=7;
					end
			
				STATE_DATA:
					begin
						sda_reg<=1'bz;
						scl_enable<=1;
						data[count]<=sda_reg;
						if(count==0) state<=STATE_ACK4;
						else count<=count-1;
					end
				
				STATE_ACK4:
					begin
						sda_reg<=1'bz;
						scl_enable<=1;
						state<=STATE_STOP;
					end
					
				STATE_STOP:
					begin
						sda_reg<=1;
						scl_enable<=0;
						state<=STATE_IDLE;
					end
			endcase
		end//end else
	
	end	// end always
	




endmodule

Now I must reduce voltage level from 3.3V to 1.8V because SDA and SCL voltage at FPGA is about 3.3V but I2C bus voltage 1.8V.

Thank you very much.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top