FPGA测量频率的方法
测量频率在自动化测试应用广泛,常用的测频率的工具也有挺多,比如示波器,频率计等。外部信号给到FPGA无非是0和1,因此测量频率主要是对周期信号进行统计,原理也挺简单。测量频率的方法也很多,这里就简单的列举下笔者知道的两种方式,其实下面的这两种方式原理差不多。
原理基本都是通过等时间计算频率,公式为:N0/f0 = N1/f1。f0为已知时钟频率,N0为在某一时间段T内周期个数,f1为待测信号频率,N1为待测信号在时间段T内的周期数。根据公式转换则 f1 = N1*f0/N0。由于要保证时间T尽可能相等,这就需要用到积分,也就是时间越长结果越准确,而实际应用只要达到目标精度即可。这里为仿真方便只设置200ms测量时间。系统时钟为100MHz,待测信号设为6.25MHz。
方法一:
直接根据上述公式进行代码编写,使能信号在200ms时间段内保持高电平。该方式下输入信号作为时钟边沿敏感信号进行计数,会存在跨时钟域的问题,因此需要做复位同步,使能信号同步等操作。这会导致时间有些偏差,但影响不大。
1 //************************************************************************** 2 // *** file name : Fre_Measure1.v 3 // *** version : 1.0 4 // *** Description : Frequency measurement method 1 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.05.06 8 // *** Changes : Initial 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Fre_Measure1 12 ( 13 input i_sys_clk , 14 input i_sys_rstn , 15 input i_signal_clk , 16 input i_measure_en , 17 output reg [31:0] o_signal_cnt , 18 output reg [31:0] o_refer_cnt , 19 output o_measure_busy 20 ); 21 22 wire w_measure_busy ; 23 reg [2:0] r_syn_rstn ; 24 reg [2:0] r_signal_en ; 25 reg [1:0] r_measure_busy ; 26 27 /******************************************************************************\ 28 Reference clock count 29 \******************************************************************************/ 30 always@(posedge i_sys_clk) 31 begin 32 if(~i_sys_rstn) 33 begin 34 o_refer_cnt <= 'd0; 35 end 36 else if(i_measure_en) 37 begin 38 o_refer_cnt <= o_refer_cnt + 1'b1; 39 end 40 else 41 begin 42 o_refer_cnt <= o_refer_cnt; 43 end 44 end 45 /******************************************************************************\ 46 Asynchronous reset and synchronous release 47 \******************************************************************************/ 48 always@(posedge i_signal_clk or negedge i_sys_rstn) 49 begin 50 if(~i_sys_rstn) 51 begin 52 r_syn_rstn <= 'd0; 53 end 54 else 55 begin 56 r_syn_rstn <= {r_syn_rstn[1:0],1'b1}; 57 end 58 end 59 /******************************************************************************\ 60 Synchronous enable 61 \******************************************************************************/ 62 always@(posedge i_signal_clk) 63 begin 64 if(~r_syn_rstn[2]) 65 begin 66 r_signal_en <= 'd0; 67 end 68 else 69 begin 70 r_signal_en <= {r_signal_en[1:0],i_measure_en}; 71 end 72 end 73 /******************************************************************************\ 74 Signal count to be measured 75 \******************************************************************************/ 76 always@(posedge i_signal_clk) 77 begin 78 if(~r_syn_rstn[2]) 79 begin 80 o_signal_cnt <= 'd0; 81 end 82 else if(r_signal_en[2]) 83 begin 84 o_signal_cnt <= o_signal_cnt + 1'b1; 85 end 86 else 87 begin 88 o_signal_cnt <= o_signal_cnt; 89 end 90 end 91 /******************************************************************************\ 92 Detection and measurement status 93 \******************************************************************************/ 94 assign w_measure_busy = i_measure_en | r_signal_en[2]; 95 96 always@(posedge i_sys_clk) 97 begin 98 if(~i_sys_rstn) 99 begin 100 r_measure_busy <= 'd0; 101 end 102 else 103 begin 104 r_measure_busy <= {r_measure_busy[0],w_measure_busy}; 105 end 106 end 107 108 assign o_measure_busy = r_measure_busy[1]; 109 110 endmodule
方法二:
这种方法适合测量比参考信号频率小得多的信号,方法一各种频率都能测。不过方法二能够测量信号的占空比,原理也挺简单。即通过时间段内计算出上升沿个数,算出该待测信号频率;累计高电平所耗时间,算出占空比。
1 //************************************************************************** 2 // *** file name : Fre_Measure2.v 3 // *** version : 1.0 4 // *** Description : Frequency measurement method 2 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.05.06 8 // *** Changes : Initial 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Fre_Measure2 12 ( 13 input i_sys_clk , 14 input i_sys_rstn , 15 input i_signal , 16 input i_measure_en , 17 output reg [31:0] o_pos_cnt , 18 output reg [31:0] o_high_cnt 19 ); 20 wire w_signal_pos; 21 wire w_signal_neg; 22 23 reg [2:0] r_signal; 24 /******************************************************************************\ 25 Synchronous i_signal 26 \******************************************************************************/ 27 always@(posedge i_sys_clk) 28 begin 29 if(~i_sys_rstn) 30 begin 31 r_signal <= 'd0; 32 end 33 else 34 begin 35 r_signal <= {r_signal[1:0],i_signal}; 36 end 37 end 38 39 assign w_signal_pos = ~r_signal[2] & r_signal[1]; 40 assign w_signal_neg = ~r_signal[1] & r_signal[2]; 41 /******************************************************************************\ 42 Cumulative number of rising edges 43 \******************************************************************************/ 44 always@(posedge i_sys_clk) 45 begin 46 if(~i_sys_rstn) 47 begin 48 o_pos_cnt <= 'd0; 49 end 50 else if(i_measure_en & w_signal_pos) 51 begin 52 o_pos_cnt <= o_pos_cnt + 1'b1; 53 end 54 else 55 begin 56 o_pos_cnt <= o_pos_cnt; 57 end 58 end 59 /******************************************************************************\ 60 Cumulative number of high-level edges 61 \******************************************************************************/ 62 always@(posedge i_sys_clk) 63 begin 64 if(~i_sys_rstn) 65 begin 66 o_high_cnt <= 'd0; 67 end 68 else if(i_measure_en & r_signal[2]) 69 begin 70 o_high_cnt <= o_high_cnt + 1'b1; 71 end 72 else 73 begin 74 o_high_cnt <= o_high_cnt; 75 end 76 end 77 78 endmodule
顶层文件AXI4_Fre_measure.v
1 //************************************************************************** 2 // *** file name : AXI4_Fre_measure.v 3 // *** version : 1.0 4 // *** Description : Frequency measurement module top 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.05.06 8 // *** Changes : Initial 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module AXI4_Fre_measure 12 #( 13 parameter SYS_FRE = 100_000_000 14 ) 15 ( 16 input wire i_s_axi_aclk , 17 input wire i_s_axi_aresetn , 18 input wire [31:0] i_s_axi_awaddr , 19 input wire [2:0] i_s_axi_awprot , 20 input wire i_s_axi_awvalid , 21 output wire o_s_axi_awready , 22 input wire [31:0] i_s_axi_wdata , 23 input wire [3:0] i_s_axi_wstrb , 24 input wire i_s_axi_wvalid , 25 output wire o_s_axi_wready , 26 output wire [1:0] o_s_axi_bresp , 27 output wire o_s_axi_bvalid , 28 input wire i_s_axi_bready , 29 input wire [31:0] i_s_axi_araddr , 30 input wire [2:0] i_s_axi_arprot , 31 input wire i_s_axi_arvalid , 32 output wire o_s_axi_arready , 33 output wire [31:0] o_s_axi_rdata , 34 output wire [1:0] o_s_axi_rresp , 35 output wire o_s_axi_rvalid , 36 input wire i_s_axi_rready , 37 input wire i_signal 38 ); 39 wire w_module_en ; 40 wire [31:0] w_ms_number ; 41 wire w_measure_en ; 42 wire [31:0] w_signal_cnt ; 43 wire [31:0] w_refer_cnt ; 44 wire w_measure_busy ; 45 wire [31:0] w_signal_pos_cnt ; 46 wire [31:0] w_signal_high_cnt ; 47 48 /******************************************************************************\ 49 Fre measure control 50 \******************************************************************************/ 51 Fre_Measure_ctrl 52 #( 53 .SYS_FRE (SYS_FRE ) 54 ) 55 u_Fre_Measure_ctrl 56 ( 57 .i_s_axi_aclk (i_s_axi_aclk ), 58 .i_s_axi_aresetn (i_s_axi_aresetn ), 59 .i_s_axi_awaddr (i_s_axi_awaddr ), 60 .i_s_axi_awprot (i_s_axi_awprot ), 61 .i_s_axi_awvalid (i_s_axi_awvalid ), 62 .o_s_axi_awready (o_s_axi_awready ), 63 .i_s_axi_wdata (i_s_axi_wdata ), 64 .i_s_axi_wstrb (i_s_axi_wstrb ), 65 .i_s_axi_wvalid (i_s_axi_wvalid ), 66 .o_s_axi_wready (o_s_axi_wready ), 67 .o_s_axi_bresp (o_s_axi_bresp ), 68 .o_s_axi_bvalid (o_s_axi_bvalid ), 69 .i_s_axi_bready (i_s_axi_bready ), 70 .i_s_axi_araddr (i_s_axi_araddr ), 71 .i_s_axi_arprot (i_s_axi_arprot ), 72 .i_s_axi_arvalid (i_s_axi_arvalid ), 73 .o_s_axi_arready (o_s_axi_arready ), 74 .o_s_axi_rdata (o_s_axi_rdata ), 75 .o_s_axi_rresp (o_s_axi_rresp ), 76 .o_s_axi_rvalid (o_s_axi_rvalid ), 77 .i_s_axi_rready (i_s_axi_rready ), 78 .o_module_en (w_module_en ), 79 .i_measure_busy (w_measure_busy ), 80 .o_ms_number (w_ms_number ), 81 .i_signal_cnt (w_signal_cnt ), 82 .i_refer_cnt (w_refer_cnt ), 83 .i_signal_pos_cnt (w_signal_pos_cnt ), 84 .i_signal_high_cnt (w_signal_high_cnt ) 85 ); 86 /******************************************************************************\ 87 Gener enable signal 88 \******************************************************************************/ 89 time_cnt 90 #( 91 .SYS_FRE (SYS_FRE ) 92 ) 93 u_time_cnt 94 ( 95 .i_sys_clk (i_s_axi_aclk ), 96 .i_sys_rstn (i_s_axi_aresetn & w_module_en), 97 .i_time_number (w_ms_number ), 98 .o_measure_en (w_measure_en ) 99 ); 100 /******************************************************************************\ 101 Fre measure method 1 102 \******************************************************************************/ 103 Fre_Measure1 u_Fre_Measure1 104 ( 105 .i_sys_clk (i_s_axi_aclk ), 106 .i_sys_rstn (i_s_axi_aresetn & w_module_en), 107 .i_signal_clk (i_signal ), 108 .i_measure_en (w_measure_en ), 109 .o_signal_cnt (w_signal_cnt ), 110 .o_refer_cnt (w_refer_cnt ), 111 .o_measure_busy (w_measure_busy ) 112 ); 113 114 /******************************************************************************\ 115 Fre measure method 2 116 \******************************************************************************/ 117 Fre_Measure2 u_Fre_Measure2 118 ( 119 .i_sys_clk (i_s_axi_aclk ), 120 .i_sys_rstn (i_s_axi_aresetn & w_module_en), 121 .i_signal (i_signal ), 122 .i_measure_en (w_measure_en ), 123 .o_pos_cnt (w_signal_pos_cnt ), 124 .o_high_cnt (w_signal_high_cnt ) 125 ); 126 endmodule
其他模块的代码前面提到过或者比较简单,这里就不一一贴出。仿真结果如下:
顶层文件信号波形:
Fre_Measure1:
Fre_Measure2:
根据上面的原理分别计算
方法一:f1 = N1*f0/N0 = 1249997*100/20000000 = 6.249985MHz
方法二:f1 = N1*f0/N0 = 1250000*100/20000000 = 6.25MHz 占空比:z = 9999999/20000000 = 49.999995% 注意:对于PWM信号占空比是直接这样算,对于ADC采样信号最高位为符号位0表示正,1表示负的时候应该在信号进入模块之前取反。
根据结果貌似方法二计算的频率更加精确但精度也相差不多,仿真没问题后,可以对代码进行IP核封装使用。