-
SPI是全双工,串行,同步的协议。
SPI先发高位再发低位。 -
有四种模式,通常采用0和3,因为支持flash读写。
其中0模式实现如下
将MOSI和MISO连接一起形成回环测试。发送1010 10 10
采用第一种模式,空闲状态为低电平
module spi_drive#(
parameter P_DATA_WIDTH = 8 ,
P_READ_DATA_WIDTH = 8 ,
P_CPOL = 0 ,
P_CPHL = 0
)(
input i_clk ,
input i_rst ,
output o_spi_clk ,//o是主??
output o_spi_cs ,
output o_spi_mosi ,//主机发???
input i_spi_miso ,//从机发???
input [P_DATA_WIDTH - 1 :0] i_user_data ,//从机发???数??
input i_user_valid ,//从机数据是否有效 可以当恒定的??
output o_user_ready ,
output [P_READ_DATA_WIDTH - 1:0] o_user_read_data ,
output o_user_read_valid
);
/***************function**************/
/***************parameter*************/
/***************port******************/
/***************mechine***************/
/***************reg*******************/
reg ro_spi_clk ;
reg ro_spi_cs ;
reg ro_spi_mosi ;
reg ro_user_ready ;
reg [P_DATA_WIDTH - 1:0] r_user_data ;
reg r_run ;
reg [15:0] r_cnt ;
reg r_spi_cnt ;
reg [P_READ_DATA_WIDTH - 1:0] ro_user_read_data ;
reg ro_user_read_valid ;
reg r_run_1d ;
/***************wire******************/
wire w_user_active ;
wire w_run_negedge ;
/***************component*************/
/***************assign****************/
assign o_spi_clk = ro_spi_clk ;
assign o_spi_cs = ro_spi_cs ;
assign o_spi_mosi = ro_spi_mosi ;
assign o_user_ready = ro_user_ready ;
assign o_user_read_data = ro_user_read_data ;
assign o_user_read_valid = ro_user_read_valid ;
assign w_run_negedge = !r_run & r_run_1d ; //??测下降沿
/***************always****************/
assign w_user_active = i_user_valid & o_user_ready;
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_user_ready <='d1;
else if(w_user_active)
ro_user_ready <= 'd0;
else if(w_run_negedge)
ro_user_ready <= 'd1;
else
ro_user_ready <= ro_user_ready;
end
always@(posedge i_clk,posedge i_rst) //用户发???过来的数据
begin
if(i_rst)
r_user_data <= 'd0;
else if(w_user_active)
r_user_data <= i_user_data;
else if(r_spi_cnt)
r_user_data <= r_user_data << 1;
else
r_user_data <= r_user_data;
end
always@(posedge i_clk,posedge i_rst) //运行状???
begin
if(i_rst)
r_run <= 'd0;
else if(r_spi_cnt && r_cnt == 7)
r_run <= 'd0;
else if(w_user_active)
r_run <= 'd1;
else
r_run <= r_run;
end
always@(posedge i_clk,posedge i_rst) //运行状???慢??拍,??测下降沿
begin
if(i_rst)
r_run_1d <= 'd0;
else
r_run_1d <= r_run;
end
always@(posedge i_clk,posedge i_rst) //写了多少数???的计数?? spi的长?? spi数据的长度
begin
if(i_rst)
r_cnt <= 'd0;
else if(r_spi_cnt && r_cnt == 7)
r_cnt <= 'd0;
else if(r_spi_cnt)
r_cnt <= r_cnt + 1;
else
r_cnt <= r_cnt;
end
always@(posedge i_clk,posedge i_rst) //
begin
if(i_rst)
r_spi_cnt <= 'd0;
else if(r_run)
r_spi_cnt <= r_spi_cnt + 1;
else
r_spi_cnt <= 'd0;
end
always@(posedge i_clk,posedge i_rst)//
begin
if(i_rst)
ro_spi_clk <= P_CPOL;
else if(r_run)
ro_spi_clk <= ~ro_spi_clk;
else
ro_spi_clk <= P_CPOL;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_spi_cs <= 'd1;
else if(w_user_active)
ro_spi_cs <= 'd0;
else if(!r_run)
ro_spi_cs <= 'd1;
else
ro_spi_cs <= ro_spi_cs;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_spi_mosi <= 'd0; //主机发???,从机接收主句output 从机input
else if(w_user_active)
ro_spi_mosi <= i_user_data[P_DATA_WIDTH - 1];
else if(r_spi_cnt)
ro_spi_mosi <= r_user_data[P_DATA_WIDTH - 2];//因为提前接收的问题导致应该先发???次高位
else
ro_spi_mosi <= ro_spi_mosi;
end
always@(posedge ro_spi_clk,posedge i_rst)
begin
if(i_rst)
ro_user_read_data <= 'd0;
// else if()
else
ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2 : 0],i_spi_miso};//从机发???的数据
// else if()
// else
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_user_read_valid <= 'd0;
else if(r_spi_cnt && r_cnt == 7)
ro_user_read_valid <= 'd1;
else
ro_user_read_valid <= 'd0;
end
endmodule