fido有单和双之分,双的话是双时钟,以下引自——小梅哥
单时钟FIFO:
单时钟FIFO常用于片内数据交互,例如,在FPGA的控制下从外部传感器读取到的一连串传感器数据,首先被写入FIFO中,然后再以UART串口的数据发送速率将数据依次发送出去。由于传感器的单次读取数据可能很快,但并不是时刻都需要采集数据,例如某传感器使用SPI接口的协议,FPGA以2M的SPI数据速率从该传感器中读取20个数据,然后以9600的波特率通过串口发送出去。此过程每秒钟执行一次。因为2M的数据速率远高于串口9600的波特率,因此需要将从传感器中采集到的数据首先用FIFO缓存起来,然后再以串口的数据速率缓慢发送出去。这里,由于传感器数据的读取和串口数据的发送都是可以同步于同一个时钟的,因此可以使用单时钟结构的FIFO来实现此功能。
双时钟FIFO:
双时钟FIFO的一个典型应用就是异步数据的收发。
所谓异步数据是指数据的发送端和接收端分别同步与不同的时钟域,使用双时钟FIFO的独立的读写时钟结构,能够将不同时钟域中的数据同步到所需的时钟域系统中。例如,在一个高速数据采集系统中,实现将高速ADC采集的数据通过千兆以太网发送到PC机。ADC的采样时钟(CLK1)由外部专用锁相环芯片产生,则高速ADC采样得到的数据就是同步于该时钟信号的,在FPGA内部,如果FPGA工作时钟(CLK2)是由独立的时钟芯片加片上锁相环产生的,则CLK1和CLK2就是两个不同。域的时钟,他们的频率和相位没有必然的联系,假如CLK1为65M,CLK2为125M,那么就不能使用125M的数据来直接采集65M速率的数据,因为两者数据速率不匹配,在采集过程中会出现包括亚稳态问题在内的一系列问题,所以这里就可以使用一个具备
双时钟结构的FIFO来进行异步数据的收发
利用quartus自带的IP核实现:fifo
FIFO属于寄存器类型的
然后就是进行配置了
设置好之后,编写TEST.v文件
`timescale 1ns/1ps
`define wrclk_period 20
`define rdclk_period 10
module mydcfifo_tb;
//source define
reg [15:0] data;
reg rdclk;
reg rdreq;
reg wrclk;
reg wrreq;
//probe define
wire [7:0] q;
wire rdempty;
wire [8:0] rdusedw;
wire wrfull;
wire [7:0] wrusedw;
//instant user module
mydcfifo mydcfifo(
.data(data),
.rdclk(rdclk),
.rdreq(rdreq),
.wrclk(wrclk),
.wrreq(wrreq),
.q(q),
.rdempty(rdempty),
.rdusedw(rdusedw),
.wrfull(wrfull),
.wrusedw(wrusedw)
);
//generater clock
initial wrclk = 1;
always #(`wrclk_period/2)wrclk = ~wrclk;
initial rdclk = 1;
always #(`rdclk_period/2)rdclk = ~rdclk;
integer i;
initial begin
data = 0;
rdreq = 0;
wrreq = 0;
#(`wrclk_period*20 + 1);
for (i=0;i <= 255 ;i = i + 1)begin
wrreq = 1;
data = i + 1024;
#`wrclk_period;
end
wrreq = 0;
#(`rdclk_period*20);
for (i=0;i <= 511 ;i = i + 1)begin
rdreq = 1;
#`rdclk_period;
end
rdreq = 0;
#(`rdclk_period*20);
$stop;
end
endmodule
然后设置modelsim软件进行,测试
然后运行测试
这里用的是双核的,
写入为16位,频率为20ns,
读入为8位,频率为10ns
这样FIFO就完成了时钟域的同步
写入时:
读取时:
由此可以得出结论:
FIFO同步时钟,消除亚稳态