新闻  |   论坛  |   博客  |   在线研讨会
【转】FPGA中几种简易滤波器的写法
502593045 | 2014-10-27 16:52:51    阅读:1703   发布文章

本文使用D-FF制作一个简单的滤波器,方便在FPGA使用,可以避掉因PCB板设计不良而产生的glitch。

Introduction

有很多论文专门在讨论数字滤波器,本文提出的方法,只是刚好适用在FPGA上,而且颇为简单,可以作为一般用途的滤波用。

背景是在最近工作时,需要将RTL在FPGA上验证,可能是因为PCB版的设计不良,所以导致有一根reset信号会在某种状况下产生glitch,通常reset信号都是异步设计,所以只要reset有一点点的low信号,就可能造成整个系统reset,long term solution当然是去改版子,但因为急着要验证RTL,所以short term solution只好先从FPGA下手,想办法去滤掉这个glitch。

在LA与SignalTap观察下,这根reset信号的glitch都很短,远小于50Mhz的周期20 ns,首先假设我们想滤掉小于1个周期的glitch,共有以下几种可能:

case 1glitch小于1个周期,且在clk正缘时有敲到

FPGA中几种简易滤波器的写法



 

host_rst_n原本是根reset信号,low active,因为PCB版问题产生极短glitch,导致整个系统reset,假设刚好被clk的正缘敲到,当使host_rst_n信号delay过 两级后,再将第一级与第二级作OR(稍后会有完整的原理图),可以发现成功的滤掉了host_rst_n原本的glitch。

 

case 2glitch小于1个周期,但clk正缘没有敲到

FPGA中几种简易滤波器的写法

 

host_rst_n在delay第一级就已经滤掉了,所以之后都没问题,目前看来这个solution能滤掉小于1个周期的glitch

目前为止,这个能滤掉小于1个周期glitch的原理图如下:

   FPGA中几种简易滤波器的写法

case 3glitch大于1个周期且小于2个周期,但clk正缘时有敲到

FPGA中几种简易滤波器的写法

 

由以上波形图推导可以发现,光使用host_rst_n_d1 | host_rst_n_d2是不够的,仍然会产生glitch,必须多delay一级到host_rst_n_d3,并且将host_rst_n_d1 | host_rst_n_d2 | host_rst_n_d3才能完全消除glitch。

case 4glitch大于1个周期且小于2个周期,但clk正缘没有敲到

FPGA中几种简易滤波器的写法

 

 

由以上波形图推导可以发现,其实host_rst_n_d1 | host_rst_n_d2就足够消除glitch,并不一定得delay到第3级,当然多了第3级去OR也不会有错。

目前为止,这个能滤掉大于1个周期且小于2个周期glitch的原理图如下:

FPGA中几种简易滤波器的写法

 

Summary

若要滤掉小于n个周期的glitch,需要delay (n+1)级,并将delay 1、delay 2....delay (n+1)级的register一起做OR,即可消除此glitch。

这样就结束了吗?还没这么单纯,因为这种解法,会有其『副作用』 ,接下来就要谈谈其副作用部份。

case 5 glitch小于1个周期,但连续2个周期出现,且在clk正缘时有敲到

FPGA中几种简易滤波器的写法

 

由以上波形图推导可以发现,连续2个小于1个周期的glitch,很意外的也在这个delay 3级作OR的解法中也被滤掉了,同理可推得连续3个周期都出现glitch,要delay 4级作OR才可滤掉,推导的方式相同,在此省略。

Summary

若要滤掉n个小于1个周期的glitch,需要delay (n+1)级,并将delay 1、delay 2....delay (n+1)级的register一起做OR,即可消除此glitch。

所以若你想滤掉小于2个周期的glitch,而采用了delay 3级作OR的方式,就会一同将连续2个小于1个周期的glitch一起滤掉,这没有好或不好,就端看你datasheet对reset信号的规定,通常reset low信号都会很长,所以应该不至于将正常的reset信号滤掉,重点是你要知道这种solution的一些限制,进而自己决定是否该使用。

使用Verilog表示

原理图已经确定后,接着要讨论如何使用Verilog表示,我们以delay 3级作OR的原理图为例:

 

10  module digital_filter_1 (
11   clk_50M,
12   rst_n,
13   host_rst_n,
14   host_rst_n_filter
15 );
16
17  input  clk_50M;
18  input  rst_n;
19  input  host_rst_n;
20  output host_rst_n_filter;
21
22  reg host_rst_n_d1;
23  reg host_rst_n_d2;
24  reg host_rst_n_d3;
25
26  always@(posedge clk_50M or negedge rst_n) begin
27   if (~rst_n) begin
28     host_rst_n_d1 <= 1'b1;
29     host_rst_n_d2 <= 1'b1;
30     host_rst_n_d3 <= 1'b1;
31   end
32   else begin
33     host_rst_n_d1 <= host_rst_n;
34     host_rst_n_d2 <= host_rst_n_d1;
35     host_rst_n_d3 <= host_rst_n_d2;
36   end
37  end
38
39  assign host_rst_n_filter = host_rst_n_d1 | host_rst_n_d2 | host_rst_n_d3;
40
41  endmodule

