[FPGA]数字等精度频率计设计II[门控信号长度自适应(对上一个的优化)]
文章目录
理论分析
改进目标
提高低频时的测量速度。
改进方案
上一篇文章的第二种方案。
约定一个门控信号长度上限,比如1s。
在输出门控信号时进行clk计时,如果超过1s,则在下一个待测信号上升沿提前结束门控信号。
得到门控信号后对待测信号和clk同时计数,计数结果送入计算模块计算。
程序设计
模块设计
如果把计数和计算模块放在一起的话,则这个模块代码会比较多,略显臃肿。
如果分开,只需要写一个计数模块如何实例化两次即可,但是需要考虑模块间的时序问题。
各有利弊,不过都是小问题。此处选择的是分开的设计。
右侧设置的所有端口均为采集信号时方便。
代码实现
Gate模块
本设计改进主要在Gate模块门控信号的生成上。
在门控信号生成的同时使用GATE_CLK_CNT计时,当计时时间超过额定时间时在下一个待测信号上升沿结束门控信号。此处使用的结束方法是改变门控信号计数器,调整计数器值到quantity + 2’b10,则在下一个待测信号上升沿处计数值为0,再下一个待测信号上升沿处门控信号结束。
GATE_CLK_CNT计时并不是严格记录门控信号的长度,而是从门控信号下降沿检测信号NEG_GATE结束后开始计时,即计的是两个NEG_GATE信号之间的时间,大概是整个门控信号生成周期减去一个待测信号周期。这样同时也可以起到对门控信号长度进行监测和截断的作用。
注意写代码的时候一个reg只在一个always中更改,即第一个只计GATE_CLK_CNT,第二个计时并根据GATE_CLK_CNT对GATE_CNT和NEG_GATE进行更新,第三个always生成门控信号。这样更加清晰明确。
Gate
module Gate( CLK , SIGNAL , RST , GATE , NEG_GATE );
input CLK;
input SIGNAL;
input RST;
output GATE;
output NEG_GATE; // the negedge of gate
parameter quantity = 16'b0001_0011_1000_1000; // 5000
//parameter time_length = 28'b0001_0111_1101_0111_1000_0011_1110; // 0.5 seconds -1 , 24_999_999 clks
reg GATE;
reg NEG_GATE;//_fx;
reg [16-1:0] GATE_CNT;
reg [28-1:0] GATE_CLK_CNT; // make sure that Gate wont last longer than 1s
//GATE_CLK_CNT//
always @ ( posedge CLK or negedge RST ) begin
if (!RST)
GATE_CLK_CNT <= 28'b0;
else if ( NEG_GATE )
GATE_CLK_CNT <= 28'b0;
else
GATE_CLK_CNT <= GATE_CLK_CNT + 1'b1;
end
//GATE_CNT & NEG_GATE//
always @ ( posedge SIGNAL or negedge RST ) begin
if (!RST) begin
GATE_CNT <= 16'b0;
NEG_GATE <= 1'b0;
end
else if (GATE_CNT == 16'b0) begin
GATE_CNT <= GATE_CNT + 1'b1;
NEG_GATE <= 1'b1;
end
else if (GATE_CNT == quantity + 2'b10) begin
GATE_CNT <= 16'b0;
NEG_GATE <= 1'b0;
end
// else if(GATE_CLK_CNT >= time_length) begin // fku parameter
else if(GATE_CLK_CNT >= 28'b0001_0111_1101_0111_1000_0011_1110) begin
if (GATE_CNT >= 1'b1) begin
GATE_CNT <= quantity + 2'b10;
NEG_GATE <= 1'b0;
end
end
else begin
GATE_CNT <= GATE_CNT + 1'b1;
NEG_GATE <= 1'b0;
end
end
//GATE//
always @ ( posedge SIGNAL or negedge RST ) begin
if (!RST)
GATE <= 1'b0;
else if (GATE_CNT <= 2'b10) // for the gap of adjacent gates
GATE <= 1'b0;
else if (GATE_CNT <= quantity + 2'b10)
GATE <= 1'b1;
else
GATE <= 1'b0;
end
endmodule
这个模块第三个always的第三个else if处有一句注释。其实一个设计我在三天前就已经完成了,这个优化我在两天前也就已经做完了设计和代码编写,但在测试的时候这句else if一直不起作用。我两天内换了几种逻辑设计,将GATE_CLK_CNT的判断放在GATE处或是更改time_length的值,但都没用。直到我在测试时为了方便修改,将time_length换成了具体的数值,他就可以了!parameter的这个time_length真tm是惊天大内鬼。我换了几个参数值,只要将具体数值放进if里来就可以正常工作,放time_length这个名字就完犊子了,我改了两天就揪出这么个内鬼,也没搞明白为什么。在网上查资料也没有找到任何关于parameter对参数设置的要求,如有高见还望不吝赐教。
Counter模块
Counter模块在上一次写好了,不需要怎么修改。
Counter
module Counter( SIGNAL , RST , GATE , NEG_GATE , CNT_READY , SIGNAL_CNT );
input SIGNAL;
input RST;
input GATE;
input NEG_GATE;
output CNT_READY;
output [32-1:0] SIGNAL_CNT;
reg CNT_READY;
reg [32-1:0] SIGNAL_CNT;
reg [32-1:0] SIGNAL_CNT_temp;
always @ ( posedge SIGNAL or negedge RST ) begin
if (!RST) begin
SIGNAL_CNT_temp <= 32'b0;
SIGNAL_CNT <= 32'b0;
CNT_READY <= 1'b0;
end
else if (GATE) begin // when gate , count
SIGNAL_CNT_temp <= SIGNAL_CNT_temp + 1'b1;
CNT_READY <= 1'b0;
end
else if (NEG_GATE) begin // when gate end , count end
if (SIGNAL_CNT_temp)
SIGNAL_CNT <= SIGNAL_CNT_temp; // until next count end , the ans will stay on bus for read
SIGNAL_CNT_temp <= 32'b0;
CNT_READY <= 1'b1;
end
end
endmodule
Calculation模块
Calculation
module Calculation( EN1 , EN2 , RST , CNT_fx , CNT_f0 , ANS );
input EN1;
input EN2;
input RST;
input [32-1:0] CNT_fx;
input [32-1:0] CNT_f0;
output [40-1:0] ANS;
localparam CLK_fs = 26'b0010_1111_1010_1111_0000_1000_0000;
reg [40-1:0] ANS;
always @ ( posedge EN1 or posedge EN2 or negedge RST ) begin
if (!RST)
ANS <= 32'b0;
else if (EN1)
if (EN2) begin
ANS <= CLK_fs * CNT_fx / CNT_f0 ;
end
end
endmodule
对于Counter模块和Calculation模块之间的时序问题要注意。
因为两个Counter模块是对不同的信号进行计数,待测信号周期较长而基准时钟周期较短,所以基准时钟先输出计数结果,待测信号后输出计数结果。要等到两个计数结果都输出,Calculation再去接收计数值并计算结果。同时也就需要Counter模块对输出结果进行保持。有两种保持方法。第一种简单,SIGNAL_CNT_temp非零时赋值给SIGNAL_CNT。如果不使用这个非零赋值,观察Counter模块的输出时序可知,基准时钟的计数模块需要一个长度为基准时钟周期的NEG_GATE信号。这个信号的生成我最少需要写两个always,所以采用了第一种方法。感兴趣可以自己尝试。
测试验证
测量精度基本没有问题。并且可以观察到,低频时的门控信号对应的待测信号周期数也自适应地减少,从而降低了低频时的测量时间。
低频测量时间如下(手计):
频率/Hz | 测量时间/s |
---|---|
1 | 8 |
2 | 6.5 |
3 | 3.3 |
4 | 2.8 |
5~10 | 2.3~2.0 |
频率再高则基本在2s以内,100Hz以上基本在1s以内。可以测量速度说有了大的提升。
继续改进
问题
较低频的测量速度虽然得到了很大改善,但仍然不是很理想。
改进
- 试一试上一篇文章的第一个改进方案。
- 调整GATE的输出时序:
目前的输出时序为:
(没错我找不到合适的软件所以这个时序图就是用excel画的XD)
其中前面的空档是为了信号稳定和门控信号之间的区分间隔,而且把间隔都放在前面比较容易写逻辑。XD
可以去掉最前面的档并把门控信号之间的区分间隔放在后面。
改进后的输出时序:
但去掉最前面的空档似乎牺牲了最开始一个周期的测量精度。在假设需要3次刷新可以得到精确的数值的,换得的仅仅是1至5Hz时速度快些,超过5Hz时仅仅将信号之间的空格放在后面就可以满足要求了,而且也无法将1至4Hz时的测量时间压缩到1s内,所以好像不太划算。
本设计并没有这么改。因为我按这个时序推了下,1Hz应该需要5s左右时间。但实际上我将时序改成这样后去测试,1Hz的测量时间长达27s,而且在1kHz至50kHz的范围内测量速度也明显降低了。现在还没找到原因,大概我时序写错了。找到原因再改。而且就算能达到理论的5s,5s也是远远不够的,所以下次试一试第一种方案。