SPI Verilog HDL

SPI Verilog HDL

RTL 代码

/**********************************************
time:2019.07.30
author: lion A
version SPI001
*************************************************/

module spi(
clk,
rstn,
rd,
wr,
data_in,
data_out,
miso,
mosi,
spi_cs,
spi_clk,
wr_done,
rd_done
);


input clk;//system clk 50MHZ
input rstn;//active low
input rd;
input wr;
input [7:0]data_in;
input miso;

output reg mosi;
output reg [7:0]data_out;
output spi_clk;
output reg spi_cs;
output wr_done;
output rd_done;

reg [2:0] send_cnt;
reg [2:0] receive_cnt;

reg wr_done_r,rd_done_r;

assign spi_clk=clk;
assign wr_done=(send_cnt==3'd7)?1:0;
assign rd_done=(receive_cnt==3'd7)?1:0;

wire spi_wr_en=wr&wr_done_r;
wire spi_rd_en=rd&rd_done_r;

/////////////////////////////////
always@(posedge clk)
  if(!rstn)
    wr_done_r <=1'b0;
  else
    wr_done_r <=~wr_done;
/////////////////////////////////
always@(posedge clk)
  if(!rstn)
    rd_done_r <=1'b0;
  else
    rd_done_r <=~rd_done;
	
	

always@(posedge clk)
  if(!rstn)
    begin send_cnt <=3'd0;spi_cs <=1'b1;end
  else if(spi_wr_en)
    begin
	     case(send_cnt)
		 3'd0:
		     begin
			      send_cnt <=3'd1;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[7];
			 end
		 3'd1:
		     begin
			      send_cnt <=3'd2;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[6];
			 end
		 3'd2:
		     begin
			      send_cnt <=3'd3;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[5];
			 end
		 3'd3:
		     begin
			      send_cnt <=3'd4;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[4];
			 end
		 3'd4:
		     begin
			      send_cnt <=3'd5;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[3];
			 end
		 3'd5:
		     begin
			      send_cnt <=3'd6;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[2];
			 end
		 3'd6:
		     begin
			      send_cnt <=3'd7;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[1];
			 end
		 3'd7:
		     begin
			      send_cnt <=3'd0;
				  spi_cs   <=1'b0;
				  mosi     <=data_in[0];
			 end
        endcase			 
	end
   else
    begin
	     send_cnt <=3'd0;
		 spi_cs <=1'b1;
		 mosi <=1'b0;
	end

always@(posedge clk)
  if(!rstn)
    begin
	receive_cnt <=3'd0;
	spi_cs <=1'b1;
	end
  else if(spi_rd_en)
    begin
	     case(receive_cnt)
		 3'd0:
		     begin
			      receive_cnt <=3'd1;
				  spi_cs   <=1'b0;
				  data_out[7] <=miso;
			 end
		 3'd1:
		     begin
			      receive_cnt <=3'd2;
				  spi_cs   <=1'b0;
				  data_out[6] <=miso;
			 end
		 3'd2:
		     begin
			      receive_cnt <=3'd3;
				  spi_cs   <=1'b0;
				  data_out[5] <=miso;
			 end
		 3'd3:
		     begin
			      receive_cnt <=3'd4;
				  spi_cs   <=1'b0;
				  data_out[4] <=miso;
			 end
		 3'd4:
		     begin
			      receive_cnt <=3'd5;
				  spi_cs   <=1'b0;
				  data_out[3] <=miso;
			 end
		 3'd5:
		     begin
			      receive_cnt <=3'd6;
				  spi_cs   <=1'b0;
				  data_out[2] <=miso;
			 end
		 3'd6:
		     begin
			      receive_cnt <=3'd7;
				  spi_cs   <=1'b0;
				  data_out[1] <=miso;
			 end
		 3'd7:
		     begin
			      receive_cnt <=3'd0;
				  spi_cs   <=1'b0;
				  data_out[0] <=miso;
			 end	
        endcase			 
	end
   else
    begin
	     receive_cnt <=3'd0;
		 spi_cs <=1'b1;
		 mosi <=1'b0;
		 data_out <=7'b0;
	end
	
endmodule 

测试代码

/*****************************
this is a test code for spi function

***************************************/
`timescale 1 ns/ 1ns
`define clk_periond 100

module spi_tb;


reg clk;//system clk 50MHZ
reg rstn;//active low
reg rd;
reg wr;
reg [7:0]data_in;
reg miso;

wire mosi;
wire [7:0]data_out;
wire spi_clk;
wire spi_cs;
wire wr_done;
wire rd_done;

spi spi(
.clk(clk),
.rstn(rstn),
.rd(rd),
.wr(wr),
.data_in(data_in),
.data_out(data_out),
.miso(miso),
.mosi(mosi),
.spi_cs(spi_cs),
.spi_clk(spi_clk),
.wr_done(wr_done),
.rd_done(rd_done)
);


always #(`clk_periond/2) clk =~clk;

initial 
       begin
	        clk=0;
			rstn=1;
			data_in=8'ha3;
			
			#(`clk_periond+20)
			  rstn=0;
			  
			#(`clk_periond*5)
			  rstn=1;
			 
			#(`clk_periond*5)
			  rd=1;
			  wr=1;
			#(`clk_periond*9)
			  rd=0;
              wr=0;
            #(`clk_periond*10)
              $stop;		  
	   
	   end
	   
    always@(posedge spi_clk)
       if(rd|wr)
          miso =mosi;
       else
          miso =0;   
    
    
    endmodule

你可能感兴趣的:(verilog)