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

📄 i2c_core.v

📁 FPGA设计的I2C总线控制器的MASTER端的程序
💻 V
字号:
// ********************************************************************* //
// Filename: i2c_core.v                                                //
// Projects: STiMi-Receiver                                              //
// Author  : XQ-Wang                                                     //
// Date    : 2007-06-25                                                  //
// Version : 1.0                                                         //
// ********************************************************************* //

`timescale	1ns/1ps

module i2c_core(
	SYS_CLK , 
	RST     , 
	RD      , 
	WR      , 
	
	Chip_id , 
	Addr    ,
	DATA_in ,
	DTyp    , 
	DNum    ,
	 
	DATA_out, 
	SCL     , 
	SDA_in  , 
	SDA_out ,
	SDA_sel ,
	ACK
	);

input		SYS_CLK  ;
input		RST      ;
input		RD       ;
input		WR       ;

input	[7:0]	Chip_id  ;
input	[7:0]	Addr     ;
input	[7:0]	DATA_in  ;	
input	[2:0]	DTyp     ;
input	[7:0]	DNum     ;

input		SDA_in   ;

output	[7:0]	DATA_out ;
wire	[7:0]	DATA_out ;
output          SCL      ;
reg             SCL      ;
output		SDA_out  ;
wire		SDA_out  ;
output		SDA_sel  ;
wire		SDA_sel  ;
output		ACK      ;
wire		ACK      ;

//------------------------------------------------
reg		WF,RF;
reg		FF;

reg	[7:0]	chip_id_slave;
reg	[7:0]	addr_slave;
reg	[7:0]	data_to_slave;

reg	[1:0]	head_buf;
reg 	[1:0]	stop_buf;

reg	[8:0]	sh8out_state;
reg	[9:0]	sh8in_state;
reg	[2:0]	head_state;
reg	[2:0]	stop_state;
reg	[7:0]	main_state; // 8 state

reg	[7:0]	sh8out_buf;
reg	[7:0]	data_from_slave;

reg		link_sda;
reg		link_read;
reg		link_head;
reg		link_write;
reg		link_stop;
reg		link_ack;
wire		sda_out1,sda_out2,sda_out3,sda_out4;

reg	[7:0]	dnum_cnt;
reg     [2:0]   dtype;	

reg	[7:0]	clk_cnt;

//--------------- Main state defination ---------
parameter	Idea           = 8'b00000001;
parameter Ready          = 8'b00000010;
parameter Write_start    = 8'b00000100;
parameter Write_chip_id  = 8'b00001000;
parameter Write_addr     = 8'b00010000;
parameter Write_data     = 8'b00100000;
parameter Read_data      = 8'b01000000;
parameter Stop           = 8'b10000000;

//--------------Parallel data to serial----------
parameter	sh8out_bit7	= 9'b000000001;
parameter	sh8out_bit6	= 9'b000000010;
parameter	sh8out_bit5	= 9'b000000100;
parameter	sh8out_bit4	= 9'b000001000;
parameter	sh8out_bit3	= 9'b000010000;
parameter	sh8out_bit2	= 9'b000100000;
parameter	sh8out_bit1	= 9'b001000000;
parameter	sh8out_bit0	= 9'b010000000;
parameter	sh8out_end	 = 9'b100000000;

//--------------Serial data to parallel----------
parameter	sh8in_begin	= 10'b0000000001;
parameter	sh8in_bit7	 = 10'b0000000010;
parameter	sh8in_bit6	 = 10'b0000000100;
parameter	sh8in_bit5	 = 10'b0000001000;
parameter	sh8in_bit4	 = 10'b0000010000;
parameter	sh8in_bit3	 = 10'b0000100000;
parameter	sh8in_bit2	 = 10'b0001000000;
parameter	sh8in_bit1	 = 10'b0010000000;
parameter	sh8in_bit0	 = 10'b0100000000;
parameter	sh8in_end	  = 10'b1000000000;

//--------------Start state---------------------
parameter	head_begin	= 3'b001;
parameter	head_bit	  = 3'b010;
parameter	head_end	  = 3'b100;

//--------------Sotp state----------------------
parameter	stop_begin	= 3'b001;
parameter	stop_bit	  = 3'b010;
parameter	stop_end	  = 3'b100;

//--------------Parameter define----------------
parameter	YES	     = 1'b1;
parameter	NO	     = 1'b0;

//----------- Generate SCL ---------------------
parameter	CLK_PERIOD	=	8'b10010110; //60M/400K=150

always @(negedge SYS_CLK)
begin
	if(RST)
	begin
		SCL     <= 1'b1;
		clk_cnt <= 8'b0;
	end
	else
	begin
		if(clk_cnt==CLK_PERIOD)
		begin
			SCL <= ~SCL;
			clk_cnt <= 8'b00000001;
		end
		else if(clk_cnt==(CLK_PERIOD>>1))
		begin
			SCL <= ~SCL;
			clk_cnt <= clk_cnt + 1;
		end
		else
			clk_cnt <= clk_cnt + 1;
	end
end

//---------------- Data Output -----------------
assign		sda_out1 = (link_head)  ?	head_buf[1] 	 : 1'b0;
assign		sda_out2 = (link_write) ?	sh8out_buf[7]	: 1'b0;
assign		sda_out3 = (link_stop)  ? stop_buf[1]	  : 1'b0;
assign		sda_out4 = (sda_out1 | sda_out2 | sda_out3);

assign		SDA_out  = (link_sda)   ?	sda_out4		      : 1'b0;
assign		DATA_out = (link_read)  ?	data_from_slave	: 8'hzz;
assign          ACK      = (link_ack)   ? SDA_in          : 1'b1;

assign		SDA_sel  = link_ack;

//----------- Data Buf --------------------------	
always @(posedge SYS_CLK, posedge RST)
begin
	if(RST)
		dtype <= 3'b000;
	else if(WR || RD)
	begin
		dtype         <= DTyp;
		chip_id_slave <= Chip_id;
		addr_slave    <= Addr;
		data_to_slave <= DATA_in;
	end
end

//----------- Main FSM --------------------------
always @(posedge SYS_CLK, posedge RST)
begin
	if(RST)
	begin
		link_read	 <= NO;
		link_write	<= NO;
		link_head	 <= NO;
		link_stop	 <= NO;
		link_sda	  <= NO;
		link_ack   <= NO;
		RF	   <= 1'b0;
		WF	   <= 1'b0;
		FF	   <= 1'b0;
		main_state	<= Idea;
		dnum_cnt	  <= 8'b0;
		
//		head_buf        <= 2'b00;
//		stop_buf        <= 2'b00;
//		sh8out_state    <= 9'b0;
//		sh8in_state     <= 10'b0;
//		head_state      <= 3'b0;
//		stop_state      <= 3'b0;
//		sh8out_buf      <= 8'b0;
//		data_from_slave <= 8'b0;
	end
	else if(clk_cnt==(CLK_PERIOD>>2) || clk_cnt==(CLK_PERIOD>>2)+(CLK_PERIOD>>1))
	begin
		case(main_state)
		Idea: begin
			link_read	 <= NO;
			link_write <= NO;
			link_head	 <= NO;
			link_stop	 <= NO;
			link_sda	  <= NO;
			link_ack   <= NO;
			dnum_cnt   <= DNum;
			if(WR)
			begin
				WF	   <= 1'b1;
				main_state	<= Ready;
			end
			else if(RD)
			begin
				RF	   <= 1'b1;
				main_state	<= Ready;
			end
			else
			begin
				WF	   <= 1'b0;
				RF	   <= 1'b0;
				main_state	<= Idea;
			end			
		end
		Ready: begin
			link_head	    <= YES;
			link_sda	     <= YES;
			dnum_cnt      <= DNum;
			head_buf[1:0]	<= 2'b10;
			stop_buf[1:0]	<= 2'b01;
			head_state	   <= head_begin;
			FF	      <= 1'b0;
			main_state	   <= Write_start;
		end
		Write_start: begin
			if(!FF)
				shift_head;
			else begin
				link_sda	       <= YES;
				link_head	      <= NO;
				link_write	     <= YES;
														
				FF	        <= 1'b0;				
				if(dtype[1:0]==2'b01)
				begin
					if(dnum_cnt==DNum)
					begin
						sh8out_buf[7:0]	<= chip_id_slave;
						sh8out_state	   <= sh8out_bit6;
						main_state	     <= Write_chip_id;
					end
					else
					begin
						sh8out_buf[7:0]	<= addr_slave;
						sh8out_state	   <= sh8out_bit6;
						main_state	     <= Write_addr;
					end
						
				end
				else if(dtype[1:0]==2'b10)
				begin
					sh8out_buf[7:0]	<= addr_slave;
					sh8out_state    <= sh8out_bit6;
					main_state      <= Write_addr ;
				end
			end
		end
		Write_chip_id:begin
			if(!FF)
				shift8_out;
			else begin
				if(!WR && !RD)
				begin
					link_read	 <= NO;
					link_write	<= NO;
					link_head	 <= NO;
					link_stop	 <= NO;
					link_sda	  <= NO;
					RF	   <= 1'b0;
					WF	   <= 1'b0;
					FF	   <= 1'b0;
					main_state	<= Idea;
					dnum_cnt	  <= 8'b0;
				end
				else if(!SCL)
				begin
					link_sda	       <= YES;
					link_write	     <= YES;
					link_ack		<= NO;
					
					FF		<= 1'b0;
					main_state	     <= Write_addr;
					sh8out_buf[7:0]	<= addr_slave;
					sh8out_state    <= sh8out_bit6;
				end
			end
		end
		Write_addr: begin
			if(!FF)
				shift8_out;
			else begin
				if(!WR && !RD)
				begin
					link_read	 <= NO;
					link_write	<= NO;
					link_head	 <= NO;
					link_stop	 <= NO;
					link_sda	  <= NO;
					RF	   <= 1'b0;
					WF	   <= 1'b0;
					FF	   <= 1'b0;
					main_state	<= Idea;
					dnum_cnt	  <= 8'b0;
				end
				else if(!SCL)
				begin
					link_sda   <= YES;
					link_ack	  <= NO;
					FF         <= 1'b0;
				
					if(WF)
					begin
						link_write 		<= YES;
						sh8out_buf[7:0] <= data_to_slave;
						sh8out_state    <= sh8out_bit6;
						main_state      <= Write_data;
					end
					else if(RF)
					begin
						link_read   <= YES;
						sh8in_state <= sh8in_begin;
						main_state  <= Read_data;
					end
				end
			end
		end
		Write_data: begin
			if(!FF)
				shift8_out;
			else begin
				if(!SCL)
				begin
					link_sda   <= YES;
					link_ack   <= NO;				
					FF         <= 1'b0;
				
					if(dnum_cnt==8'b0)
					begin
						link_stop     <= YES;
						stop_buf[1:0]	<= 2'b01;
						stop_state	   <= stop_bit;
						main_state	   <=Stop;
					end
					else if(!dtype[2])
					begin
						link_head     <= YES;
						head_buf[1:0]	<= 2'b10;
						head_state	   <= head_begin;
						main_state    <= Write_start;
					end
					else if(dtype[2])
					begin
						link_write		<= YES;
						sh8out_buf[7:0] <= data_to_slave;
						sh8out_state    <= sh8out_bit6;
						main_state      <= Write_data;
					end	
				end
			end
		end
		Read_data: begin
			if(!FF)
				shift8_in;
			else begin
				link_sda   <= YES;
				link_ack   <= NO ;
				FF         <= 1'b0;
				
				if(dnum_cnt==8'b0)
				begin
					link_stop     <= YES;
					stop_buf[1:0]	<= 2'b01;
					stop_state	   <= stop_bit;
					main_state	   <=Stop;
				end
				else if(!dtype[2])
				begin
					link_head     <= YES;
					head_buf[1:0]	<= 2'b10;
					head_state	   <= head_begin;
					main_state    <= Write_start;
				end
				else if(dtype[2])
				begin
					link_read   <= YES;
					sh8in_state <= sh8in_begin;
					main_state  <= Read_data;
				end
			end
		end
		Stop: begin
			if(!FF)
				shift_stop;
			else
			begin
				link_stop  <= NO;
				link_sda   <= NO;
				WF         <= 1'b0;
				RF         <= 1'b0;
				main_state <= Idea;
			end
		end
		default: main_state <= Idea;
		endcase
	end
end

//-----------------------------------------------
task shift_head;
begin
	casex(head_state)
	head_begin:
		if(!SCL)
		begin
			link_write	<= NO;
			link_sda	  <= YES;
			link_head	 <= YES;
			head_state	<= head_bit;
		end
		else
			head_state	<= head_begin;
		
	head_bit:
		if(SCL)
		begin
			FF	   <= 1'b1;
			head_buf	  <= head_buf<<1;
			head_state	<= head_end;
		end
		else
			head_state	<= head_bit;
	head_end:
		if(!SCL)
		begin
			link_head	 <= NO;
			link_write	<= YES;
		end
		else
			head_state	<= head_end;
	endcase
end
endtask
//-----------------------------------------------
task shift_stop;
begin
	casex(stop_state)
	stop_begin:
		if(!SCL)
		begin
			link_sda	  <= YES;
			link_write	<= NO;
			link_stop	 <= YES;
			stop_state	<= stop_bit;
		end
		else
			stop_state	<= stop_begin;
	stop_bit:
		if(SCL)
		begin
			stop_buf	  <= stop_buf<<1;
			stop_state	<= stop_end;
		end
		else
			stop_state	<= stop_bit;
	stop_end:
		if(!SCL)
		begin
			link_head	<= NO;
			link_stop	<= NO;
			link_sda	 <= NO;
			FF	  <= 1'b1;
		end
		else
			stop_state	<= stop_end;
	endcase	
end
endtask
//-----------------------------------------------
task shift8_in;
begin
	casex(sh8in_state)
		sh8in_begin:
			sh8in_state <= sh8in_bit7;
		
		sh8in_bit7: begin
			if(SCL)
			begin
				data_from_slave[7]	    <= SDA_in;
				sh8in_state		    <= sh8in_bit6;
			end
			else
				sh8in_state		    <= sh8in_bit7;
		end
		sh8in_bit6: begin
			if(SCL)
			begin
				data_from_slave[6]		<= SDA_in;
				sh8in_state		    <= sh8in_bit5;
			end
			else
				sh8in_state		    <=sh8in_bit6;
		end
		sh8in_bit5: begin
			if(SCL)
			begin
				data_from_slave[5]		<= SDA_in;
				sh8in_state		    <= sh8in_bit4;
			end
			else
				sh8in_state		    <= sh8in_bit5;
		end
		sh8in_bit4: begin
			if(SCL)
			begin
				data_from_slave[4]		<= SDA_in;
				sh8in_state		    <= sh8in_bit3;
			end
			else
				sh8in_state		    <= sh8in_bit4;
		end
		sh8in_bit3: begin
			if(SCL)
			begin
				data_from_slave[3]		<= SDA_in;
				sh8in_state		    <= sh8in_bit2;
			end
			else
				sh8in_state		    <= sh8in_bit3;
		end
		sh8in_bit2: begin
			if(SCL)
			begin
				data_from_slave[2]		<= SDA_in;
				sh8in_state		    <= sh8in_bit1;
			end
			else
				sh8in_state		    <= sh8in_bit2;
		end
		sh8in_bit1: begin
			if(SCL)
			begin
				data_from_slave[1]		<= SDA_in;
				sh8in_state		    <= sh8in_bit0;
			end
			else
				sh8in_state		    <= sh8in_bit1;
		end
		sh8in_bit0: begin
			if(SCL)
			begin
				data_from_slave[0]		<= SDA_in;
				sh8in_state		    <= sh8in_end;
			end
			else
				sh8in_state		    <= sh8in_bit0;
		end
		sh8in_end: begin
			if(SCL)
			begin
				link_read		    <= YES;
				link_ack		    <= YES;
				FF		    <= 1'b1;
				sh8in_state		    <= sh8in_bit7;
				
				if(main_state==Read_data)
					dnum_cnt 	 <= dnum_cnt - 1;
			end
			else
				sh8in_state         <= sh8in_end;
		end
		default: begin
			link_read			    <= NO;
			sh8in_state			    <= sh8in_bit7;
		end
	endcase
end
endtask
//-----------------------------------------------
task shift8_out;
begin
	casex(sh8out_state)
		sh8out_bit7:
		begin
			if(!SCL) 
			begin
				link_sda		<= YES;
				link_write		<= YES;
				sh8out_state		<= sh8out_bit6;
			end
			else
				sh8out_state		<= sh8out_bit7;
		end
		sh8out_bit6:
		begin
			if(!SCL) 
			begin
				link_sda		<= YES;
				link_write		<= YES;
				sh8out_state		<= sh8out_bit5;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit6;
		end
		sh8out_bit5:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_bit4;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit5;
		end
		sh8out_bit4:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_bit3;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit4;
		end
		sh8out_bit3:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_bit2;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit3;
		end
		sh8out_bit2:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_bit1;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit2;
		end
		sh8out_bit1:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_bit0;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit1;
		end
		sh8out_bit0:
		begin
			if(!SCL) 
			begin
				sh8out_state		<= sh8out_end;
				sh8out_buf		<= sh8out_buf<<1;
			end
			else
				sh8out_state		<= sh8out_bit0;
		end
		sh8out_end:
			if(!SCL) 
			begin
				link_sda		<= NO;
				link_write		<= NO;
				link_ack		<= YES;
				FF		<= 1'b1;
				if(main_state==Write_data)
					dnum_cnt 	 <= dnum_cnt - 1;
			end
			else
				sh8out_state		<= sh8out_end;
		endcase
	end
endtask

endmodule

⌨️ 快捷键说明

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