⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.v

📁 pci转local bus总线的应用
💻 V
字号:
//I2C interface

module i2c (
	clock,
	reset_n,
	scl,
	sda,
	no_ack,
	ready,
	data_in,
	data_out,
	sa,
	rw,
	ra,
	ini
	);


	input clock;
	input reset_n;

	output scl;
	inout sda;
	output no_ack;
	output ready;
	input [7:0] data_in;
	output [7:0] data_out;
	input [6:0] sa;//slave address
	input rw;//1---R; 0---W
	input [7:0] ra;//register address
	input ini;

	reg ready;
	reg scl_oe;
	reg sda_oe;
	wire sda_in;
	reg sda_out;
	reg no_ack;
	reg [7:0] data_out;

	reg [30:0] sda_write_reg;
	reg [41:0] sda_read_reg;

	reg [5:0] sda_count;

	reg clk_scl;
	reg clk_sda;
	reg ini_dly;
	reg ini_m_dly;
/******************************************************************************/
assign scl = (scl_oe) ? clk_scl : 1'b1;
assign sda = (sda_oe) ? sda_out : 1'bz;
assign sda_in = (!sda_oe) ? sda : 1'b0;
/******************************************************************************/
always @(posedge ini or posedge clk_sda or negedge reset_n) //ini_m_dly <= ini;
	begin
	    if(!reset_n) ini_m_dly <= 1'b0;
	    else if(ini) ini_m_dly <= 1'b1;
	    else ini_m_dly <= 1'b0;
	end

always @(posedge clk_sda) ini_dly <= ini_m_dly;

//注意:接收到ini信号后要过约4us操作才真正开始(Ready=0)
/******************************************************************************/
/******************************************************************************/
//sda_out state machine

	reg [2:0] cstate;

	parameter [2:0]
		IDLE 	= 3'b001,
		READ 	= 3'b010,
		WRITE	= 3'b100;

////////////////////////////////////////////////////////////////////////////////
always @(posedge clk_sda or negedge reset_n)
	begin
	    if(!reset_n)
		begin
		    cstate <= IDLE;
		    ready <= 1'b0;
		    sda_oe <= 1'b0;
		    sda_out <= 1'b0;
		    sda_write_reg <= 31'b0;
		    sda_read_reg <= 42'b0;
		    sda_count <= 6'b0;
		end
	    else
		begin
		    case(cstate)

			IDLE:
			    begin
			        sda_count <= 6'b0;
			        sda_oe <= 1'b1;
			        sda_out <= 1'bz;
				if(ini_dly && rw)
				    begin
				        cstate <= READ;
				        ready <= 1'b0;
					sda_read_reg <= {2'b10,		/*start*/
							sa[6:0],	/*slave address*/
							1'b0,		/*write*/
							1'bz,		/*ack*/
							ra[7:0],	/*register address*/
							1'bz,		/*ack*/
							2'b10,		/*start*/
							sa[6:0],	/*slave address*/
							1'b1,		/*read*/
							1'bz,		/*ack*/
							8'bzzzzzzzz,	/*data*/
							1'b0,		/*/ack*/
							2'b01		/*stop*/
							};		/*42 bits*/
				    end
				else if(ini_dly && !rw)
				    begin
				        cstate <= WRITE;
				        ready <= 1'b0;
					sda_write_reg <= {2'b10,	/*start*/
							sa[6:0],	/*slave address*/
							1'b0,		/*write*/
							1'bz,		/*ack*/
							ra[7:0],	/*register address*/
							1'bz,		/*ack*/
							data_in[7:0],	/*data*/
							1'bz,		/*ack*/
							2'b01		/*stop*/
							};		/*31 bits*/
				    end
				else
				    begin
				        ready <= 1'b1;
				        cstate <= IDLE;
				    end
			    end

			READ:
			    begin
			    	if(sda_count <= 41)
			    	    begin
					cstate <= READ;
					sda_out <= sda_read_reg[41];
					sda_read_reg <= sda_read_reg << 1;
					sda_oe <= (sda_count == 10
						|| sda_count == 19
						|| (sda_count >= 30 && sda_count <= 38))
						? 1'b0 : 1'b1;
					sda_count <= sda_count + 1;
				    end
				else
					cstate <= IDLE;
			    end

			WRITE:
			    begin
				if(sda_count <= 30)
				    begin
					cstate <= WRITE;
					sda_out <= sda_write_reg[30];
					sda_write_reg <= sda_write_reg << 1;
					sda_oe <= (sda_count == 10
						|| sda_count == 19
						|| sda_count == 28)
						? 1'b0 :1'b1;
					sda_count <= sda_count + 1;
				    end
				else
					cstate <= IDLE;
			    end

			default: cstate <= IDLE;
		    endcase
		end
	end
