Discussion on some details of dual independent clock fifo
[Copy link]
Recently, I encountered a project that converts received data into local data. The two clocks have basically the same frequency, but there is a 5% deviation and a phase difference.
This is a basic requirement. The general conversion method is to write valid data into the fifo and then read it out with empty. But there is a problem. If the interval between two frames is too short, the data of the two frames will be connected into one frame when reading. The solution is to add the write enable to the fifo, invalidate the enable before and after + data, and also write them into the fifo, and restore them to valid data when restoring.
wire wrfifo_wren;
assign wrfifo_wren = serdes_en_d2 | serdes_en;
wire[32:0] wrfifo_wrdata;
assign wrfifo_wrdata = { serdes_en_d0,rx_data_lock_d0};
Second, regarding the frequency deviation problem, many people use the internal count to judge, but fortunately, Xilinx has prog-empty, which can be programmed to be empty, and select two states. In this way, the signal is pulled low to judge whether the FIFO has written data, and then read it.
.prog_empty(fifo_almost_empty)
);
reg fifo_almost_empty_d0;
reg fifo_almost_empty_d1;
reg fifo_almost_empty_d2;
reg fifo_almost_empty_d3;
reg fifo_almost_empty_d4;
always @(posedge ref_clk)
begin
fifo_almost_empty_d0 <= fifo_almost_empty;
fifo_almost_empty_d1 <= fifo_almost_empty_d0;
fifo_almost_empty_d2 <= fifo_almost_empty_d1;
fifo_almost_empty_d3 <= fifo_almost_empty_d2;
fifo_almost_empty_d4 <= fifo_almost_empty_d3;
end
reg fifo_rd_en_temp;
always @(posedge ref_clk)
begin
if( fifo_almost_empty_d4 == 0)
fifo_rd_en_temp <= 1;
else if( fifo_empty)
fifo_rd_en_temp <= 0;
end
There are three problems. The clock written in the fifo will fluctuate and may stop in the middle, because the power-on reset process will stop the clock, and the clock will also stop in the middle. Many fifos do not explain this clock. The phenomenon found is that the full signal is always a slow signal. Empty is also an empty signal, and the subsequent data cannot be written at all. The solution is to directly judge the full signal and reset the fifo. In this way, the clock is stable and data can be written.
Note that synchronous reset requires more than three clocks of the slowest clock to be valid.
wire lock_fail_rising;
assign lock_fail_rising = (( lock_fail_temp_d1 == 1'b0) & (lock_fail_temp_d0 ==1'b1));
wire fifo_full;
reg fifo_full_d0;
reg fifo_full_d1;
reg fifo_full_d2;
always @(posedge ref_clk)
begin
fifo_full_d0 <= fifo_full;
fifo_full_d1 <= fifo_full_d0;
fifo_full_d2 <= fifo_full_d1;
end
reg lock_fail_rising_d0;
reg lock_fail_rising_d1;
reg lock_fail_rising_d2;
reg lock_fail_rising_d3;
reg lock_fail_rising_d4;
reg lock_fail_rising_d5;
reg lock_fail_rising_d6;
always @(posedge ref_clk)
begin
lock_fail_rising_d0 <= lock_fail_rising| fifo_full_d2;
lock_fail_rising_d1 <= lock_fail_rising_d0;
lock_fail_rising_d2 <= lock_fail_rising_d1;
lock_fail_rising_d3 <= lock_fail_rising_d2;
lock_fail_rising_d4 <= lock_fail_rising_d3;
lock_fail_rising_d5 <= lock_fail_rising_d4;
lock_fail_rising_ d6 <= lock_fail_rising_d5;
end
assign rd_rst = lock_fail_rising_d6 | lock_fail_rising_d0;
|