本帖最后由 何立立 于 2015-6-7 20:59 编辑
最近遇到FPGA复位信号的问题困扰很久,查了相关资料: FPGA设计是基于大量flip-flop或者寄存器的同步系统设计,所以所有这些同步单元的起始状态或者将要返回的状态是一个已知状态(罗辑‘1’或者‘0’)就显得非常重要。在程序中,往往都在端口定义中使用同一个rst_n信号,通常的同步威廉希尔官方网站
通常是由两种复位方式来进行威廉希尔官方网站
的复位,即同步复位和异步复位。同步复位的复位频率同步与寄存器的时钟域,而异步复位按性质,其影响寄存器和寄存器的时钟之间没有确定的时序关系。正因为如此,获取异步复位信号的时序关系是非常困难的。
(1)同步复位:所谓同步复位是基于这样的一个前提,即服务信号只是在寄存器时钟的有效沿时影响该寄存器的状态,同步复位信号是被时钟启动(Launch)和锁存(Latch),而启动和锁存的时钟彼此同步。
总之(复位信号的产生依赖于系统时钟信号);
优缺点:更好的避免亚稳态,但是消耗更多的LE,时钟起到了过滤复位信号小毛刺的作用;
同步复位需要一个脉宽沿展器来保证复位信号有一定脉冲宽度,以确保时钟的有效沿能采样到。同步复位总是需要一个时钟来完成对威廉希尔官方网站
的复位。如果因为某些因素导致复位信号的启动时钟沿错误,那么就会导致整个威廉希尔官方网站
复位功能的失败。
always@(posedge CLK)
begin
if(!RST_n)
b <= 0;
else
b <= a;
end
(2)异步复位:异步复位在威廉希尔官方网站
设计中经常被采用,特别是ASIC设计中。这样的设计非常受欢迎,比如一个异步输入到器件,然后给该异步信号分配全局布线资源,并连接这个异步信号到器件中每一个(几乎所有)寄存器的异步复位引脚。
总之(复位信号和系统时钟信号相互独立,可以发生在任何时候);
优缺点:消耗更少的LE,但是复位信号释放时边沿落入亚稳区域使得态系统不稳定有时上电可以工作,有时上电不能工作,看看是不是复位的问题;
亚稳态是指,原本有效的异步复位信号释放(对低电平有效的复位来说就是上跳沿)与紧跟其后的第一个时钟有效沿之间所必须的最小时间。tremoval(removal time)指的是时钟有效沿与紧跟其后的原本有效的异步复位信号变得无效之间所必须的最小时间。如果异步复位信号的上跳沿(以低电平有效为例)落在trecovery与tremoval的窗口之内,触发器的输出端的值将是不确定的,可能是高电平,可能是低电平,可能处于高低电平之间,也可能处于震荡状态),并且在未知的时刻会固定到高电平或低电平。这种状态就称为亚稳态。 always@(posedge CLK or negedge RST_n)
begin
if(!RST_n)
b <= 0;
else
b <= a;
end
(3)如果确定使用异步复位的话:最好的复位方法“异步复位、同步释放”
既解决了同步复位的资源消耗问题,也解决了异步复位的亚稳态问题。其根本思想,也是将异步信号同步化。
分享两个不错的代码
代码1
- module reset(
- input wire clk,
- input wire rst_in, //未处理的复位信号
- output reg rst_n //处理后的复位信号
- );
- //内部寄存器定义
- reg rst_Buffer; //处理后的复位信号暂存寄存器
- //对复位信号的处理------异步复位,同步释放
- always@(posedge clk or negedge rst_in)//接收数据
- if(!rst_in)
- begin
- rst_Buffer <= 1'b0;
- rst_n <= 1'b0;
- end
- else
- begin
- rst_Buffer <= 1'b1;
- rst_n <= rst_Buffer;
- end
- endmodule
代码2:考虑到系统的初始化可能需要一定的时间,需要写一段Verilog代码进行延时复位,这段代码综合后就是上电自动复位的过程,上电自动复位也要外部硬件提供一个低电平脉冲。第一个进程用来延时,当上电后,延时100ms,以保证FPGA内部达到稳定状态;此时sys_rst_n始终为0,也就是系统时钟处于复位状态中。
当100ms延时结束后,sys_rst_n与系统时钟同步释放,即sys_rst_n拉高,复位结束,系统开始正常工作;[size=15.1999998092651px]
[size=12.8000001907349px]- 1 /**************************************
- 2 * 功能:同步复位产生模块
- 3 * 输入参数:
- 4 * 1. clk: 50M 时钟输入
- 5 * 2. 全局复位信号
- 6 * 输出参数:
- 7 * sys_rst_n:系统全局同步复位信号
- 8 ***************************************/
- 9 module system_ctrl
- 10 (
- 11 input clk,
- 12 input rst_n,
- 13 output sys_rst_n
- 14 );
- 15
- 16 //------------------------------------------
- 17 // Delay 100ms for steady state
- 18 reg [22:0] cnt;
- 19 always@(posedge clk or negedge rst_n)
- 20 begin
- 21 if(!rst_n)
- 22 cnt <= 0;
- 23 else
- 24 begin
- 25 if(cnt < 23'd50_00000) //100ms
- 26 cnt <= cnt+1'b1;
- 27 else
- 28 cnt <= cnt;
- 29 end
- 30 end
- 31
- 32 //------------------------------------------
- 33 //rst_n synchronism
- 34 reg rst_nr0;
- 35 reg rst_nr1;
- 36 always@(posedge clk or negedge rst_n)
- 37 begin
- 38 if(!rst_n)
- 39 begin
- 40 rst_nr0 <= 0;
- 41 rst_nr1 <= 0;
- 42 end
- 43 else if(cnt == 23'd50_00000)
- 44 begin
- 45 rst_nr0 <= 1;
- 46 rst_nr1 <= rst_nr0;
- 47 end
- 48 else
- 49 begin
- 50 rst_nr0 <= 0;
- 51 rst_nr1 <= 0;
- 52 end
- 53 end
- 54
- 55 assign sys_rst_n = rst_nr1;
- 56
- 57 endmodule
系统每次上电,都会由该程序产生一个复位信号,从而避免了手动复位。上电后延时多少才复位就看你自己的需要,可以修改。
(3)复位信号是必须的?
在设计FPGA的时候一般用一个全局复位引脚加上RC来给各个module复位。但是复位信号不是必须的,实际上FPGA上电完成后,本身就处于复位状态,定义变量的时候给寄存器赋值就可以了,可以不用连reset信号。
Xilinx FPGA设计中一般不需要插入全局复位网络,这样我们在写程序的时候就不必每个模块都加入reset端口了,既方便了程序书写,又减小了编译时间,还减少了资源占用。绝大多数情况下,重配置或者上电过程中,所有的触发器和RAM等都可以被预设初始状态,所以全局复位是完全没有必要的,因为所有的信号都已经具有明确的初值。