声明:本篇文章面向在已对SPI的四种时序有所了解的人
我们采用SPI3模式以及将FPGA作从机,STM32作主机的方式讲解,在STM32控制部分采用的是半双工模式,但其实半双工与全双工区别不大,
稍加修改即可
本片文章是接续上篇文章的,如果未浏览上一篇文章的,可以在此跳转SPI代码详解FPGA-verilog部分(FPGA+STM32)(一)
本部分代码相当于对SPI模块的一个驱动,从SPI模块中进出的数据都要经过spi_mp 这个模块这一层壳
模块工作流程:单片机先拉低cs_cmd,发送的命令dcmd送给sel,sel的值若是0 ~ 7则表明下一次的FPGA发送从输入口Din0 ~ Din7中选择,sel的值若是128 ~ 135则表明下一次的FPGA接收从输出口Dout0 ~ Dout7中选择。|这里的输入输出口是针对SPI模块来说的,因为spi模块接收的数据是要给FPGA其他模块用的,所以SPI模块从单片机中接收的数据送出去就叫做Dout口|
module spi_mp #(
parameter cmd_width = 8,
parameter data_width = 32
)
(
input clk,
input rstn,
input spi_scl,
input spi_sdi,
input spi_cs_cmd,
input spi_cs_data,
input [data_width - 1:0] Din0,
input [data_width - 1:0] Din1,
input [data_width - 1:0] Din2,
input [data_width - 1:0] Din3,
input [data_width - 1:0] Din4,
input [data_width - 1:0] Din5,
input [data_width - 1:0] Din6,
input [data_width - 1:0] Din7,
output spi_sdo,
output reg [cmd_width - 1:0] sel,
output reg [data_width - 1:0] Dout0,
output reg [data_width - 1:0] Dout1,
output reg [data_width - 1:0] Dout2,
output reg [data_width - 1:0] Dout3,
output reg [data_width - 1:0] Dout4,
output reg [data_width - 1:0] Dout5,
output reg [data_width - 1:0] Dout6,
output reg [data_width - 1:0] Dout7
);
reg [data_width - 1:0] r_Dout;
reg [data_width - 1:0] r_din;
wire w_cmd_done;
wire w_data_done;
wire [cmd_width - 1:0] w_dcmd;
wire [data_width - 1:0] w_dout;
spi spi_inst(
.clk(clk),
.rstn(rstn),
.spi_scl(spi_scl),
.spi_sdi(spi_sdi),
.spi_cs_cmd(spi_cs_cmd),
.spi_cs_data(spi_cs_data),
.din(r_Dout),
.spi_sdo(spi_sdo),
.cmd_done(w_cmd_done),
.data_done(w_data_done),
.dcmd(w_dcmd),
.dout(w_dout)
);
//
always @(posedge clk , negedge rstn) begin
if(!rstn)
sel <= 0;
else if(w_cmd_done)
sel <= w_dcmd;
else
sel <= sel;
end
always @(posedge clk , negedge rstn) begin
if(!rstn)
r_din <= 0;
else if(w_data_done)
if(sel > 127)
r_din <= w_dout;
else
r_din <= r_din;
else
r_din <= r_din;
end
//
always @(posedge clk , negedge rstn) begin
if(!rstn)
r_Dout <= 0;
else
case (sel)
0: r_Dout <= Din0;
1: r_Dout <= Din1;
2: r_Dout <= Din2;
3: r_Dout <= Din3;
4: r_Dout <= Din4;
5: r_Dout <= Din5;
6: r_Dout <= Din6;
7: r_Dout <= Din7;
default: r_Dout <= r_Dout;
endcase
end
//
always @(posedge clk , negedge rstn) begin
if(!rstn) begin
Dout0 <= 0;
Dout1 <= 0;
Dout2 <= 0;
Dout3 <= 0;
Dout4 <= 0;
Dout5 <= 0;
Dout6 <= 0;
Dout7 <= 0;
end
else
case (sel)
128: Dout0 <= r_din;
129: Dout1 <= r_din;
130: Dout2 <= r_din;
131: Dout3 <= r_din;
132: Dout4 <= r_din;
133: Dout5 <= r_din;
134: Dout6 <= r_din;
135: Dout7 <= r_din;
default: begin
Dout0 <= Dout0;
Dout1 <= Dout1;
Dout2 <= Dout2;
Dout3 <= Dout3;
Dout4 <= Dout4;
Dout5 <= Dout5;
Dout6 <= Dout6;
Dout7 <= Dout7;
end
endcase
end
endmodule