声明:本篇文章面向在已对SPI的四种时序有所了解的人
我们采用SPI3模式以及将FPGA作从机,STM32作主机的方式讲解,在STM32控制部分采用的是半双工模式,但其实半双工与全双工区别不大, 稍加修改即可
本片文章是接续上篇文章的,如果未浏览上一篇文章的,可以在此跳转SPI驱动代码详解SPI代码详解FPGA-verilog部分(FPGA+STM32)(二)
本文是FPGA通过SPI接收的数据做出应答的模块,比如改变ADC采样率,将ADC采集的数据放在RAM中和从RAM中取出再发送给单片机
module samplingCtrl (
input clk,
input rstn,
input [31:0] FCW,
input en,
input [11:0] AD9226_Din_0,
input [11:0] AD9226_Din_1,
input [11:0] AD9226_Din_2,
input [6:0] rd_addr,
output reg clk_sampling_1,
output reg clk_sampling_2,
output reg clk_sampling_0,
output reg [11:0] AD9226_Dout_0,
output reg [11:0] AD9226_Dout_1,
output reg [11:0] AD9226_Dout_2,
output reg busy
);
localparam OFFSET_VALID = 7'd0;
wire clk_sampling;
reg [1:0] r_en;
wire pos_en;
reg [1:0] r_clk_sampling;
wire pos_clk_sampling;
wire neg_clk_sampling;
reg wr_en;
reg [6:0] wr_addr;
wire [15:0] ram_dout0;
wire [15:0] ram_dout1;
wire [15:0] ram_dout2;
always @(posedge clk , negedge rstn)
begin
if(!rstn)
r_en <= 2'd0;
else
r_en <= {r_en[0], en};
end
assign pos_en = (!r_en[1]) &(r_en[0]);
always @(posedge clk , negedge rstn)
begin
if(!rstn)
r_clk_sampling <= 2'd0;
else
r_clk_sampling <= {r_clk_sampling[0], clk_sampling};
end
assign pos_clk_sampling = (!r_clk_sampling[1]) &(r_clk_sampling[0]);
assign neg_clk_sampling = (r_clk_sampling[1]) &(!r_clk_sampling[0]);
reg [3:0] state_c;
reg [3:0] state_n;
localparam s_idle = 4'b0001;
localparam s_waitPos = 4'b0010;
localparam s_store = 4'b0100;
localparam s_addAddr = 4'b1000;
wire idle_2_waitPos;
wire waitPos_2_store;
wire store_2_addAddr;
wire addAddr_2_waitPos;
wire addAddr_2_idle;
always @(posedge clk , negedge rstn)
begin
if(!rstn)
state_c <= s_idle;
else
state_c <= state_n;
end
always @(*)
begin
case (state_c)
s_idle:
if(idle_2_waitPos)
state_n <= s_waitPos;
else
state_n <= state_c;
s_waitPos:
if(waitPos_2_store)
state_n <= s_store;
else
state_n <= state_c;
s_store:
if(store_2_addAddr)
state_n <= s_addAddr;
else
state_n <= state_c;
s_addAddr:
if(addAddr_2_waitPos)
state_n <= s_waitPos;
else if(addAddr_2_idle)
state_n <= s_idle;
else
state_n <= state_c;
default:
state_n = s_idle;
endcase
end
assign idle_2_waitPos = (state_c == s_idle) &&(pos_en);
assign waitPos_2_store = (state_c == s_waitPos) &&(pos_clk_sampling);
assign store_2_addAddr = (state_c == s_store) &&(neg_clk_sampling);
assign addAddr_2_waitPos = (state_c == s_addAddr) &&(wr_addr < (64 + OFFSET_VALID) );
assign addAddr_2_idle = (state_c == s_addAddr) &&(wr_addr >= (64 + OFFSET_VALID) );
always @(posedge clk , negedge rstn)
begin
if(!rstn)
begin
busy <= 1'b0;
wr_en <= 1'b0;
wr_addr <= 7'd0;
end
else
case (state_n)
s_idle:
begin
busy <= 1'b0;
wr_en <= 1'b0;
wr_addr <= 7'd0;
end
s_waitPos:
begin
busy <= 1'b1;
wr_en <= 1'b0;
wr_addr <= wr_addr;
end
s_store:
begin
busy <= 1'b1;
wr_en <= 1'b1;
wr_addr <= wr_addr;
end
s_addAddr:
begin
busy <= 1'b1;
wr_en <= 1'b0;
wr_addr <= wr_addr + 7'd1;
end
default:
begin
busy <= 1'b0;
wr_en <= 1'b0;
wr_addr <= 7'd0;
end
endcase
end
always @(posedge clk , negedge rstn)
begin
if(!rstn)
begin
clk_sampling_0 <= 1'b0;
clk_sampling_1 <= 1'b0;
clk_sampling_2 <= 1'b0;
end
else
begin
clk_sampling_0 <= clk_sampling;
clk_sampling_1 <= clk_sampling;
clk_sampling_2 <= clk_sampling;
end
end
always @(posedge clk , negedge rstn)
begin
if(!rstn)
begin
AD9226_Dout_0 <= 12'd0;
AD9226_Dout_1 <= 12'd0;
AD9226_Dout_2 <= 12'd0;
end
else
begin
AD9226_Dout_0 <= ram_dout0[11:0];
AD9226_Dout_1 <= ram_dout1[11:0];
AD9226_Dout_2 <= ram_dout2[11:0];
end
end
clkSamplingGen clkSamplingGen_inst(
.clk_50M(clk),
.rstn(rstn),
.pos_en(pos_en),
.FCW(FCW),
.clk_sampling(clk_sampling)
);
ram_2p ram_2p_inst0 (
.clock ( clk ),
.data ( {4'd0, AD9226_Din_0} ),
.rdaddress ( rd_addr ),
.wraddress ( wr_addr[6:0] ),
.wren ( wr_en ),
.q ( ram_dout0 )
);
ram_2p ram_2p_inst1 (
.clock ( clk ),
.data ( {4'd0, AD9226_Din_1} ),
.rdaddress ( rd_addr ),
.wraddress ( wr_addr[6:0] ),
.wren ( wr_en ),
.q ( ram_dout1 )
);
ram_2p ram_2p_inst2 (
.clock ( clk ),
.data ( {4'd0, AD9226_Din_2} ),
.rdaddress ( rd_addr ),
.wraddress ( wr_addr[6:0] ),
.wren ( wr_en ),
.q ( ram_dout2 )
);
endmodule
|