How to write a code for sending data through I2C

Status
Not open for further replies.

torius

Newbie level 4
Joined
Oct 20, 2006
Messages
7
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,367
Hello there,

I'm busy with 2 moter encoders. those encoders are connented to a fpga. the fpga need to count every pulse. so i created a 32 bit register to count. the 32 bit register is split in 4 times 8 bit. now i want to send those values to a microcontroller with I2C, i found an i2c slave on fpga4fun. My question is how to send the data through the sda. What is the best way i've tried some things, but my knowledge with verilog code is not so good.

i hope someone can help me

here's the code:

// Example of I2C slave
// www.fpga4fun.com

module I2CslaveWith8bitsIO(SDA, SCL, IOout);

inout SDA;
input SCL;

// The 7-bits address that we want for our I2C slave
parameter I2C_ADR = 7'h27;

// I2C start and stop conditions detection logic
// That's the "black magic" part of this design...
// We use two wires with a combinatorial loop to detect the start and stop conditions
// making sure these two wires don't get optimized away
wire SDA_shadow /* synthesis keep = 1 */;
wire start_or_stop /* synthesis keep = 1 */;
assign SDA_shadow = (~SCL | start_or_stop)? SDA : SDA_shadow;
assign start_or_stop = ~SCL? 1'b0 : (SDA ^ SDA_shadow);
reg incycle;

always @(negedge SCL or posedge start_or_stop)
if(start_or_stop)
incycle <= 1'b0;
else if(~SDA)
incycle <= 1'b1;


// Now we are ready to count the I2C bits coming in
reg [3:0] bitcnt; // counts the I2C bits from 7 downto 0, plus an ACK bit
wire bit_DATA = ~bitcnt[3]; // the DATA bits are the first 8 bits sent
wire bit_ACK = bitcnt[3]; // the ACK bit is the 9th bit sent
reg data_phase;

always @(negedge SCL or negedge incycle)
if(~incycle)
begin
bitcnt <= 4'h7; // the bit 7 is received first
data_phase <= 0;
end
else
begin
if(bit_ACK)
begin
bitcnt <= 4'h7;
data_phase <= 1;
end
else
bitcnt <= bitcnt - 4'h1;
end

// and detect if the I2C address matches our own
wire adr_phase = ~data_phase;
reg adr_match, op_read, got_ACK;
reg SDAr;

always @(posedge SCL) SDAr<=SDA; // sample SDA on posedge since the I2C spec specifies as low as 0µs hold-time on negedge
reg [7:0] mem;
wire op_write = ~op_read;

always @(negedge SCL or negedge incycle)
if(~incycle)
begin
got_ACK <= 0;
adr_match <= 1;
op_read <= 0;
end
else
begin
if(adr_phase & bitcnt==7 & SDAr!=I2C_ADR[6]) adr_match<=0;
if(adr_phase & bitcnt==6 & SDAr!=I2C_ADR[5]) adr_match<=0;
if(adr_phase & bitcnt==5 & SDAr!=I2C_ADR[4]) adr_match<=0;
if(adr_phase & bitcnt==4 & SDAr!=I2C_ADR[3]) adr_match<=0;
if(adr_phase & bitcnt==3 & SDAr!=I2C_ADR[2]) adr_match<=0;
if(adr_phase & bitcnt==2 & SDAr!=I2C_ADR[1]) adr_match<=0;
if(adr_phase & bitcnt==1 & SDAr!=I2C_ADR[0]) adr_match<=0;
if(adr_phase & bitcnt==0) op_read <= SDAr;
if(bit_ACK) got_ACK <= ~SDAr; // we monitor the ACK to be able to free the bus when the master doesn't ACK during a read operation

if(adr_match & bit_DATA & data_phase & op_write) mem[bitcnt] <= SDAr; // memory write
end

// and drive the SDA line when necessary.
wire mem_bit_low = ~mem[bitcnt[2:0]];
wire SDA_assert_low = adr_match & bit_DATA & data_phase & op_read & mem_bit_low & got_ACK;
wire SDA_assert_ACK = adr_match & bit_ACK & (adr_phase | op_write);
wire SDA_low = SDA_assert_low | SDA_assert_ACK;
assign SDA = SDA_low ? 1'b0 : 1'bz;


endmodule
 

Re: Data through i2c

hi,torius

It's not hard to do simple I2C IO use HDL

but you shoud have some basis knowledge of I2C spec and logic

design concept

The fpga4fun.coms' I2C example is good for a tyro

