module spi_master
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire data_in0 ,
input wire data_in1 ,
input wire data_in2 ,
input wire data_in3 ,
input wire data_in4 ,
input wire data_in5 ,
input wire data_in6 ,
input wire data_in7 ,
input wire pclk ,
input wire vsync ,
input wire hsync ,
output wire [7:0] data_out,
output reg rd_req,
output reg wr_req,
output wire rd_empty,
output wire wr_full,
output reg [7:0] data_in ,
output reg cs_n , //片选信号
output reg sck , //串行时钟
output reg mosi , //主输出从输入数据
output reg handshake_start , //开始传输标志信号
output reg handshake_end , //结束传输标志信号
output reg [3:0] cnt_sck ,
output reg [2:0] cnt_bit , //比特计数器
output reg [3:0] state
);
//parameter define
parameter IDLE = 4'b0001 , //初始状态
WR_EN = 4'b0010; //写状态
//以pclk为时钟采样输入data0~7信号
always @(posedge pclk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
data_in <= 0;
else begin
data_in[0] <= data_in0;
data_in[1] <= data_in1;
data_in[2] <= data_in2;
data_in[3] <= data_in3;
data_in[4] <= data_in4;
data_in[5] <= data_in5;
data_in[6] <= data_in6;
data_in[7] <= data_in7;
end
end
fifo fifo_inst (
.data ( data_in ),
.rdclk ( sck ),
.rdreq ( rd_req ),
.wrclk ( pclk ),
.wrreq ( wr_req ),
.q ( data_out ),
.rdempty ( rd_empty ),
.wrfull ( wr_full )
);
//cnt_sck:串行时钟计数器,用以生成串行时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sck <= 2'd0;
else if(cnt_sck == 4'd9)
cnt_sck <= 1'b0;
else if(state == WR_EN)
cnt_sck <= cnt_sck + 1'b1;
else
cnt_sck <= cnt_sck;
//cs_n:片选信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cs_n <= 1'b1;
else if(state == WR_EN)
cs_n <= 1'b0;
else
cs_n <= 1'b1;
//sck:输出串行时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sck <= 1'b0;
else if(cnt_sck == 2'd0)
sck <= 1'b0;
else if(cnt_sck == 4'd6)
sck <= 1'b0;
else if(cnt_sck == 2'd2)
sck <= 1'b1;
//cnt_bit:高低位对调,控制mosi输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else if(cnt_sck == 2'd2)
cnt_bit <= cnt_bit + 1'b1;
//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0) begin
state <= IDLE;
wr_req <= 1'b0;
end
else
case(state)
IDLE: if(sys_rst_n == 1'b1) begin
state <= WR_EN;
wr_req <= 1'b1; //按键按下状态跳转的同时使能FIFO写入信号
end
WR_EN: state <= WR_EN;
default: state <= IDLE;
endcase
//初始化FIFO读写使能信号,rd_req信号是状态变为IDLE的后一拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_req <= 1'b0;
else if(state == WR_EN)
rd_req <= 1'b1;
else
rd_req <= 1'b0;
//mosi:两段式状态机第二段,逻辑输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
mosi <= 1'b0;
else if((state == WR_EN) && (cnt_sck == 4'b0110))
mosi <= data_out[7-cnt_bit]; //写使能指令
else if((state == WR_EN) && (rd_empty == 1'b1))
mosi <= 8'b1111_1111; //发送一个全1数据包表示摄像头传输结束
else if(state == IDLE)
mosi <= 1'b0;
//handshake_start信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
handshake_start <= 1'b0;
else if((state == WR_EN) && (cnt_bit == 1'b1) && (cnt_sck == 1'b0))
handshake_start <= 1'b1;
else
handshake_start <= 1'b0;
//handshake_end信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
handshake_end <= 1'b0;
else if((state == WR_EN) && (cnt_bit == 1'b0) && (cnt_sck == 1'b0))
handshake_end <= 1'b1;
else
handshake_end <= 1'b0;
endmodule
`timescale 1ns/1ns
module spi_slave
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire key1 , //按键输入信号
input wire key2 ,
input wire data_in0 ,
input wire data_in1 ,
input wire data_in2 ,
input wire data_in3 ,
input wire data_in4 ,
input wire data_in5 ,
input wire data_in6 ,
input wire data_in7 ,
input wire pclk ,
input wire vsync ,
input wire hsync ,
output wire [7:0] data_out,
output reg rd_req,
output reg wr_req,
output wire rd_empty,
output wire wr_full,
output reg [7:0] data_in ,
input wire cs_n , //片选信号
input wire sck , //串行时钟
output reg mosi , //主输出从输入数据
output reg handshake_start , //开始传输标志信号
output reg handshake_end , //结束传输标志信号
output reg [2:0] cnt_bit , //比特计数器
output reg [3:0] state
);
//parameter define
parameter IDLE = 4'b0001 , //初始状态
WR_EN = 4'b0010; //写状态
parameter WR_EN_INST = 8'b0000_0110; //写使能指令
reg daq_clk;
//通过pclk在sys_clk下打拍产生一个采样时钟daq_clk来保证采样时数据已经稳定
//适用条件是f_pclk < f_sys_clk
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
daq_clk <= 1'b0;
else if((pclk == 1'b1) && (state == WR_EN))
daq_clk <= 1'b1;
else
daq_clk <= 1'b0;
end
//以pclk为时钟采样输入data0~7信号
always @(posedge daq_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
data_in <= 0;
else begin
data_in[0] <= data_in0;
data_in[1] <= data_in1;
data_in[2] <= data_in2;
data_in[3] <= data_in3;
data_in[4] <= data_in4;
data_in[5] <= data_in5;
data_in[6] <= data_in6;
data_in[7] <= data_in7;
end
end
fifo fifo_inst (
.data ( data_in ),
.rdclk ( sck ),
.rdreq ( rd_req ),
.wrclk ( daq_clk ),
.wrreq ( wr_req ),
.q ( data_out ),
.rdempty ( rd_empty ),
.wrfull ( wr_full )
);
//cnt_bit:高低位对调,控制mosi输出
always@(posedge sck or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else
cnt_bit <= cnt_bit + 1'b1;
//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0) begin
state <= IDLE;
wr_req <= 1'b0;
end
else
case(state)
IDLE: if(sys_rst_n == 1'b1) begin
state <= WR_EN;
wr_req <= 1'b1; //按键按下状态跳转的同时使能FIFO写入信号
end
WR_EN: state <= WR_EN;
default: state <= IDLE;
endcase
//初始化FIFO读写使能信号,rd_req信号是状态变为IDLE的后一拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_req <= 1'b0;
else if(state == WR_EN)
rd_req <= 1'b1;
else
rd_req <= 1'b0;
//mosi:两段式状态机第二段,逻辑输出
always@(posedge sck or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
mosi <= 1'b0;
else if(state == WR_EN)
mosi <= data_out[7-cnt_bit]; //写使能指令
else if((state == WR_EN) && (rd_empty == 1'b1))
mosi <= 8'b1111_1111; //发送一个全1数据包表示摄像头传输结束
else if(state == IDLE)
mosi <= 1'b0;
//handshake_start信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
handshake_start <= 1'b0;
else if((state == WR_EN) && (cnt_bit == 3'b010))
handshake_start <= 1'b1;
else
handshake_start <= 1'b0;
//handshake_end信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
handshake_end <= 1'b0;
else if((state == WR_EN) && (cnt_bit == 3'b001))
handshake_end <= 1'b1;
else
handshake_end <= 1'b0;
endmodule
`timescale 1ns/1ns
module tb_spi_slave();
//wire define
wire cs_n;
reg sck ;
wire mosi ;
//reg define
reg clk ;
reg rst_n ;
reg key1 ;
reg key2 ;
wire [3:0] state ; //状态机状态
wire [2:0] cnt_bit ; //比特计数器
reg data_in0 ;
reg data_in1 ;
reg data_in2 ;
reg data_in3 ;
reg data_in4 ;
reg data_in5 ;
reg data_in6 ;
reg data_in7 ;
wire [7:0] data_out;
wire rd_req;
wire wr_req;
wire rd_empty;
wire wr_full;
reg pclk ;
reg vsync ;
reg hsync ;
wire handshake_start ;
wire handshake_end ;
wire [7:0] data_in;
//时钟、复位信号、模拟按键信号
initial
begin
clk = 0;
sck = 0;
rst_n <= 0;
key1 <= 0;
key2 <= 0;
data_in0 <= 1;
data_in1 <= 0;
data_in2 <= 0;
data_in3 <= 1;
data_in4 <= 0;
data_in5 <= 0;
data_in6 <= 1;
data_in7 <= 0;
pclk <= 0;
vsync <= 0;
hsync <= 0;
#100
rst_n <= 1;
#1000
key1 <= 1;
#20
key1 <= 0;
#1000
data_in0 <= 1;
data_in1 <= 0;
data_in2 <= 1;
data_in3 <= 0;
data_in4 <= 1;
data_in5 <= 0;
data_in6 <= 1;
data_in7 <= 0;
#10
#1000
data_in0 <= 1;
data_in1 <= 0;
data_in2 <= 0;
data_in3 <= 0;
data_in4 <= 0;
data_in5 <= 0;
data_in6 <= 1;
data_in7 <= 0;
#10000
key2 <= 1;
#20
key2 <= 0;
end
always #10 clk <= ~clk;
always #20 pclk <= ~pclk;
always #50 sck <= ~sck;
//-------------spi_flash_erase-------------
spi_slave spi_slave_inst
(
.sys_clk (clk ), //系统时钟,频率50MHz
.sys_rst_n (rst_n ), //复位信号,低电平有效
.key1 (key1 ), //按键输入信号
.key2 (key2 ),
.data_in0 (data_in0 ),
.data_in1 (data_in1 ),
.data_in2 (data_in2 ),
.data_in3 (data_in3 ),
.data_in4 (data_in4 ),
.data_in5 (data_in5 ),
.data_in6 (data_in6 ),
.data_in7 (data_in7 ),
.pclk (pclk),
.vsync (vsync),
.hsync (hsync),
.data_out (data_out),
.rd_req (rd_req),
.wr_req (wr_req),
.rd_empty (rd_empty),
.wr_full (wr_full),
.data_in (data_in ),
.sck (sck ), //串行时钟
.cs_n (cs_n ), //片选信号
.mosi (mosi ), //主输出从输入数据
.handshake_start (handshake_start ),
.handshake_end (handshake_end ),
.cnt_bit (cnt_bit ),
.state (state )
);
endmodule