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

📄 i2c_slave.v

📁 一个好用的经过FPGA验证的i2c_slave verilog代码。
💻 V
📖 第 1 页 / 共 2 页
字号:
//**********************************************************************
//
//            File: i2c_slave.v
//            Module:i2c_slave
//            IME of CAS
//            by jgchen 
//
//
//**********************************************************************
`timescale	1ns/1ps

module	i2c_slave(
		reset_n,
		clock,
		sda_out,
		sda_in,
		scl,
		sda_en,
                data_reg0,   
                data_reg1                          
		);
		
input		clock;   
input		reset_n;
input		sda_in;
input		scl;

output	[7:0]	data_reg0;  //to define eight register 
output	[7:0]	data_reg1;
output 		sda_en;
reg		sda_en;
output 		sda_out;

reg 		reset_n1;
reg 		reset_n2;
reg 		scl_regi0; 
reg 		scl_regi;
reg 		sda_regi0;
reg 		sda_regi;
reg		start_bus_reg;
reg		stop_bus_reg; 
 
reg	[7:0] 	data_reg0;  
reg	[7:0]	data_reg1; 
 
reg	[6:0]	addr_in_reg;
reg	[7:0] 	data_in_reg0;  
reg	[7:0] 	data_in_reg1;
reg	[7:0] 	reg_addr;
reg	[3:0]	main_state; 
reg	[2:0]	addr_in_state;
reg	[3:0]	data_in_state;
reg	[3:0]	data_out_state;
reg	[3:0]	reg_addr_state;

reg		sda_out1;		// ACK
reg 		sda_out2;		// data_to_master
 
reg		write_read;
reg	[1:0]	ack_state; 
 
reg		flag;
 
assign sda_out = flag ? sda_out2 : sda_out1;

// ----------------------------------------------------------------
// reset_n, scl, sda_in -> two stages registered 
always@(posedge clock)
begin
	reset_n1 <= reset_n;
	reset_n2 <= reset_n1; 
end
  
always@(posedge clock or negedge reset_n2)
begin
      if(!reset_n2)
	begin
             scl_regi  <= 1'b0;
             sda_regi  <= 1'b0;
             scl_regi0 <= 1'b0;
             sda_regi0 <= 1'b0;
	end
      else
	begin
             scl_regi0 <= scl_regi;
             scl_regi  <= scl;
             sda_regi0 <= sda_regi;
             sda_regi  <= sda_in;
	end
end

// ----------------------------------------------------------------
// to test start condition: scl=1, sda_in=100

always@(posedge clock or negedge reset_n2)
 begin
  if(!reset_n2)
     start_bus_reg <= 1'b0;
  else
     begin
       if({sda_regi0,sda_regi,sda_in}==3'b100 && {scl_regi0,scl_regi,scl}==3'b111)
            start_bus_reg <= 1'b1;
       else
            start_bus_reg <= 1'b0;
     end
 end
 
// ----------------------------------------------------------------
// to test stop condition: scl=1, sda_in=011

always@(posedge clock or negedge reset_n2)
 begin
  if(!reset_n2)
     stop_bus_reg <= 1'b0;
  else
     begin
       if({sda_regi0,sda_regi,sda_in}==3'b011 && {scl_regi0,scl_regi,scl}==3'b111)
            stop_bus_reg <= 1'b1;
       else
            stop_bus_reg <= 1'b0;
     end
 end
 
//----------------- addr in statemachine -------------------------------
 
parameter addr_in6   		= 3'h0;			// chip_id
parameter addr_in5   		= 3'h1;
parameter addr_in4   		= 3'h2;
parameter addr_in3   		= 3'h3;
parameter addr_in2   		= 3'h4;
parameter addr_in1   		= 3'h5;
parameter addr_in0   		= 3'h6;
parameter addr_end   		= 3'h7;

//----------------- reg addr in statemachine ----------------------------
parameter reg_addr7         =4'h0;
parameter reg_addr6         =4'h1;
parameter reg_addr5         =4'h2;
parameter reg_addr4         =4'h3;
parameter reg_addr3         =4'h4;
parameter reg_addr2         =4'h5;
parameter reg_addr1         =4'h6;
parameter reg_addr0         =4'h7;
parameter reg_addr_end      =4'h8;
       
//----------------- data in statemachine -------------------------------

parameter   data_in7   		= 4'h0;
parameter   data_in6   		= 4'h1;
parameter   data_in5   		= 4'h2;
parameter   data_in4   		= 4'h3;
parameter   data_in3   		= 4'h4;
parameter   data_in2   		= 4'h5;
parameter   data_in1   		= 4'h6;
parameter   data_in0   		= 4'h7;
parameter   data_end   		= 4'h8;

//----------------- data out statemachine -------------------------------
 parameter   data_out7   		= 4'h0;
 parameter   data_out6   		= 4'h1;
 parameter   data_out5   		= 4'h2;
 parameter   data_out4   		= 4'h3;
 parameter   data_out3   		= 4'h4;
 parameter   data_out2   		= 4'h5;
 parameter   data_out1   		= 4'h6;
 parameter   data_out0   		= 4'h7;
 parameter   data_out_end  = 4'h8; 

//----------------- main statemachine ------------------------------
parameter idle                       =4'h0;
parameter addr_read                  =4'h1;
parameter write_read_flag            =4'h2;
parameter addr_ack                   =4'h3;
parameter data_write	                =4'h4;
parameter data_in_ack                =4'h5;			 	 
parameter data_read                  =4'h6;
parameter data_out_ack               =4'h7;
parameter reg_addr_read              =4'h8;
parameter reg_addr_ack               =4'h9;
parameter if_rep_start               =4'ha; 

//------------------------------------------------------------------	
//main state machine

always @(posedge clock or negedge reset_n2) 
	if(!reset_n2)
	begin
		main_state <= idle;
		write_read <= 1'b0;
	end
	else
	begin
		case (main_state)	
		idle:
		begin
					    
			if(start_bus_reg)	// receive start from SDA
			begin
				main_state	<= addr_read;							 
			end
			else					 
			begin
				main_state	<= idle;						     
			end									     					  
		end
						
		addr_read:	// read chip_id from the master
		begin				    
			if(addr_in_state==addr_end)
				main_state	 <= write_read_flag;
			else					        
				main_state	 <= addr_read;
		end	
				
		write_read_flag:	// read R/W flag following chip_id 			         
		begin
			if({scl_regi0,scl_regi,scl}==3'b011)
			begin
				write_read <= sda_in;   	                                                      
				main_state <= addr_ack;
			end	
			else
				main_state <= write_read_flag;			 
		end
				
		addr_ack:	// send chip_id_ack to the master
		begin	
			if({scl_regi0,scl_regi,scl}==3'b011) 
			begin
				if(addr_in_reg==7'b1100110)
					main_state <= reg_addr_read;
				else                  
					main_state <= idle; 
			end
			else
				main_state <= addr_ack;   				       				     
		end	
		reg_addr_read:	// read register address form master
		begin
			if(reg_addr_state==reg_addr_end)
				main_state <= reg_addr_ack;
			else                  
				main_state <= reg_addr_read;
		end
		reg_addr_ack:	// send reg_addr_ack to master
		begin
			if({scl_regi0,scl_regi,scl}==3'b011)	
			begin
				if(sda_out1)	
					main_state <= idle;
				else
				begin
					if(write_read)	 // '1': read			            
						main_state <= data_read;				       
					else		// '0': write
						main_state <= data_write;
				end
			end
			else
				main_state <= reg_addr_ack;	
		end				
		data_write:	// read data from master			
		begin						 
 			if(data_in_state == data_end)			
				main_state <= data_in_ack;
			else
				main_state <= data_write;						    					      
		end
						
		data_in_ack:	// write data_in_ack to master		 
		begin	
			if({scl_regi0,scl_regi,scl}==3'b011)					
				main_state <= if_rep_start;
			else                  
				main_state <= data_in_ack;			
		end	
								 
		data_read:	// write data to master
		begin
			if(data_out_state==data_out_end && {scl_regi0,scl_regi,scl}==3'b100)		              
			begin
				main_state <= data_out_ack;		             
			end                   
			else                  
			begin                 
				main_state <= data_read;			              
			end			            	           
		end
			
		data_out_ack:	// write data_out_ack to master
		begin			             
			if({scl_regi0,scl_regi,scl}==3'b011)
				main_state <= if_rep_start;
			else                  
				main_state <= data_out_ack;
		end
			 
		if_rep_start:	// read restart from master
		begin
			if(stop_bus_reg)
				main_state <= idle;
			else if(start_bus_reg)
				main_state <= reg_addr_read;
			else                  
				main_state <= if_rep_start;			 
		end   
		                        
		default:	main_state <= idle;
		endcase 						 
	end 
	
//------------------------------------------------------------------			
// send chip_id_ack to master           
always @(posedge clock or negedge reset_n2) //addr ack output
begin
	if(!reset_n2)
	begin 
		ack_state <= 2'b00;
		sda_en    <= 1'b0;
		flag      <= 1'b0;
		sda_out1  <= 1'b0; 
	end
	else
	begin
		case(ack_state)
		2'b00:
		begin
			if(main_state==addr_ack && {scl_regi0,scl_regi,scl}==3'b100)    //to ack chip address           
			begin 
				if(addr_in_reg==7'b1100110)   
					sda_out1 <= 1'b0;
				else
					sda_out1 <= 1'b1; 
					 
                                flag      <= 1'b0;    //??1                              
				sda_en    <= 1'b1;
				ack_state <= 2'b11;
			end
			else if(main_state==reg_addr_ack && {scl_regi0,scl_regi,scl}==3'b100)// to ack register address
			begin
				case(reg_addr)
				8'haa:	sda_out1 <= 1'b0; 
				8'h55:	sda_out1 <= 1'b0;
				default:sda_out1 <= 1'b1;
				endcase
				
			    	flag      <= 1'b0;    //??1
				sda_en    <= 1'b1;
				ack_state <= 2'b11;  
			end 					 
			else if(main_state==data_in_ack && {scl_regi0,scl_regi,scl}==3'b100)
			begin
				flag      <= 1'b0;    //??1
				sda_out1  <= 1'b0;    //??2
				sda_en    <= 1'b1;
				ack_state <= 2'b01;
			end
			else if(main_state==data_read && {scl_regi0,scl_regi,scl}==3'b100)
			begin
				flag      <= 1'b1;
				sda_en    <= 1'b1;
				ack_state <= 2'b10;	//?master??????ack???
			end
			else
				sda_en<=1'b0;
			end
		2'b01:
		begin
			if({scl_regi0,scl_regi,scl}==3'b100)
			begin
				sda_en    <= 1'b0;
				ack_state <= 2'b00;
			end
			else
				ack_state <= 2'b01; 
		end
		2'b10:
		begin
			if(main_state==data_read)
				ack_state <= 2'b10;
			else
			begin 
				ack_state <= 2'b00;
				sda_en    <= 1'b0;  
				flag      <= 1'b0;
			end
		end
		
		2'b11:
		begin
			if(main_state==data_read && {scl_regi0,scl_regi,scl}==3'b100)
			begin
				flag      <= 1'b1;
				sda_en    <= 1'b1;
				ack_state <= 2'b10;
			end
			else if(main_state!=data_read && {scl_regi0,scl_regi,scl}==3'b100)
			begin 
				ack_state <= 2'b00;
				sda_en    <= 1'b0;  
			end
			else
				ack_state <= 2'b11;
		end  
		default:	ack_state <= 2'b00;         
		endcase				 
	end
 end

//------------------------------------------------------------------	
//to read Chip_id from master

always @(posedge clock or negedge reset_n2)//to write chip address
	if(!reset_n2)
	begin 
		addr_in_state <= addr_in6;
		addr_in_reg   <= 7'b0000000;
	end
	else if(main_state==addr_read)
	begin
		case(addr_in_state)	
		addr_in6:
		begin
			if({scl_regi0,scl_regi,scl}==3'b011)
			begin
				addr_in_state  <= addr_in5;
				addr_in_reg[6] <= sda_in;
			end
			else
				addr_in_state  <= addr_in6;
		end
			        
		addr_in5:					 
		begin
			if({scl_regi0,scl_regi,scl}==3'b011)
			begin
				addr_in_state  <= addr_in4;
				addr_in_reg[5] <= sda_in;
			end
			else

⌨️ 快捷键说明

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