no more easy example like it.
 

Re: Data through i2c

Hello,

I understand the i2c protocol, the only problem for me is verilog code,

the only thing what i've got to do now is a reg [31:0] data. send through the sda line so i need to send 8 bits then wait for ack then send 8 bit etc. but this is the problem, don't know how to do this in a good way. tried different things for example with case structere but did't work, maybe you can give me a example to start on?

thnx anyway

greets torius
 

Re: Data through i2c

hi,

1.

The fpga4fun.com also provide VHDL code,Please check again.



https://www.fpga4fun.com/I2Cslave1.html

2.

I give you some my ideal,

In your need,there should be contain a 32 bit counter,a 32 bit latch....

and some control logic.

when mcu need to read counter value,first mcu send latch command(host write

to slave) to your I2C slave for latch the value of 32 bit counter into 32 bit latch.

second mcu receive MSB of 32 bit latch(host read form slave),

then receive 2nd,.......receive LSB and let 32 bit latch unlatch.

here you need to pay attention to synchr of counter CLK and latch signal,

Otherwise may latch error value in some condition.

I am poor in english,so hope you can understand what I say....

addn
 

Re: Data through i2c

Hallo, addn

first, Thnx for your reaction.

i understand what you saying. this is what i had in my mind.

always @ (condition) sel1 = sel1+1;

always @ (condition) begin
got_ACK = 1'b1; // temp for simulation
case (sel1)
0: SDA = Enc_1T[0] ;
1: SDA = Enc_1T[1] ;
2: SDA = Enc_1T[2] ;
3: SDA = Enc_1T[3] ;
4: SDA = Enc_1T[4] ;
5: SDA = Enc_1T[5] ;
6: SDA = Enc_1T[6] ;
7: SDA = Enc_1T[7] ;
8: SDA = 1'bz; // ackbit
9: if (got_ACK) begin
next_sel1 = 1'b1;
SDA = Enc_1T[8];
end
10:if (next_sel1) SDA = Enc_1T[9] ;
11:if (next_sel1) SDA = Enc_1T[10] ;
12: if (next_sel1) SDA = Enc_1T[11] ;
13: if (next_sel1) SDA = Enc_1T[12] ;
14: if (next_sel1) SDA = Enc_1T[13] ;
15: if (next_sel1) SDA = Enc_1T[14] ;
16: if (next_sel1) SDA = Enc_1T[15] ;
17: if (next_sel1) SDA = 1'bz;
18: if (got_ACK) begin
next_sel2 = 1'b1;
SDA = Enc_1T[16];
end
19:if (next_sel2) SDA = Enc_1T[17] ;
20:if (next_sel2) SDA = Enc_1T[18] ;
21: if (next_sel2) SDA = Enc_1T[19] ;
22: if (next_sel2) SDA = Enc_1T[20] ;
23: if (next_sel2) SDA = Enc_1T[21] ;
24: if (next_sel2) SDA = Enc_1T[22] ;
25: if (next_sel2) SDA = Enc_1T[23] ;
26: if (next_sel2) SDA = 1'bz;
27: if (got_ACK) begin
next_sel3 = 1'b1;
SDA = Enc_1T[24];
end
28:if (next_sel3) SDA = Enc_1T[25] ;
29:if (next_sel3) SDA = Enc_1T[26] ;
30: if (next_sel3) SDA = Enc_1T[27] ;
31: if (next_sel3) SDA = Enc_1T[28] ;
32: if (next_sel3) SDA = Enc_1T[29] ;
33: if (next_sel3) SDA = Enc_1T[30] ;
34: if (next_sel3) SDA = Enc_1T[31] ;
35: if (next_sel3) SDA = 1'bz;
endcase
 

Re: Data through i2c

hi,

maybe you can use shift_reg

ex:

...................
if(SCL'event and SCL='0') then
if(other_condition) then
SDA_tmp<=shift_reg(31);
...................
shift_reg(31 downto 1)<=shift_reg(30 downto 0);
end if;
.....................
end if;
...........................
SDA<='0' when (SDA_tmp='0' and other_condition1) else
'Z';
...........................
 

Re: Data through i2c

Hi,

Tell me your requirements for I2C host controller, I will give you the code in vhdl

Regards
vs21
 

Re: Data through i2c

hello again

thnx addn i think its with shift reg its much easier
also thnx vs21 for your offer, but i think i will make it now and if not i will replay on your offer

thnx
Torius
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…