05_Design and Verification of Simple Frequency Meter
1. Theoretical study
2. Experimental objectives
Using the acquired knowledge, design a simple frequency meter based on the principle of equal precision measurement, measure the frequency of the input unknown clock signal, and display the measurement results on the digital tube.
Requirements: The standard clock signal frequency is 100MHz, and the actual gate time is greater than or equal to 1s. The purpose is to reduce errors and improve measurement accuracy.
3. Modular design
3.1 Top-level modules
3.1 Frequency calculation module
4. Waveform diagram
The signals designed by the frequency calculation module are all based on this method diagram
. The software gate
counter is
an actual gate of 1.5 s, and the clock cycle of the measured information is used as the standard.
In order to present an integer relationship with the measured clock signal, at this time, the rising edge of the detection clock signal is considered, and Gate_s is pulled high at a high level, and then the rising edge of the clock signal is detected and Gate_s is pulled low at a low level.
Count the number of clock cycles to see how many
clock cycles of the clock signal under test are registered, use a delay of one clock cycle, find the falling edge pull signal, and then register when the flag signal is high.
Start to count the standard clock signal, because the IP core generates, the standard frequency is 100MHZ, the method is similar to the test clock signal. When the actual gate gata_a is high, start counting the standard clock signal
Calculate the flag signal
5. RTL
5.1 freq_meter_calc
`timescale 1ns/1ns
module freq_meter_calc
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire clk_test , //待检测时钟
output reg [33:0] freq //待检测时钟频率
);
//********************************************************************//
//****************** Parameter And Internal Signal *******************//
//********************************************************************//
//parameter define
parameter CNT_GATE_S_MAX = 28'd74_999_999 , //软件闸门计数器计数最大值
CNT_RISE_MAX = 28'd12_500_000 ; //软件闸门拉高计数值
parameter CLK_STAND_FREQ = 28'd100_000_000 ; //标准时钟时钟频率
//wire define
wire clk_stand ; //标准时钟,频率100MHz
wire gate_a_fall_s ; //实际闸门下降沿(标准时钟下)
wire gate_a_fall_t ; //实际闸门下降沿(待检测时钟下)
//reg define
reg [27:0] cnt_gate_s ; //软件闸门计数器
reg gate_s ; //软件闸门
reg gate_a ; //实际闸门
reg gate_a_stand ; //实际闸门打一拍(标准时钟下)
reg gate_a_test ; //实际闸门打一拍(待检测时钟下)
reg [47:0] cnt_clk_stand ; //标准时钟周期计数器
reg [47:0] cnt_clk_stand_reg ; //实际闸门下标志时钟周期数
reg [47:0] cnt_clk_test ; //待检测时钟周期计数器
reg [47:0] cnt_clk_test_reg ; //实际闸门下待检测时钟周期数
reg calc_flag ; //待检测时钟时钟频率计算标志信号
reg [63:0] freq_reg ; //待检测时钟频率寄存
reg calc_flag_reg ; //待检测时钟频率输出标志信号
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_gate_s:软件闸门计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_gate_s <= 28'd0;
else if(cnt_gate_s == CNT_GATE_S_MAX)
cnt_gate_s <= 28'd0;
else
cnt_gate_s <= cnt_gate_s + 1'b1;
//gate_s:软件闸门
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
gate_s <= 1'b0;
else if((cnt_gate_s>= CNT_RISE_MAX)
&& (cnt_gate_s <= (CNT_GATE_S_MAX - CNT_RISE_MAX)))
gate_s <= 1'b1;
else
gate_s <= 1'b0;
//gate_a:实际闸门
always@(posedge clk_test or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
gate_a <= 1'b0;
else
gate_a <= gate_s;
//cnt_clk_stand:标准时钟周期计数器,计数实际闸门下标准时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk_stand <= 48'd0;
else if(gate_a == 1'b0)
cnt_clk_stand <= 48'd0;
else if(gate_a == 1'b1)
cnt_clk_stand <= cnt_clk_stand + 1'b1;
//cnt_clk_test:待检测时钟周期计数器,计数实际闸门下待检测时钟周期数
always@(posedge clk_test or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk_test <= 48'd0;
else if(gate_a == 1'b0)
cnt_clk_test <= 48'd0;
else if(gate_a == 1'b1)
cnt_clk_test <= cnt_clk_test + 1'b1;
//gate_a_stand:实际闸门打一拍(标准时钟下)
always@(posedge clk_stand or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
gate_a_stand <= 1'b0;
else
gate_a_stand <= gate_a;
//gate_a_fall_s:实际闸门下降沿(标准时钟下)
assign gate_a_fall_s = ((gate_a_stand == 1'b1) && (gate_a == 1'b0))
? 1'b1 : 1'b0;
//cnt_clk_stand_reg:实际闸门下标志时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk_stand_reg <= 32'd0;
else if(gate_a_fall_s == 1'b1)
cnt_clk_stand_reg <= cnt_clk_stand;
//gate_a_test:实际闸门打一拍(待检测时钟下)
always@(posedge clk_test or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
gate_a_test <= 1'b0;
else
gate_a_test <= gate_a;
//gate_a_fall_t:实际闸门下降沿(待检测时钟下)
assign gate_a_fall_t = ((gate_a_test == 1'b1) && (gate_a == 1'b0))
? 1'b1 : 1'b0;
//cnt_clk_test_reg:实际闸门下待检测时钟周期数
always@(posedge clk_test or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk_test_reg <= 32'd0;
else if(gate_a_fall_t == 1'b1)
cnt_clk_test_reg <= cnt_clk_test;
//calc_flag:待检测时钟时钟频率计算标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
calc_flag <= 1'b0;
else if(cnt_gate_s == (CNT_GATE_S_MAX - 1'b1))
calc_flag <= 1'b1;
else
calc_flag <= 1'b0;
//freq_reg:待检测时钟信号时钟频率寄存
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq_reg <= 64'd0;
else if(calc_flag == 1'b1)
freq_reg <= (CLK_STAND_FREQ * cnt_clk_test_reg / cnt_clk_stand_reg);
//calc_flag_reg:待检测时钟频率输出标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
calc_flag_reg <= 1'b0;
else
calc_flag_reg <= calc_flag;
//freq:待检测时钟信号时钟频率
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
freq <= 34'd0;
else if(calc_flag_reg == 1'b1)
freq <= freq_reg[33:0];
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//---------- clk_gen_inst ----------
clk_gen clk_gen_inst
(
.areset (~sys_rst_n ),
.inclk0 (sys_clk ),
.c0 (clk_stand )
);
endmodule
5.2 freq_meter
`timescale 1ns/1ns
module freq_meter
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire clk_test , //待检测时钟
output wire clk_out , //生成的待检测时钟
output wire stcp , //输出数据存储寄时钟
output wire shcp , //移位寄存器的时钟输入
output wire ds , //串行数据输入
output wire oe
);
//wire define
wire [33:0] freq ; //计算得到的待检测信号时钟频率
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//---------- clk_gen_test_inst ----------
clk_test_gen clk_gen_test_inst
(
.areset (~sys_rst_n ), //复位端口,高电平有效
.inclk0 (sys_clk ), //输入系统时钟
.c0 (clk_out ) //输出生成的待检测时钟信号
);
//------------- freq_meter_calc_inst --------------
freq_meter_calc freq_meter_calc_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.clk_test (clk_test ), //待检测时钟
.freq (freq ) //待检测时钟频率
);
//------------- seg_595_dynamic_inst --------------
seg_595_dynamic seg_595_dynamic_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低有效
.data (freq/1000 ), //数码管要显示的值
.point (6'b001000 ), //小数点显示,高电平有效
.seg_en (1'b1 ), //数码管使能信号,高电平有效
.sign (1'b0 ), //符号位,高电平显示负号
.stcp (stcp ), //输出数据存储寄时钟
.shcp (shcp ), //移位寄存器的时钟输入
.ds (ds ), //串行数据输入
.oe (oe ) //输出使能信号
);
endmodule
6. Testbench
6.1 tb_freq_meter
`timescale 1ns/1ns
module tb_freq_meter();
//********************************************************************//
//****************** Parameter And Internal Signal *******************//
//********************************************************************//
//wire define
wire stcp ; //输出数据存储寄时钟
wire shcp ; //移位寄存器的时钟输入
wire ds ; //串行数据输入
wire oe ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg clk_test ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//时钟、复位、待检测时钟的生成
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#200
sys_rst_n <= 1'b1;
#500
clk_test = 1'b1;
end
always #10 sys_clk = ~sys_clk ; //50MHz系统时钟
always #100 clk_test= ~clk_test ; //5MHz待检测时钟
//重定义软件闸门计数时间,缩短仿真时间
defparam freq_meter_inst.freq_meter_calc_inst.CNT_GATE_S_MAX = 240 ;
defparam freq_meter_inst.freq_meter_calc_inst.CNT_RISE_MAX = 40 ;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- freq_meter_inst -------------
freq_meter freq_meter_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.clk_test (clk_test ), //待检测时钟
.clk_out (clk_out ), //生成的待检测时钟
.stcp (stcp ), //输出数据存储寄时钟
.shcp (shcp ), //移位寄存器的时钟输入
.ds (ds ), //串行数据输入
.oe (oe )
);
endmodule