0
点赞
收藏
分享

微信扫一扫

野火FPGA强化(2):简易频率计


文章目录

  • ​​第34讲:简易频率计的设计与验证​​
  • ​​freq_meter_calc​​
  • ​​freq_meter​​
  • ​​tb_freq_meter​​

第34讲:简易频率计的设计与验证

常用频率测量法:频率测量法、周期测量法、等精度测量法

频率测量法:在时间T内对被测时钟信号的时钟周期N进行计数,然后求出单位时间内的时钟周期数,即为被测时钟信号的时钟频率。

周期测量法:先测量出被测时钟信号的时钟周期T,然后根据频率f=1/T求出被测时钟信号的频率。

野火FPGA强化(2):简易频率计_时钟周期


野火FPGA强化(2):简易频率计_系统时钟_02


子功能模块设计

野火FPGA强化(2):简易频率计_时钟周期_03


系统框图设计

野火FPGA强化(2):简易频率计_系统时钟_04


野火FPGA强化(2):简易频率计_sed_05

freq_meter_calc

野火FPGA强化(2):简易频率计_系统时钟_06

`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 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 ; //待检测时钟频率输出标志信号

//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];

//---------- clk_gen_inst ----------
clk_gen clk_gen_inst
(
.areset (~sys_rst_n ),
.inclk0 (sys_clk ),

.c0 (clk_stand )
);

endmodule

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 ; //计算得到的待检测信号时钟频率

//---------- 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

tb_freq_meter

`timescale  1ns/1ns
module tb_freq_meter();

//wire define
wire stcp ; //输出数据存储寄时钟
wire shcp ; //移位寄存器的时钟输入
wire ds ; //串行数据输入
wire oe ;

//reg define
reg sys_clk ;
reg sys_rst_n ;
reg clk_test ;

//时钟、复位、待检测时钟的生成
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 ;

//------------- 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


举报

相关推荐

0 条评论