本文转载自: FPGA技术联盟微信公众号
FPGA频率测量
频率测量在电子设计和测量领域中经常用到,因此对频率测量方法的研究在实际工程应用中具有重要意义。
通常的频率测量方法有三种:直接测量法,间接测量法,等精度测量法。
2、直接测量法
2.1、方法
直接测量法也叫频率测量法,即在固定在时间t内对被测信号的脉冲数进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。
下图中的信号分别为:
sys_clk:系统的基准时钟
gate:根据基准时钟生成的闸门信号,用于生成一个固定的时间(例如1s,方便计算)
clk_fx:被测信号
gate是在基准时钟下生成的固定时间信号,它持续的时间 Tg = sys_clk ✖ 计数个数N(可设置);在gate持续为高的时间内,可使用被测信号clk_fx对其进行计数,计数个数为cnt,则cnt个被测信号的周期即为gate时长。
此种方法的本质是:同样的时间内分别使用两种时钟计时,则有 Tg = Tfx---- Tsys_clk ✖ 计数个数N = Tclk_fx ✖ cnt,公式变换后: clk_fx = cnt ✖ sys_clk / 计数个数N (其中clk_fx为待测信号频率,sys_clk为基准时钟频率)
2.2、误差分析
从图可以看出,在gate为高电平期间,被测信号实际上差不多有六个周期被囊括在内,但是因为被测信号是相对与系统的异步信号,相位不同,第一个周期无法被采样,所以实际采样为5,这样造成的误差为一个被测信号周期。可以预见,这种测量方法带来的测量误差即为一个被测信号周期。
那么理论上测得的准确频率:clk_fxe = cnt ✖ sys_clk / 计数个数N----理论上cnt无误差
实际上测量的频率值:clk_fx = cnt±1 ✖ sys_clk / 计数个数N----cnt会存在一个周期的测量误差
测量误差 = |(clk_fxe - clk_fx)/ clk_fxe | ✖ 100% = 1 / cnt ✖ 100%
所以测得的cnt越大,那么测出来的误差值就小,而cnt越大则代表被测信号的频率越高,所以可以推断该种测量方法适合测量高频信号;此外,选择的闸门时间越长则被测信号的个数越多,同样测量就越精确,但是增大闸门时间又会带来测量时间过长的问题,需要依据具体需求进行取舍。
2.3、Verilog代码
Verilog源码如下:
闸门时间设定为0.5s,非闸门时间也0.5s,则每1秒更新一次测量数据
使用计数器生成闸门时间,闸门时间取反得到非闸门时间
在闸门时间对被测信号计数
在非闸门时间更新测量数据
使用parameter定义参数,方便调用修改
2.4、仿真分析
Testbench:
设计被测信号周期为489*2=978ns,则其理论频率为1/978ns=1022494.88Hz;
上图在闸门时间内测得的被测信号个数cnt_fx为511248,测得被测信号频率为1022496Hz;理论频率=1/978ns=1022494.88Hz(MHz级别)。
可以看出这个测量结果还是比较准确的。因为闸门时间够长,且被测信号自身频率就比较高(约1Mhz)。
接下来更改一下Testbench,比较一下闸门时间对被测信号的影响以及被测信号自身频率高低对测量的影响:
第1个模块:被测信号频率为1022494.88Hz(MHz级别),闸门时间0.5s
第2个模块:被测信号频率为1022494.88Hz(MHz级别),闸门时间0.5ms
第3个模块:被测信号频率为76103.5Hz(KHz级别),闸门时间0.5s
第4个模块:被测信号频率为21.217Hz(Hz级别),闸门时间0.5s
//多变量对比测试
`timescale 1ns/1ns //时间单位/精度
//------------<模块及端口声明>----------------------------------------
module tb_cymometer_direct();
reg sys_clk;
reg sys_rst_n;
reg clk_fx1;
reg clk_fx2;
reg clk_fx3;
reg clk_fx4;
wire [31:0] fre1;
wire [31:0] fre2;
wire [31:0] fre3;
wire [31:0] fre4;
defparam cymometer_direct_inst2.TIME_GATE = 500_000; //重设闸门时间1ms
//------------<例化被测试模块>----------------------------------------
cymometer_direct cymometer_direct_inst1(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.clk_fx (clk_fx1 ),
.fre (fre1 )
);
cymometer_direct cymometer_direct_inst2(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.clk_fx (clk_fx2 ),
.fre (fre2 )
);
cymometer_direct cymometer_direct_inst3(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.clk_fx (clk_fx3 ),
.fre (fre3 )
);
cymometer_direct cymometer_direct_inst4(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.clk_fx (clk_fx4 ),
.fre (fre4 )
);
//------------<例化被测试模块>----------------------------------------
//------------<设置初始测试条件>----------------------------------------
initial begin
sys_clk = 1'b0; //初始时钟为0
sys_rst_n <= 1'b0; //初始复位
clk_fx1 <= 1'b0;
clk_fx2 <= 1'b0;
clk_fx3 <= 1'b0;
clk_fx4 <= 1'b0;
#5 //5个时钟周期后
sys_rst_n <= 1'b1; //拉高复位,系统进入工作状态
end
//------------<设置时钟>----------------------------------------------
always #10 sys_clk = ~sys_clk; //系统时钟周期20ns
always #489 clk_fx1 = ~clk_fx1; //被测信号周期489*2ns,理论频率1022494.88Hz(MHz级别)
always #489 clk_fx2 = ~clk_fx2; //被测信号周期489*2ns,理论频率1022494.88Hz(MHz级别)
always #6570 clk_fx3 = ~clk_fx3; //被测信号周期6570*2ns,理论频率76103.5Hz(KHz级别)
always #23565678 clk_fx4 = ~clk_fx4; //被测信号周期23565678*2ns,理论频率21.217Hz(Hz级别)
endmodule
测量结果如下:
将测量结果整理成下表:
从上表的测试结果可以对直接测量法做出如下总结: