异步复位同步释放在实际项目中的应用

博客 分享
0 290
张三
张三 2022-04-12 10:57:53
悬赏:0 积分 收藏

异步复位同步释放在实际项目中的应用

异步复位同步释放在实际项目中的应用

1 引言

最近看了“How do I reset my FPGA?”和一些时序分析的内容,发现之前ov5640图像采集项目中的几个问题:

问题1:用了全局时钟复位,全局复位一般具有高扇出(需要驱动的后级逻辑信号多),因为它需要扩展到设计中的每一个触发器。这样会消耗大量的布线资源,对器件的利用率和时序性能造成不利影响。

问题2:设计全采用了异步复位,对毛刺敏感且复位结束会处于亚稳态。

问题3:在locked1,locked2为低时,时钟是不稳定的,此时送入后续模块的是不稳定的时钟,触发器可能出现功能错误。

那么我们是否需要重构全部的代码呢?其实也没有必要。重构代码很麻烦,需要对所有18个模块进行代码修改,然后重新仿真十八次。

这里我们选择在顶层模块进行复位模块局部化的划分,若实现送入每一个模块的都是异步复位同步释放后的复位信号,保证信号已经同步,本质上也是一样的。而且打两拍之后的复位信号送到时,一方面信号对毛刺不敏感,不会受到脉冲干扰,另外一方面,也相当于复位信号延后了一个或两个clock,最后一个clock时两个locked信号均已稳定,保证系统正常工作。

2 代码

2.1 时钟模块

首先,我们需要确定项目中各模块工作的时钟域。此处有一点注意事项,我们pll2中的输入时钟为pll1生成的100Mhz时钟而非外部时钟,因此调用ip核时需要选用"no buffer"否则会报错。我们调用的两个pll代码如下:

//复位模块复位信号assign  rst_n = locked1 && locked2 && sys_rst_n;//时钟模块1例化clk_gen clk_gen_inst(    .clk_125m            (clk_125m           ),     // output sdram clk    .clk_shift_125m      (clk_shift_125m     ),     // output sdram output clk    .clk_50m             (clk_50m            ),     // output ov5640 clk    .clk_100m            (clk_100m           ),     // output pll2 clk    .clk_24m             (clk_24m            ),     // output ov5640 output clk    .reset               (~pll_rst_n1        ),     // input     .locked              (locked1            ),     // output    .sys_clk             (sys_clk            )      // input sys_clk);//时钟模块2例化clk_gen_hdmi clk_gen_hdmi_inst(    .clk_74m             (clk_74m            ),     // output vga clk    .clk_371m            (clk_371m           ),     // output hdmi tmds clk    .reset               (~pll_rst_n2        ),     // input     .locked              (locked2            ),     // output     .clk_100m            (clk_100m           )      // input clk_100m pll1 output clk_100Mhz);

此处我们会发现一个问题,我们后续模块的复位信号是在时钟稳定的情况下基础上生成的,而实际上pll本身也有复位信号,为了保障整个工程的稳定性,我们需要对pll的复位信号也进行异步复位同步释放

图1 结果时序图

2.2 复位模块

下面是我们设置的复位模块代码,在时钟稳定后, 将工作时钟,外部输入复位信号送入模块后,在各模块时钟下同步后的复位信号输出至各模块

那么这里有个问题,如果在时钟没稳定前,如果有复位信号输入本模块会不会出现亚稳态的问题呢,实际上是不会的,我们可以看复位模块的复位信号,在时钟信号没稳定下,locked1,locked2常为0,不存在信号变化也就不存在亚稳态的问题了。

复位模块复位信号代码如下:

//复位模块复位信号assign  rst_n = locked1 && locked2 && sys_rst_n;

复位模块代码如下:

//**************************************************************************// *** 名称 : sys_reset.v// *** 作者 : 吃豆熊// *** 日期 : 2021-4-1// *** 描述 : 异步复位同步释放模块//**************************************************************************module sys_reset//========================< 端口 >==========================================(    input   wire                sys_clk,                  //系统时钟    input   wire                pll_clk1,     input   wire                pll_clk2,     input   wire                vga_clk,      input   wire                sdram_clk,    input   wire                hdmi_clk,     input   wire                sys_rst_n,                //外界输入复位    input   wire                rst_n,                    //两级时钟pll稳定后复位    output   wire               pll_rst_n1,               //第一级pll复位    异步复位同步释放后复位    output   wire               pll_rst_n2,               //第二级pll复位    output   wire               camera_rst_n,             //摄像头模块复位    output   wire               vga_rst_n,                //vga模块复位    output   wire               sdram_rst_n,              //sdram模块复位    output   wire               hdmi_rst_n                //hdmi模块复位);//========================< 信号 >==========================================//第一级pll复位reg                         pll_rst_n_reg1;reg                         pll_rst_n_reg2;//第二级pll复位reg                         pll_rst_n_reg3;reg                         pll_rst_n_reg4;//摄像头复位reg                         camera_rst_n_reg1;reg                         camera_rst_n_reg2;//sdram复位reg                         sdram_rst_n_reg1;reg                         sdram_rst_n_reg2;//vga复位reg                         vga_rst_n_reg1;reg                         vga_rst_n_reg2;//hdmi复位reg                         hdmi_rst_n_reg1;reg                         hdmi_rst_n_reg2;//==========================================================================//==    信号生成//==========================================================================//第一级pll复位信号always@(posedge pll_clk1 or negedge sys_rst_n )begin    if(sys_rst_n == 1'b0)begin        pll_rst_n_reg1 <= 1'b0;        pll_rst_n_reg2 <= 1'b0;   end  else begin        pll_rst_n_reg1 <= 1'b1;        pll_rst_n_reg2 <= pll_rst_n_reg1;    endend assign pll_rst_n1 = pll_rst_n_reg2;//第二级pll复位信号 always@(posedge pll_clk2 or negedge sys_rst_n )begin    if(sys_rst_n == 1'b0)begin        pll_rst_n_reg3 <= 1'b0;        pll_rst_n_reg4 <= 1'b0;   end  else begin        pll_rst_n_reg3 <= 1'b1;        pll_rst_n_reg4 <= pll_rst_n_reg3;    endend assign pll_rst_n2 = pll_rst_n_reg4;//摄像头复位信号always@(posedge pll_clk2 or negedge rst_n )begin    if(rst_n == 1'b0)begin        camera_rst_n_reg1 <= 1'b0;        camera_rst_n_reg2 <= 1'b0;   end  else begin        camera_rst_n_reg1 <= 1'b1;        camera_rst_n_reg2 <= camera_rst_n_reg1;    endend assign camera_rst_n = camera_rst_n_reg2; //sdram复位信号always@(posedge sdram_clk or negedge rst_n )begin    if(rst_n == 1'b0)begin        sdram_rst_n_reg1 <= 1'b0;        sdram_rst_n_reg2 <= 1'b0;   end  else begin        sdram_rst_n_reg1 <= 1'b1;        sdram_rst_n_reg2 <= sdram_rst_n_reg1;    endend assign sdram_rst_n = sdram_rst_n_reg2; //vga复位信号always@(posedge vga_clk or negedge rst_n )begin    if(rst_n == 1'b0)begin        vga_rst_n_reg1 <= 1'b0;        vga_rst_n_reg2 <= 1'b0;   end  else begin        vga_rst_n_reg1 <= 1'b1;        vga_rst_n_reg2 <= vga_rst_n_reg1;    endend assign vga_rst_n = vga_rst_n_reg2; //hdmi复位信号always@(posedge hdmi_clk or negedge rst_n )begin    if(rst_n == 1'b0)begin        hdmi_rst_n_reg1 <= 1'b0;        hdmi_rst_n_reg2 <= 1'b0;   end  else begin        hdmi_rst_n_reg1 <= 1'b1;        hdmi_rst_n_reg2 <= hdmi_rst_n_reg1;    endend assign hdmi_rst_n = hdmi_rst_n_reg2;endmodule

最后是我们的顶层模块例化代码:

//局部复位划分模块sys_reset sys_reset_inst(    .sys_clk             (sys_clk            ),    .pll_clk1            (sys_clk            ),    .pll_clk2            (clk_100m           ),    .vga_clk             (clk_74m            ),    .sdram_clk           (clk_125m           ),    .hdmi_clk            (clk_74m            ),    //输入复位           .sys_rst_n           (sys_rst_n          ),    .rst_n               (rst_n              ),    //输出异步复位同步释放后复位信号        .pll_rst_n1          (pll_rst_n1         ),    .pll_rst_n2          (pll_rst_n2         ),    .camera_rst_n        (camera_rst_n       ),    .vga_rst_n           (vga_rst_n          ),    .sdram_rst_n         (sdram_rst_n        ),    .hdmi_rst_n          (hdmi_rst_n         ));

随后我们就可以将输出的复位信号输入各个模块使用,且理论上由于均为wire型,因此与在每个模块内进行同步毫无区别。同时也避免了需要在顶层模块进行时钟复位信号的同步,保证了顶层模块的简洁。

---

原创教程,转载请注明出处吃豆熊-异步复位同步释放

参考资料:深入浅出玩转fpga

posted @ 2022-04-12 10:05 吃豆熊 阅读(34) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员