随笔 - 55  文章 - 4  评论 - 7  阅读 - 39107

关于双独立时钟fifo的一些细节探讨

   最近遇到一个项目,就是接收数据转换成本地数据。两个时钟是频率是基本一样,但是存在5%偏差,而且存在相位差。

 这是基本需求。一般转换的办法就是fifo写入有效数据,然后用empty读取出来。但是发现有个问题。就是如果两个帧之间间隔太短了,会导致读取的时候,两帧的数据会连续成一帧数据。解决办法就是把写使能也要加入到fifo中,把前后使能无效+数据,也是写入到fifo,恢复的时候再恢复到有效数据。

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};

    二个关于频率偏差问题,很多人都是内部count 来判断,好在xilinx由prog-empty,可以编程的empty,选择两个状态。这样在拉低信号,判断fifo是否写入数据,再读取。

      .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 

 

三个问题,fifo其中写的时钟会波动,中途可能会停掉,因为上电复位过程会停止时钟,中途也会停止时钟。很多fifo对这个时钟是没有讲解的,发现的现象竟然是full信号一直为慢的信号。empty也是空的信号,后面的数据根本写入不了。解决办法就是,直接判断full信号,复位fifo。这样稳定时钟又可以写入数据。

注意同步复位,要求是最慢的时钟的三个时钟以上有效。

 

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;

posted on   szfpga  阅读(600)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示