1、毛刺产生的原因
信号在 IC/FPGA 器件中通过逻辑单元连线时,是存在延时的。延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。(这里的“同时发生跳变”指源信号,到达目的端口的时间由于上述各种原因可能不同,所以产生了“竞争冒险”,其实就是于期望值不同,产生了bug,这个bug可能与后面的东西息息相关,危害很大,必须解决。)
2、竞争与冒险
信号由于经由不同路径传输达到某一汇合点的时间有先有后的现象,就称之为竞争,英文名Race;由于竞争现象所引起的电路输出发生瞬间错误的现象,就称之为冒险,英文名Hazard或者Risk。有竞争不一定有冒险,但出现了冒险就一定存在竞争。发生冒险时往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。
竞争产生的原因一般有两种:
(1)门电路两个输入信号同时向相反的逻辑电平跳变,由于信号发生变化需要时间,且门电路的传输时间可能也不尽相同,导致信号变化后到达门级的时间不同,产生了竞争。如下图:
(2)同一信号经不同路径到达终点的时间有先有后的现象(或者不同信号变化不同步)。例如y=A,如下图:
3、解决毛刺的方法:
硬件:加小电容,由于FPGA内部没有电容,无法过滤毛刺,所以我们就给他加一个(好像是这个原因,我之前看到的,找不到了,至于电容为什么能过滤毛刺,我不清楚,大家感兴趣可以自己查找资料)
软件:增加时序逻辑,由于毛刺现象发生在组合逻辑,且一般持续时间都比较短,所以我们增加时序逻辑采样正确的值或者过滤错误的值即可。
(1)增加D触发器
原理就是用一个D触发器去读带毛刺的信号,利用 D 触发器对输入信号的毛刺不敏感的特点,去除信号中的毛刺。在实际中,对于简单的逻辑电路,尤其是对信号中发生在非时钟跳变沿的毛刺信号,去除效果非常的明显。 但是如果毛刺信号发生在时钟信号的跳变沿,D 触发器的效果就没有那么明显了(加 D触发器以后的输出 q,仍含有毛刺)。另外,D 触发器的使用还会给系统带来一定的延时,特别是在系统级数较多的情况下,延时也将变大,因此在使用 D 触发器去除毛刺的时候,一定要视情况而定,并不是所有的毛刺都可以用 D 触发器来消除。
(2)同步电路设计
由于大多数毛刺都比较短(大概几个纳秒),只要毛刺不出现在时钟跳变沿,毛刺信号就不会对系统造成危害了。因此一般认为,只要在整个系统中使用同一个时钟就可以实现系统同步。但是,时钟信号在 FPGA 器件中传递时是有延时的,我们无法预知时钟跳变沿的精确位置。也就是说我们无法保证在某个时钟的跳变沿读取的数据是一个稳定的数据,尤其是在多级设计中,这个问题就更加突出。因此,做到真正的“同步”就是去除毛刺信号的关键。所以同步的关键就是保证在时钟的跳变沿读取的数据是稳定的数据而不是毛刺数据。
下面介绍两种具体的信号同步方法。
信号延时同步法
信号延时法,它的原理就是在两级信号传递的过程中加一个延时环节,从而保证在下一个模块中读取到的数据是稳定后的数据,即不包含毛刺信号。这里所指的信号延时可以是数据信号的延时,也可以是时钟信号的延时。这种方法的局限性很大,因为要视不同电路为不同情况,不同电路所加的延时可能不同。
状态机控制
使用状态机也可以实现信号的同步和消除毛刺的目的。在数据传递比较复杂的多模块系统中,由状态机在特定的时刻分别发出控制特定模块的时钟信号或者模块使能信号,状态机的循环控制就可以使得整个系统协调运作,同时减少毛刺信号。那么只要我们在状态机的触发时间上加以处理,就可以避免竞争冒险,从而抑制毛刺的产生。
(3)格雷码计数器
前面说过毛刺产生的原因之一就是多个信号同时发生变化,那么只要保证同一时刻只有一个信号发生变化即可预防毛刺,格雷码就符合这个特点。
4、代码实现:
(1)原理
过滤单边毛刺:
过滤负毛刺,主要用于过滤低电平复位毛刺,不足一个时钟周期的情况下通过打两拍,即两级D触发器,将每一级触发器的结果相或即可,若过滤大于1个周期,小于2个周期的毛刺,就打三拍,以此类推。电路图如下所示:
过滤不足一周期的负毛刺对应的波形图如下所示:
过滤正毛刺则是将结果相与,用于过滤高电平复位毛刺。
(2)代码
代码实现:
module trace(
input clk,
input rst,
input din,
output dout
);
reg dout1,dout2;
always @ (posedge clk or negedge rst) begin
if(!rst) begin
dout1 <= 1'b0;
dout2 <= 1'b0;
end else begin
dout1 <= din;
dout2 <= dout1;
end
end
assign dout = dout1&dout2;
endmodule
仿真激励:
module trace_tb();
reg clk;
reg rst;
reg din;
wire dout;
initial begin
clk=1'b0;rst=1'b1;
#5 rst=1'b0;
#10 rst=1'b1;
end
initial begin
din=1'b0;
#5 din=1'b1;
#10 din=1'b0;
#10 din=1'b1;
#10 din=1'b0;
#20 din=1'b1;
#5 din=1'b0;
end
always #10 clk = ~clk;
trace u1(clk,rst,din,dout);
endmodule
仿真波形:第一根黄线代表检测到复位,第二根黄线代表检测到毛刺,第三根黄线虽然没有检测到毛刺,但由于毛刺信号小于一周期,所以自然而然被过滤了。
至于多个周期的毛刺和过滤正毛刺的代码和上面的大同小异,很好修改,我就不写了。
——————————————————————————————————————————
上面讲的只是过滤单边毛刺,大家是不是很好奇正负毛刺同时检测的电路是什么样子的。其实这和按键消抖非常类似,我下面粘贴的链接也有,大家可以看看或网上查阅,后续我会出。