Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

I2C code help

Altera_Forum
Honored Contributor II
2,132 Views

Hello. Im in the stages of designing an I2C interface to the audio codec on my fpga. Its very simple, as im new to verilog and still in debugging stages. One snag is when Im attempting to read certain bits of a parallel input. My code, in state s2, seems alright but it goes unstable in simulation when leaving s2. Can you think of what is wrong, or an alternative way of coding my problem? 

 

module i2c(SCL_io, SDA_io, clk, rst, write); input write, clk, rst; output SCL_io; inout SDA_io; reg stopcount = 0; reg bitcount = 0; reg msbcount = 0; reg indata = 8'b01001010; reg SCL,SDA; reg pres, next; parameter s0=4'b0000,s1=4'b0001,s2=4'b0010,s3=4'b0011,s4=4'b0100,s5=4'b0101,s6=4'b0110,s7=4'b0111,s8=4'b1000; always@(posedge clk) begin if(rst) pres=s0; else pres=next; end always @ (pres or write or stopcount or msbcount or indata or bitcount) begin case (pres) s0: begin SDA = 1'b1; SCL = 1'b1; if(write) next=s1; else next=s0; end s1: begin SDA = 1'b0; SCL = 1'b1; next=s2; end s2: begin SDA = 1'b0; SCL = 1'b0; stopcount <= stopcount + 1; if(stopcount == 4) next=s8; else begin case (msbcount) 1: begin if( indata == 1'b1) next=s5; else next=s3; end 2: begin if( indata == 1'b1) next=s5; else next=s3; end 3: begin if( indata == 1'b1) next=s5; else next=s3; end 4: begin if( indata == 1'b1) next=s5; else next=s3; end 5: begin if( indata == 1'b1) next=s5; else next=s3; end 6: begin if( indata == 1'b1) next=s5; else next=s3; end 7: begin if( indata == 1'b1) next=s5; else next=s3; end 8: begin if( indata == 1'b1) next=s5; else next=s3; end endcase end end s3: begin SDA = 1'b0; SCL = 1'b1; next=s4; end s4: begin SDA = 1'b0; SCL = 1'b0; bitcount <= bitcount+1; msbcount <= msbcount+1; if(bitcount == 8) next=s7; else begin case (msbcount) 1: begin if( indata== 1'b1) next=s5; else next=s3; end 2: begin if( indata== 1'b1) next=s5; else next=s3; end 3: begin if( indata== 1'b1) next=s5; else next=s3; end 4: begin if( indata== 1'b1) next=s5; else next=s3; end 5: begin if( indata== 1'b1) next=s5; else next=s3; end 6: begin if( indata== 1'b1) next=s5; else next=s3; end 7: begin if( indata== 1'b1) next=s5; else next=s3; end 8: begin if( indata== 1'b1) next=s5; else next=s3; end endcase end end s5: begin SDA = 1'b1; SCL = 1'b1; next=s6; end s6: begin SDA = 1'b1; SCL = 1'b0; bitcount <= bitcount+1; msbcount <= msbcount+1; if(bitcount == 8) next=s7; else begin case (msbcount) 1: begin if( indata== 1'b1) next=s5; else next=s3; end 2: begin if( indata== 1'b1) next=s5; else next=s3; end 3: begin if( indata== 1'b1) next=s5; else next=s3; end 4: begin if( indata== 1'b1) next=s5; else next=s3; end 5: begin if( indata== 1'b1) next=s5; else next=s3; end 6: begin if( indata== 1'b1) next=s5; else next=s3; end 7: begin if( indata== 1'b1) next=s5; else next=s3; end 8: begin if( indata== 1'b1) next=s5; else next=s3; end endcase end end s7: begin SDA = 1'b1; SCL = 1'b1; if(~SDA) next=s2; else next=s7; next=s2; end s8: begin SDA = 1'b1; SCL = 1'b0; next=s0; end endcase end assign SDA_io = SDA; assign SCL_io = SCL; endmodule
0 Kudos
7 Replies
Altera_Forum
Honored Contributor II
1,397 Views

It seems you don't initialize "stopcount" and go out of the s2 state.

0 Kudos
Altera_Forum
Honored Contributor II
1,397 Views

stopcount is initalised at the top. does it need to be defined as zero again? Also, i think it has something to do with msbcount. what do u think?

0 Kudos
Altera_Forum
Honored Contributor II
1,397 Views

i have been playing with my code, however the counts are just so unstable. Any better method you could suggest to get this working efficeintly?

0 Kudos
Altera_Forum
Honored Contributor II
1,397 Views

The counters need to be in a clocked process otherwise they'll increment every time a signal in the sensitivity list changes and also you'll find it won't act the same way in hardware.

0 Kudos
Altera_Forum
Honored Contributor II
1,397 Views

Do you think putting the counters in their own clk sensitive case statement would help? I hava feeling it wont work. Any strategies you can suggest?  

 

As a side note, i have a master i2c core working on a pic. but im having trouble getting the fpga to send back and ack. Is this the right way to set up linking the pic to the fpga? 

 

[input from pic SDA]--------------------[bi-directional to/from audio codec] 

[input from pic SCL]--------------------[output to audio codec]
0 Kudos
Altera_Forum
Honored Contributor II
1,396 Views

Hello, 

 

Although I didn't test it, I attach the code modified. In the verilog reg defines registers and wires, you should make it clear which are real register and which are just wire. I hope it will help. 

 

Thanks,
0 Kudos
Altera_Forum
Honored Contributor II
1,396 Views

Gee, you are a genious! Thanks for your help, it works well now! 

 

I changed my code a bit though, instead of msbcount and all those case satements I just used a right shift operator and tested bit 7.  

 

Only problem now is simulating when SDA is forced low for the acknowledgement. I have tried forcing SDA low at the right point in the waveform, but it doesnt seem to work...anything special i need to do to simulate bi-directional pins?
0 Kudos
Reply