fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)

基于FPGA的spi协议接收模块(从机)高速传输防亚稳态抖动 【fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)】**
1:何为spi? spi是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)
文章图片

2:此文章的应用目标: 1:接收定好协议的spi数据,例如:帧头+数据+帧尾。 帧头+数据。 数据+帧尾。
本文只介绍帧头+数据的这种格式,其他原理相通。
2:快速的spi信号采集,用高频时钟信号采集比较慢的sck时钟信号。
3:技术支撑: 本文将从关机技术点:上升沿检测、稳定数据判断、移位寄存器(数组)、结束接收判断。发进行分析,最后直接给出代码。
普通的上升沿检测:
fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)
文章图片

可知mcu_read_flag=1时为一次上升沿。
但,这种上升沿检测只对信号判断了一次,在信号高速传输过程中,是很不可靠的,可能数据在某个上升沿时刻进行信号的抖动。刚好寄存器锁存了亚稳态的数据,在下个时钟周期立马改变电平。所以,一次判断的上升沿是十分危险。
fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)
文章图片

数组移位寄存器写的上升沿判断可以很好的防止抖动问题。
fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)
文章图片

这种移位寄存器的方法,索存相邻几个周期的电平信号,可以准确,高效的检测出上升沿或者下降沿。
所以,我们检测出上升沿,并锁存了当前的mosi信号后,什么时候停止呢?
比如:指令为0xe3+0x数据、、、、、、共160位(20字节)。
我们可以将每次检测到的数据,在data[159,0]左移一位进行拼接,最后判断高位即可。
fpga|基于fpga的spi协议接收模块(高速传输防亚稳态抖动)
文章图片

4,代码展示:


//此代码为80m时钟采1m的spi数据的接收模块,亲测可效! //当判断接收端为0xE3时,停止接收
`timescale 1ns / 1psmodule spi(
input clk,
input rst_n,
input spi_cs,
input spi_sck,
input spi_mosi, output reg[159:0] data0,
output reg data_done
);
reg [3:0]spi_sck0; //??spi????????????
reg [3:0]spi_cs0;
reg [3:0]spi_mosi0;
reg [159:0] data;
reg [2:0] sum_cs;
reg [2:0] sum_mosi; always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
spi_sck0 <=4’b0;
spi_cs0 <=4’b0;
spi_mosi0 <=4’b0;
end
else
begin
spi_sck0 <={spi_sck0[2:0],spi_sck};
spi_cs0 <={spi_cs0[2:0],spi_cs};
spi_mosi0 <={spi_mosi0[2:0],spi_mosi};
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sum_cs<=3’d0;
sum_mosi<=3’d0;
endelse
begin
sum_cs<=spi_cs0[0]+spi_cs0[1]+spi_cs0[2]+spi_cs0[3];
sum_mosi<=spi_mosi0[0]+spi_mosi0[1]+spi_mosi0[2]+spi_mosi0[3];
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data<=160’d0;
else if((sum_cs>=3’d2)&&(spi_sck04’b0111))
begin
if(sum_mosi>=3’d2)
data<={data[158:0],1’b1};
else
data<={data[158:0],1’b0};
end
else if(spi_cs0
4’d0)
data<=0;
else;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
//data_done<=1’b0;
data0<=160’d0;
end
else if((data[159:152]==8’hE2)||(data[159:152]==8’hE3)||(data[159:152]8’hE4))
begin
//data_done<=1;
data0<=data;
end
else
begin
//data_done<=0;
data0<=data0;
end
endalways@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_done<=1’b0;
else if(spi_cs0
4’b1000)
data_done<=1;
else
data_done<=0;
endendmodule

    推荐阅读