**文章摘要:**借助于QuartusII PLL_IP核产生一个任意频率被测时钟信号,设计一个等精度测量模块,通过其处理后,再数码管上显示出六位的测量频率数值,验证测量的准确度。
**关键词:**Verilog HDL;等精度频率测量;数码管;PLL_IP核
最终框图:
频率计,即频率计数器,专用于测量被测信号频率,基本工作原理就是当被测信号在特定时间段T内的周期个数为N时,则被测信号的频率freq可以通过公式freq=N/T计算得出。
在EDA设计中,常见的频率测量方法包括频率测量法(适合高频被测信号)、周期测量法(适合低频被测信号)和等精度测量法。频率测量法是通过统计单位时间内上升沿(或下降沿等)来计算频率,而周期测量法是通过测量上升沿(或下降沿等)的时间间隔来计算频率。等精度测量法与前两种不同,其在于门控时间的设定。
【基础原理】
在等精度测量法中,门控时间的长度并非固定,而会根据被测时钟信号的周期进行调整,保证其为被测时钟信号周期的整数倍。在这样的参考门限范围内,同时记录标准时钟和被测时钟信号的周期数,随后通过计算两者的比例关系,得到被测信号的时钟频率。
预先设定一个软件门限,在此门限划定测量参考范围,通过对测量信号Measured_sig
上升沿触发,可得到一个相对的参考门限REF_threshold
,其是被测时钟周期的整数倍,消除了被测信号存在的±1个时钟周期误差。
测量方法:
参考门限范围内,计数被测信号周期个数为N;给一个高频(固定频率Fs)标准信号,并计数得到其在同样门限下周期个数为Y;借助 N * 1 / Fn = Y * 1/Fs 可知被测信号频率 Fn = Fs * N / Y。
f为被测信号频率的测量值,f'为实际频率,参考门限T;
测量误差β = | f'-f | / f' * 100%,若忽略标准信号的误差,可得到f' = N / (Y ± ΔY)* Fs;
联立得到 β = ΔY/Y *100% ≤ 1/Y = 1/(Fs * T)
**结论:**被测信号的频率接近或高于标准信号,测量的误差会大,就是说,增大标准信号频率,或者扩大软件门限,这样可提高测量精度。
【时序逻辑设计】
系统时钟sys_clk
为50Mhz信号,sys_rst
为系统复位。被测信号Measured_sig
设定任意频率,thres_cnt
门限计数周期定位1.5s(可调),前0.25s为信号保持,在中间的1.00s内是软件门限测量范围,后0.25s为计算时间。actual_thres
是参考门限范围,也就是被测信号的实际测量范围,是被测时钟周期的整数倍。
meas_clk_cnt
到act_cnt_reg
是被测时钟信号相对于参考门限的周期个数测量,最终得到计数N。由被测时钟信号上升沿触发,act_thres_reg
对actual_thres
做了一个延后保持(打拍),得到计数结束信号act_reg_flag
,通过其高电平触发计数值转移值act_cnt_reg
保持。std_clk_cnt
到std_cnt_reg
原理同样如此,是标准高频信号相对于参考门限的周期个数测量,最终得到计数Y,通过公式计算得到被测信号频率。
对上述时序图中的信号,编写Verilog程序:(注意不同的信号触发类型)
verilog
parameter THRES_CNT_MAX = 27'd75_000_000;
parameter THRES_CNT_250MS = 27'd12_500_000;
parameter CNT_STAND_FREP = 27'd100_000_000;
assign Std_flag = (Std_reg)&&(!act_thres)?1'b1:1'b0;
assign act_reg_flag = (act_thres_reg)&&(!act_thres)?1'b1:1'b0;
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) thres_cnt <= 27'd0;
else if(thres_cnt == THRES_CNT_MAX -1'b1) thres_cnt <= 27'd0;
else thres_cnt <= thres_cnt + 1'b1;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) thres_range <= 1'b0;
else if((thres_cnt > (THRES_CNT_250MS-1'b1))&&(thres_cnt < (THRES_CNT_MAX-THRES_CNT_250MS-1'b1))) thres_range <= 1'b1;
else thres_range <= 1'b0;
end
always @(posedge measured_sig or negedge sys_rst)begin
if(!sys_rst) act_thres <= 1'b0;
else act_thres <= thres_range;
end
always @(posedge measured_sig or negedge sys_rst)begin
if(!sys_rst) meas_clk_cnt <= 48'd0;
else if(!act_thres) meas_clk_cnt <= 48'd0;
else meas_clk_cnt <= meas_clk_cnt + 1'b1;
end
always @(posedge measured_sig or negedge sys_rst)begin
if(!sys_rst) act_thres_reg <= 1'b0;
else act_thres_reg <= act_thres;
end
always @(posedge measured_sig or negedge sys_rst)begin
if(!sys_rst)act_cnt_reg <= 48'd0;
else if(act_reg_flag) act_cnt_reg <= meas_clk_cnt;
end
always @(posedge clk_stand or negedge sys_rst)begin
if(!sys_rst) std_clk_cnt <= 48'd0;
else if(!act_thres)std_clk_cnt <= 48'd0;
else std_clk_cnt <= std_clk_cnt + 1'b1;
end
always @(posedge clk_stand or negedge sys_rst)begin
if(!sys_rst) Std_reg <= 1'd0;
else Std_reg <= act_thres;
end
always @(posedge clk_stand or negedge sys_rst)begin
if(!sys_rst) std_cnt_reg <= 48'd0;
else if(Std_flag) std_cnt_reg <= std_clk_cnt;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) calc_flag <= 1'd0;
else if(thres_cnt == THRES_CNT_MAX-1)calc_flag <= 1'd1;
else calc_flag <= 1'd0;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst)frep_result <= 32'd0;
else if(calc_flag)frep_result <= (CNT_STAND_FREP/ std_cnt_reg* act_cnt_reg);
end
其中的标准高频信号clk_stand
需要借助于QuartusII的PLL_IP核产生,模块实例化其中。
verilog
//Stand_clk from PLL_IP_core
clk_stand clk_stand_inst (
.areset ( !sys_rst ),//Hign Level take effect
.inclk0 ( sys_clk ),
.c0 ( clk_stand ) );
【频测模块仿真验证】
在仿真程序及仿真现象中,设定系统时钟20ns,即50Mhz,而被测时钟周期216ns,即1 / 216 * 10e9 ≈ 4.6296Mhz。并且,为方便观察波形变化,将软件门限缩小了10e5倍(精度减小),最终得到被测信号频率 32'h46a806 ≈ 4.6305Mhz,误差0.9khz,仿真上的时序变化均达到时序逻辑要求。
verilog
always #10 sys_clk =~sys_clk;
always #108 clk_test =~clk_test;
defparam frep_calc_inst.THRES_CNT_MAX = 750;
defparam frep_calc_inst.THRES_CNT_250MS = 125;
【部署其他模块】
考虑到最后的板级验证,没有信号源和示波器通过,在此再建立一个PLL_IP核产生一个"任意时钟信号",作为被测信号,并且将最终的结果输入到六位数码管上显示出来观察,该被测信号的实际频率为3.580097Mhz。
其次,实例化数码管显示模块,这里还是存在问题的,测信号的实际频率十六进制显示采用六位即可,这里图个方便,用assign直接赋值了。
verilog
digital digital_inst(
.sys_clk (sys_clk ),
.sys_rst (sys_rst ),
.clk_2khz (clk_2khz ),
.num6 (num6 ), //assign num6 = frep_result[23:20];
.num5 (num5 ), //assign num5 = frep_result[19:16];
.num4 (num4 ), //......
.num3 (num3 ),
.num2 (num2 ),
.num1 (num1 ),
.sel_cnt (sel_cnt ), //所使用到的位数
.dp_cnt (dp_cnt ), //小数点所在位号
.seg_sel (seg_sel ), //数码管位选
.seg_led (seg_led ) //数码管段选
);
【板级验证方案】
从下图可以看到,代码里采用了除法运算。在FPGA或ASIC设计中,除法运算本身是一种复杂的算术操作,相比于加法、减法和乘法,它需要更多的计算步骤和逻辑单元来完成,除法操作往往需要专门的硬件除法器。
上机测试后,烧录至EP4CE10F17C8开发板,数码管显示十六进制36A0C1,刚好是3,580,097hz。软件门限范围为1.00s,标准信号设定100Mhz,测量准确度还是比较高的。
文献参考:
[1]基于Altera EP4CE10 征途Mini开发板文档(https://doc.embedfire.com/fpga/altera/ep4ce10_mini/zh/latest/fpga/Frequency_Meter.html)
[2]王立华,周松江,高世皓,等. 基于内嵌Cortex-M3内核FPGA的等精度频率计设计[J]. 实验室研究与探索,2017,36(7):139-143,181. DOI:10.3969/j.issn.1006-7167.2017.07.033.
本篇文章中使用的Verilog程序模块,若有需见网页左栏Gitee仓库链接:https://gitee.com/silly-big-head/little-mouse-funnyhouse/tree/FPGA-Verilog/