这是一般初学者的写法,就乖乖的将原理图用Verilog去表示,无论是Quartus II、Synplify Pro或者Design Compiler都可以看的懂,并且合成出正确的电路。

digital_filter_2.v / Verilog 

 1
 9
10  module digital_filter_2 (
11   clk_50M,
12   rst_n,
13   host_rst_n,
14   host_rst_n_filter
15 );
16
17  input  clk_50M;
18  input  rst_n;
19  input  host_rst_n;
20  output host_rst_n_filter;
21
22  reg [2:0] host_rst_n_dly;
23
24  always@(posedge clk_50M or negedge rst_n) begin
25   if (~rst_n)
26     host_rst_n_dly <= 3'b111;
27    else
28     host_rst_n_dly <= {host_rst_n_dly[1:0], host_rst_n};
29  end
30
31  assign host_rst_n_filter = |host_rst_n_dly;
32
33  endmodule

这是较有经验的写法,初学者可能会看不懂,这种写法在Quartus II、Synplify Pro与Design Compiler都可以看的懂,也可以合成出正确的电路。

22行

reg [2:0] host_rst_n_dly;

因为要delay 3级,所以宣告3 bit的host_rst_n_dly,事实上,host_rst_n_dly[0]就相当于host_rst_n_d1,host_rst_n_dly[1]就相当于host_rst_n_d2,host_rst_n_dly[2]就相当于host_rst_n_d3。

28行

host_rst_n_dly <= {host_rst_n_dly[1:0], host_rst_n};

事实上这一行可以拆成以下3行

host_rst_n_dly[0] <= host_rst_n;
host_rst_n_dly[1] <= host_rst_n_dly[0];
host_rst_n_dly[2] <= host_rst_n_dly[1];

因为host_rst_n_dly[0]相当于host_rst_n_d1,host_rst_n_dly[1]相当于host_rst_n_d2,host_rst_n_dly[2]相当于host_rst_n_d3,所以也相当于第一种写法的以下3行。

host_rst_n_d1 <= host_rst_n;
host_rst_n_d2 <= host_rst_n_d1;
host_rst_n_d3 <= host_rst_n_d2;

事实上这个技巧在RTL相当常见, 算是Verilog的惯用写法,要让自己习惯并熟析这种写法。

31行

assign host_rst_n_filter = |host_rst_n_dly;

这里用到了Verilog的一个独门语法:reduction operator,这在VHDL与C/C++都没有,这一行相当于以下的写法。

assign host_rst_n_filter = host_rst_n_dly[2] | host_rst_n_dly[1] | host_rst_n_dly[0];

也就是一个vector内,每个bit彼此去做OR。

以前在学Verilog时,一直不懂为什么Verilog要特别提供reduction写法,今天总算在这里看到reduction写法的威力了。

Quartus II合成结果

 

以上两种写法,经过Quartus II合成后的结果都一样,事实上,Quartus II合成的结果就是第2种写法所描述的结果。

Conclusion
本博文提出一个简单的方法,可以在使用FPGA做RTL验证时,暂时将因PCB版设计不良所产生的 glitch做滤波,但这种方式所带来的副作用必须特别小心,是否因此而导致不符合datasheet规定,也示范了其Verilog的实现方式,其中包 含了一些Verilog的小技巧。

此外,我们可以发现整篇博文的思路为:波形图推导 –> 原理图 –> Verilog,所以Verilog code绝对不是凭空生出来的,若初学者直接看到第二种写法的Verilog code,一定会看不懂它的意义是什么,此时我们可以逆推回去,首先将其所代表的硬件原理图画出来,运气好在这个阶段就可以了解,若还是不懂,就实际搭配 波形图,应该就更可以了解code所要表达的意义。这点与C语言有很大的差别,C语言基本上只要语法能懂,再将其所要表达的流程图画出来,就能了解其所要 表达的算法,至于他所代表的汇编语言为何我们不知道也没关系。但是Verilog是硬件描述语言,其所描述的是一个实体硬件,Verilog或VHDL只 是试着用code的方式表示那个硬件而已,所以在写code之前要以经先有原理图,而不是直接去写连自己都不知道结果为什么硬件的code,这是写 Verilog与写C最大的差异。


转自:http://blog.sina.com.cn/s/blog_62926c230100qc2c.html
参与讨论
登录后参与讨论
虾虽在江湖,江湖却没有关于虾的传说!
推荐文章
最近访客