/******************************************************************************/
//sda_in state machine

	reg [2:0] cstate_1;

	parameter [2:0]
		IDLE_1 	= 3'b001,
		READ_1 	= 3'b010,
		WRITE_1	= 3'b100;

////////////////////////////////////////////////////////////////////////////////
always @(posedge clk_scl or negedge reset_n)
	begin
	    if(!reset_n)
		begin
		    cstate_1 <= IDLE_1;
		    scl_oe <= 1'b0;
		    data_out <= 8'b0;
		    no_ack <= 1'b0;
		end
	    else
		begin
		    case(cstate_1)

			IDLE_1:
			    begin
			        scl_oe <= 1'b0;
				if(ini_dly && rw)
				    begin
				        cstate_1 <= READ_1;
				        no_ack <= 1'b0;
				    end
				else if(ini_dly && !rw)
				    begin
				        cstate_1 <= WRITE_1;
				        no_ack <= 1'b0;
				    end
				else
				    begin
				        cstate_1 <= IDLE_1;
				    end
			    end

			READ_1:
			    begin
			    	if(sda_count <= 41)
			    	    begin
					cstate_1 <= READ_1;
					scl_oe <= ((sda_count >= 2 && sda_count <= 20)
						|| (sda_count >= 22 && sda_count <= 40))
						? 1'b1 : 1'b0;
					if(sda_count == 11 || sda_count == 20
						|| sda_count == 31)
					    	no_ack <= no_ack || sda_in;
					if(sda_count >= 31 && sda_count <= 39)
						data_out[7:0] <= {data_out[6:0] , sda_in};
				    end
				else
					cstate_1 <= IDLE_1;
			    end

			WRITE_1:
			    begin
				if(sda_count <= 30)
				    begin
					cstate_1 <= WRITE_1;
					scl_oe <= (sda_count >= 2 && sda_count <= 29)
						? 1'b1 : 1'b0;
					if(sda_count == 11 || sda_count == 20
						|| sda_count == 29)
					    	no_ack <= no_ack || sda_in;
				    end
				else
					cstate_1 <= IDLE_1;
			    end

			default: cstate_1 <= IDLE_1;
		    endcase
		end
	end

/******************************************************************************/
//Counter
//clk_scl & clk_sda

	reg [6:0] counter;

always @ (posedge clock or negedge reset_n)
	begin
	    if(!reset_n)
	        begin
		    counter <= 7'b0;
	    	    clk_sda <= 1'b0;
	    	    clk_scl <= 1'b0;
	    	end
	    else
	        begin
		counter <= counter + 1;
		if(counter[5:0] == 6'b10_0000)
	    	    clk_sda <= ~ clk_sda;
	    	if(counter[5:0] == 6'b11_1111)
	    	    clk_scl <= ~ clk_scl;
	    	end
	end
/*
f(clk_sda , clk_scl)=f(clock)/128 =33MHz/128=260KHz
            ___     ___     ___     ___     ___     ___     ___
clk_scl	___|   |___|   |___|   |___|   |___|   |___|   |___|   |___
          ___     ___     ___     ___     ___     ___     ___
clk_sda	_|   |___|   |___|   |___|   |___|   |___|   |___|   |___

*/
/******************************************************************************/
/******************************************************************************/

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -