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

📄 i2c_slave_model.v

📁 一般网站上都有i2c master模块的代码,但很少有slave的代码,这里就是slave的代码,非常有用.
💻 V
字号:
`timescale 1ns/10ps
module i2c_slave_model(sda_en,sda_in,sda_out,scl,reset,chip_address,chip_outdata,chip_inputdata,cpu_cs,cpu_we);
input scl;

input sda_in;
output sda_out;
output sda_en;
input reset;

//-----added today----------
output [7:0] chip_address;
output [7:0] chip_outdata;
input  [7:0] chip_inputdata;
output cpu_cs;
output cpu_we;
reg cpu_cs;
//--------------define the port address-------------------------
parameter I2C_ADR = 7'b0010_000;
//--------------the test memory space---------------------------
reg [7:0] mem [255:0]; 
reg [7:0] mem_adr;   
//--------------general register declearation------------------
reg ld;
reg [2:0] bit_cnt;
reg data_out;
reg write_enable;
assign sda_out=data_out;

parameter idle        = 3'b000;//---------------------0
parameter slave_ack   = 3'b001;//---------------------1
parameter get_mem_adr = 3'b010;//---------------------2
parameter gma_ack     = 3'b011;//---------------------3
parameter data        = 3'b100;//---------------------4
parameter data_ack    = 3'b101;//---------------------5

reg [2:0] state; 
reg [2:0] start_rw;
reg rw;
reg [7:0] mem_do;
reg  sda_o;
wire debug = 1'b1;

//--------------detect the start condition----------------------
reg start;
wire start_reset_n;
assign start_reset_n=reset & (scl | sda_in);
always @(negedge sda_in or negedge start_reset_n)
begin
  if(~start_reset_n)
    start<= 1'b0;
  else
    if(scl)
    start<= 1'b1; 
    else
    start<= 1'b0;
end
//---------------detect the stop condition-----------------------
reg stop;
wire stop_reset_n;
assign stop_reset_n=reset &(scl | sda_in);
always @(posedge sda_in or negedge stop_reset_n)
begin
if(~stop_reset_n)
  stop<=1'b0;
else
  begin
  if(scl)
  stop<=1'b1;
  else
  stop<=1'b0;
  end
end
//--------------shift the receive data bus------------------------
reg [7:0] src;
always @(negedge scl)
begin
  if(start==1'b1) begin
  src <= 8'b0;
  end
  else begin
  src <= {src[6:0],sda_in};
  end
end
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
reg [3:0] count;
always @(posedge scl or posedge start)
begin
if(start)
  count <= 4'b0000;
else
  begin
  if (count==4'd9)
    count <= count;
  else
    count <= count + 1'b1;
  end
end

//---------------judge if the address is my own--------------------
wire my_adr;
assign my_adr = (src[6:0] == I2C_ADR);
//------------------generate done signal--------------------------
wire acc_done;
assign acc_done = !(|bit_cnt);
//-----------generate the muti_reset signal----------------------- 
wire reverse_reset;
assign reverse_reset=~reset;
wire combine;
assign combine = start | stop | reverse_reset;
//-----------the state machine------------------------------------

always @ (negedge scl or posedge combine)
begin
if(combine)
  begin
  sda_o <= 1'b1;
  state <=  idle; // reset statemachine
  ld    <=  1'b1;
  bit_cnt<= 3'b111;
  cpu_cs <= 1'b1;
  end
else	
  begin
 //  ld    <=  1'b0;
//   sda_o <=  1'b1;
   case (state)
   idle: 
         begin
   	     bit_cnt <=  bit_cnt - 3'b1;
		     if(acc_done && my_adr && count==4'd8) begin
		      state <=  slave_ack;
	         sda_o <=  1'b0; // generate i2c_ack
		      data_out <= 1'b0;
			//if(rw)
	        //mem_do <=  mem[mem_adr];
		     end
   	   end
   slave_ack: 
         begin     
	       bit_cnt <= 3'b111; 
           
		    if(rw) begin
	        state <=  data;
	        sda_o <=  1'b0;
	        cpu_cs<=  1'b0;
			  data_out <= mem_do[7];//**//**//**//**//**//**
			  //mem_do <=  mem[mem_adr];=========================================
		     end
	       
			else
	         begin
				state <=  get_mem_adr;
		      ld    <=  1'b1;
	     		sda_o <= 1'b1;
				cpu_cs<=1'b1;
				end
		  end
    get_mem_adr: // wait for memory address
	     begin
		    bit_cnt <=  bit_cnt - 3'b1;
		    if(acc_done)
	         begin
	         state <=  gma_ack;
	         data_out <= 1'b0;   
	         sda_o <=  1'b0; // generate i2c_ack, for valid address
		      cpu_cs<= 1'b1;
				end
    	  end
    gma_ack:
	     begin
	       bit_cnt <= 3'b111;
		    ld    <=  1'b1;
	       mem_adr <=  src; // store memory address
		    state <=  data;
		    sda_o <= 1'b1;
		    cpu_cs<=1'b1;
		  end
    	data: // receive or drive data
	     begin
	       bit_cnt <=  bit_cnt - 3'b1;
		    if(rw)
	         begin
		        sda_o <= 1'b0;
		        data_out <= mem_do[7];//**//**//**//**//**//**

				  if(acc_done) begin
		         mem_adr <=  mem_adr + 8'h1;
		    	   sda_o<=1'b1;
				   cpu_cs <=1'b1;
				   state <= data_ack;
				  end
		        else
				  cpu_cs <= 1'b0;
				end
		  else
		    begin
		  	 if(acc_done)
	          begin
	            state <= data_ack;   
	            //write_enable<=1'b1;
	            sda_o <=  1'b0; // send ack on write, receive ack on read
			      cpu_cs<=1'b1;
				 end
          end
		  
	      end
	  data_ack:
	        begin
	          ld <=  1'b1;
               bit_cnt <= 3'b111;
			if(rw)
	             begin
			    	  
			       if(sda_in) // read operation && master send NACK
	               begin
	                 state <=  idle;
	                 sda_o <=  1'b1;
	                 cpu_cs<= 1'b0;
						end
	             else
	                begin
	                  state <=  data;
	                  sda_o <=  1'b0;
	                	data_out <= mem_do[7];//**//**//**//**//**//**
							//data_out<=1'b0;////////////////////////////////////////////
						   cpu_cs<=1'b0;
						 end
	             end 
			 else
	              begin
	            cpu_cs<=1'b1;    
			      mem_adr <=  mem_adr + 8'h1; 
				   mem[mem_adr] <= src; 
				   state <=  data;
	            sda_o <=  1'b1;
	              end
	         end            
			    
			    
    endcase
  end 
end


//--------------------------------------------------------------------
always @(negedge scl or posedge combine)
begin
if(combine)
  write_enable<=1'b0;
else 
  begin
    if(state==data && acc_done && ~rw)  
      write_enable <= 1'b1;
    else
      write_enable <= 1'b0;
  end
end



always @(posedge scl or negedge reset)
begin
 if(~reset)
 mem_do <= 8'b0;
 else begin
  if(~rw)
   mem_do <= chip_inputdata;//------------------------------5:00
  else
    begin
	   if(state==data_ack || state==slave_ack)
		  mem_do <=chip_inputdata;//--------------------------5:00
		else 
		  mem_do <= {mem_do[6:0], 1'b1};
    end
  end
end

 
assign sda_en=sda_o;
assign chip_address=mem_adr;
assign chip_outdata=src[7:0];
//////////////////////////////////////////////////////////////////////////
always @(posedge scl)
begin
if(count==4'd8)
 rw <=  src[0];
else
 rw <= rw;
end
//////////////////////////////////////////////////////////////////////////
/*
always @(posedge scl)
begin
if(~rw && state==data_ack)
  write_enable <= 1'b1;
else
  write_enable <= 1'b0;
end
*/
assign cpu_we=write_enable;


endmodule

⌨️ 快捷键说明

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