天天看点

IIC(I2C)总线 FPGA Verilog HDL

IIC(I2C)总线 FPGA Verilog HDL

配置文件:根据具体的IIC设备改一下时钟频率就可以产生正确的时钟波形

`define SYS_CLK  50_000_000
`define SCL_CLK  400_000

`define COUNT_MAX (`SYS_CLK/`SCL_CLK)

`define HALF  (`COUNT_MAX/2 -1)

`define H_HALF  (`HALF/2)
`define NEG     (`HALF +1)
`define L_HALF  (`H_HALF+NEG)
           

RTL代码:

`include "config.v"
module I2C(
    clk,               //system clk 50MHZ
	rstn,              //active low
	data_in,           
    data_out,
	sda,
	scl,
	wr,               //wr=0   write; wr=1  read
	fail,
	req,
	address,
	wr_done,
	rd_done
);


    input clk;
	input rstn;
	input [7:0]data_in;
	input wr;
	input req;
	input [7:0] address;
	
	output [0:0]scl;
	output reg[7:0] data_out;
	
	inout sda;
	output fail;
	output rd_done;
	output wr_done;
	
	reg [7:0] clk_cnt;
	
	wire sda_in;
	reg sda_out;
	
	reg [29:0] state;
	
	reg [0:0]  sda_mode;
	wire clk_en;
	
	parameter IN   =0,
	          OUT  =1;
				 
				 
	parameter         idle      =30'b00_0000_0000_0000_0000_0000_0000_0001,
	                  start     =30'b00_0000_0000_0000_0000_0000_0000_0010,
					  mode0     =30'b00_0000_0000_0000_0000_0000_0000_0100,
					  mode1     =30'b00_0000_0000_0000_0000_0000_0000_1000,
					  mode2     =30'b00_0000_0000_0000_0000_0000_0001_0000,
					  mode3     =30'b00_0000_0000_0000_0000_0000_0010_0000,
					  mode4     =30'b00_0000_0000_0000_0000_0000_0100_0000,
					  mode5     =30'b00_0000_0000_0000_0000_0000_1000_0000,
					  mode6     =30'b00_0000_0000_0000_0000_0001_0000_0000,
					  mode7     =30'b00_0000_0000_0000_0000_0010_0000_0000,
					  ack_mode  =30'b00_0000_0000_0000_0000_0100_0000_0000,
					  addr0     =30'b00_0000_0000_0000_0000_1000_0000_0000,
					  addr1     =30'b00_0000_0000_0000_0001_0000_0000_0000,
					  addr2     =30'b00_0000_0000_0000_0010_0000_0000_0000,
					  addr3     =30'b00_0000_0000_0000_0100_0000_0000_0000,
					  addr4     =30'b00_0000_0000_0000_1000_0000_0000_0000,
					  addr5     =30'b00_0000_0000_0001_0000_0000_0000_0000,
					  addr6     =30'b00_0000_0000_0010_0000_0000_0000_0000,
					  addr7     =30'b00_0000_0000_0100_0000_0000_0000_0000,
					  ack_addr  =30'b00_0000_0000_1000_0000_0000_0000_0000,
					  bit0      =30'b00_0000_0001_0000_0000_0000_0000_0000,      
					  bit1      =30'b00_0000_0010_0000_0000_0000_0000_0000, 
					  bit2      =30'b00_0000_0100_0000_0000_0000_0000_0000, 
					  bit3      =30'b00_0000_1000_0000_0000_0000_0000_0000, 
					  bit4      =30'b00_0001_0000_0000_0000_0000_0000_0000, 
					  bit5      =30'b00_0010_0000_0000_0000_0000_0000_0000, 
					  bit6      =30'b00_0100_0000_0000_0000_0000_0000_0000, 
					  bit7      =30'b00_1000_0000_0000_0000_0000_0000_0000, 
					  ack_bit   =30'b01_0000_0000_0000_0000_0000_0000_0000,
					  stop      =30'b10_0000_0000_0000_0000_0000_0000_0000;    
					  
   //generate clk 400khz
	[email protected](posedge clk)
      if(!rstn)
		   clk_cnt <=8'd0;
		else if(clk_en)
		   begin
			   if(clk_cnt==`COUNT_MAX)
				  clk_cnt <=8'd0;
				else
				  clk_cnt <=clk_cnt + 1'b1;
			end
		else
		   clk_cnt <=8'd0;
			
	//wire neg=(clk_cnt==`NEG)?1:0;            //negedge of the scl_clk
	wire      h_half   =(clk_cnt==h_half);      
	wire      l_half   =(clk_cnt==l_half);  
   wire      scl_clk  =(clk_cnt <`HALF);
   assign    scl      =(clk_en&scl_clk)|(!clk_en);
	
	//control sda direction
    assign sda=(sda_mode==OUT)?sda_out:1'bz;
	assign sda_in=(sda_mode==IN)?sda:1'bz;
	wire    full=(clk_cnt==`COUNT_MAX);

   //state control	
	[email protected](posedge clk)
      if(!rstn)
	      state <=idle;
		else
	      case(state)
		   idle:
		      if(req)
			      state <=start;
				else
			      state <=state;
			start:   //at the same time start clock generator
			      if(full)
					   state <=mode0;
					else
					   state <=state;
			mode0:
			      if(full)
		            state <=mode1;
					else
					   state <=state;
			mode1:
			      if(full)
		            state <=mode2;
					else
					   state <=state;
			mode2:
			      if(full)
		            state <=mode3;
					else
					   state <=state;
			mode3:
		         if(full)
					  state <=mode4;
					else
					  state <=state;
			mode4:
		         if(full)
					  state <=mode5;
					else
					  state <=state;
			mode5:
			      if(full)
		            state <=mode6;
					else
					   state <=state;
			mode6:
		         if(full)
					  state <=mode7;
					else
					  state <=state;
			mode7:
			      if(full)
		            state <=ack_mode;	
					else
					   state <=state;
			ack_mode:
			      if(h_half)
					   begin
						   if(sda_in==1'b1)
							   state <=addr0;
							else
							   state <=stop;
						end
					else
					   state <=state;
			addr0:
			      if(full)
					   state <=addr1;
					else
					   state <=state;
			addr1: 
			      if(full)
					   state <=addr2;
					else
					   state <=state;
			addr2:
			      if(full)
					   state <=addr3;
					else
					   state <=state;
			addr3:  
			      if(full)
					   state <=addr4;
					else
					   state <=state;
			addr4:
			      if(full)
					   state <=addr5;
					else
					   state <=state;
			addr5:
			      if(full)
					   state <=addr6;
					else
					   state <=state;
			addr6:
			      if(full)
					   state <=addr7;
					else
					   state <=state;
			addr7:
			      if(full)
					   state <=ack_addr;
					else
					   state <=state;
		   ack_addr:
			      if(h_half)
					   begin
			            if(sda_in==1'b0)
					         state <=bit0;
					      else
					         state <=stop;
						end
				   else
					   state <=state;
		   bit0:
			      if(full)
					   state <=bit1;
					else
					   state <=bit2;
			bit1:
			      if(full)
					   state <=bit2;
					else
					   state <=state;
			bit2:
			      if(full)
					   state <=bit3;
					else
					   state <=state;
			bit3:
			      if(full)
					   state <=bit4;
					else
					   state <=state;
			bit4:
			      if(full)
					   state <=bit5;
					else
					   state <=state;
			bit5:
			      if(full)
					   state <=bit6;
					else
					   state <=state;
			bit6:
			      if(full)
					   state <=bit7;
					else
					   state <=state;			
			bit7:
			      if(full)
					   state <=ack_bit;
					else
					   state <=state;
			ack_bit:
			        if((!wr)&h_half)
					      begin
			               if(sda_in==1'b0)
					            state  <=stop;
					         else
					            state  <=stop;
							end
                    else if(wr&l_half)
                           state <=stop;					
					else
						   state <=state;
			stop:
			      if(full)
					   state <=idle;
					else
					   state <=state;
			default: state  <=stop;
		endcase
			
	[email protected](posedge clk)
	if(!rstn)
	begin
	    sda_mode <=OUT;
		sda_out  <=1'b1;
		data_out <=8'b0;
	end
	else
	    case(state)
		    idle:
			        begin
			        sda_mode <=OUT;
				     sda_out  <=1'b1;
			        end
		    start:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b0;
					    else
					    sda_out <=1'b1;
			        end
		    mode0:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b1;
					    else
					    sda_out <=sda_out;
			        end
		    mode1:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b0;
					    else
					    sda_out <=sda_out;
			        end
		    mode2:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b1;
					    else
					    sda_out <=sda_out;
			        end
		    mode3:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b0;
					    else
					    sda_out <=sda_out;
			        end
		    mode4:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b1;
					    else
					    sda_out <=sda_out;
			        end
		    mode5:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b0;
					    else
					    sda_out <=sda_out;
			        end
		    mode6:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=1'b0;
					    else
					    sda_out <=sda_out;
			        end
		    mode7:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=wr;
					    else
					    sda_out <=sda_out;
			        end
		    ack_mode:
			        begin
			        sda_mode <=IN;
			        end
		    addr0:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[7];
					    else
					    sda_out <=sda_out;
			        end					
		    addr1:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[6];
					    else
					    sda_out <=sda_out;
			        end	
		    addr2:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[5];
					    else
					    sda_out <=sda_out;
			        end	
		    addr3:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[4];
					    else
					    sda_out <=sda_out;
			        end	
		    addr4:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[3];
					    else
					    sda_out <=sda_out;
			        end	
		    addr5:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[2];
					    else
					    sda_out <=sda_out;
			        end	
		    addr6:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[1];
					    else
					    sda_out <=sda_out;
			        end	
		    addr7:
			        begin
			        sda_mode <=OUT;
				        if(l_half)
					    sda_out <=address[0];
					    else
					    sda_out <=sda_out;
			        end						
		   ack_addr:
			        begin
			        sda_mode <=IN;
			        end	
            bit0:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[7]  <=sda_in;
							else
							data_out[7]  <=data_out[7];
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[7];
							   else
							   sda_out   <=sda_out;
                        end						
            bit1:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[6]  <=sda_in;
							else
							data_out[6]  <=data_out[6];
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[6];
							   else
							   sda_out   <=sda_out;
                        end	
            bit2:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[5]  <=sda_in;
							else
							data_out[5]  <=data_out[5];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[5];
							   else
							   sda_out   <=sda_out;
                        end	
            bit3:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[4]  <=sda_in;
							else
							data_out[4]  <=data_out[4];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[4];
							   else
							   sda_out   <=sda_out;
                        end	
            bit4:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[3]  <=sda_in;
							else
							data_out[3]  <=data_out[3];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[3];
							   else
							   sda_out   <=sda_out;
                        end	
            bit5:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[2]  <=sda_in;
							else
							data_out[2]  <=data_out[2];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[2];
							   else
							   sda_out   <=sda_out;
                        end	
            bit6:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[1]  <=sda_in;
							else
							data_out[1]  <=data_out[1];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[1];
							   else
							   sda_out   <=sda_out;
                        end	
            bit7:
                    if(wr)//read
					    begin
                            sda_mode     <=IN;
                            if(h_half)
					    	data_out[0]  <=sda_in;
							else
							data_out[0]  <=data_out[0];							
                        end
                   	else//write
                        begin
                            sda_mode     <=OUT;
							   if(l_half)
							   sda_out   <=data_in[0];
							   else
							   sda_out   <=sda_out;
                        end	
            ack_bit:
						if(!wr)
                            sda_mode  <=IN;
						else
						    begin
							sda_mode  <=OUT;
							if(l_half)
							sda_out   <=1'b1;
							else
							sda_out   <=sda_out;
							end        									
            stop:
                if(h_half)//閹峰鐝
				    begin
					sda_mode    <=OUT;
					sda_out     <=1;
					end
				else if(!h_half)//閹峰缍
				    begin
					sda_mode    <=OUT;
					sda_out     <=0;					
					end
		    default:begin   
						sda_out   <=1'b1;
						sda_mode  <=OUT;
                        data_out  <=8'd0;						
			        end
	    endcase
								
   assign   clk_en       =(state==idle);
   assign   wr_done      =(state==ack_bit)&(h_half)&(sda_in==1'b0);
   assign   fail         =((state==ack_mode)&(h_half)&(sda_in!=1'b0))|
                          ((state==ack_addr)&(h_half)&(sda_in!=1'b0))|
                          ((state==ack_bit)&(h_half)&(sda_in!=1'b0));			 
   assign   rd_done     =(state==stop);	
endmodule