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