搜索
bottom↓
回复: 4

【正点原子FPGA连载】第二十七章 频率计实验--摘自【正点原子】开拓者 FPGA 开发指南

[复制链接]

出0入234汤圆

发表于 2019-6-13 17:16:02 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 15:15 编辑

1)实验平台:正点原子开拓者FPGA开发板
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-281143-1-1.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:712557122
5)关注正点原子公众号,获取最新资料更新:

第二十七章 频率计实验


数字频率计是一种基本的测量仪器,被广泛应用于航天、电子、测控等领域。基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低,在使用中有较大的局限性,而等精度频率计不但具有较高的测量精度,而且在整个频率区域能保持恒定的测试精度。本章我们
通过开拓者FPGA开发板搭建等精度频率计,学习等精度频率计的设计思想和实现方案。
本章分为以下几个章节:
27.1 等精度频率计简介
27.2 实验任务
27.3 硬件设计
27.4 程序设计
27.5 下载验证
27.1 等精度频率计简介
频率测量在电子设计和测量领域中经常用到,因此对频率测量方法的研究在实际工程应用中具有重要意义。常用的频率测量方法有两种:周期测量法和频率测量法。周期测量法是先测量出被测信号的周期T,然后根据频率f = 1/T求出被测信号的频率。频率测量法是在时间t内
对被测信号的脉冲数N进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。但是上述两种方法都会产生±1个被测脉冲的误差,在实际应用中有一定的局限性。根据测量原理,很容易发现周期测量法适合于低频信号测量,频率测量法适合于高频信号测量,但二者都不能
兼顾高低频率同样精度的测量要求。等精度测量的一个最大特点是测量的实际门控时间不是一个固定值,而是一个与被测信号有关的值,刚好是被测信号的整数倍。在计数允许时间内,同时对基准时钟和被测信号进行计数,再通过数学公式推导得到被测信号的频率。由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l周期误差,但是会产生对基准时钟±1周期的误差。等精度测量原理如图27.1.1所示。
image481.png

图 27.1.1 等精度测量原理

从以上叙述的等精度的测量原理可以很容易得出如下结论:首先,被测信号频率clk_fx的相对误差与被测信号的频率无关;其次,增大测量时间段“软件闸门”或提高“标频”clk_fs,可以减小相对误差,提高测量精度;最后,由于一般提供基准时钟clk_fs的石英晶振稳定性很
高,所以基准时钟的相对误差很小,可忽略。假设基准时钟的频率为100MHz,只要实际闸门时间大于或等于1s,就可使测量的最大相对误差小于或等于10^(-8),即精度达到1/100MHz。等精度测量的核心思想在于如何保证在实际测量门闸内被测信号为整数个周期,这就需要在设计
中让实际测量门闸信号与被测信号建立一定的关系。基于这种思想, 设计中以被测信号的上升沿作为开启门闸和关闭门闸的驱动信号,只有在被测信号的上升沿才将图 27.1.1中预置的“软件闸门”的状态锁存,因此在“实际闸门” Tx内被测信号的个数就能保证整数个周期,这样就
避免普通测量方法中被测信号的±1的误差,但会产生高频的基准时钟信号的±l周期误差,由于基准时钟频率远高于被测信号,因此它产生的±1周期误差对测量精度的影响十分有限,特别是在中低频测量的时候,相较于传统的频率测量和周期测量方法,可以大大提高测量精度。
等精度测频的原理图如图 27.1.2所示。图中,预置软件闸门信号gate是由FPGA的定时模
块产生, gate的时间宽度对测频精度的影响较少,故可以在较大的范围内选择。这里选择预置闸门信号的长度由参数GATE_TIME设置。图中的fs_cnt和fx_cnt是2个可控的32位高速计数器,
fs_cnt和fx_cnt分别是其计数使能端,由gate信号控制, 基准时钟信号clk_fs从时钟输入端clk_fs输入,待测信号clk_fx从时钟输入端clk_fx输入,并将clk_fx接到D触发器的clk端。测量时,由FPGA的定时模块产生预置的gate信号,在gate为高电平,并且clk_fx的上升沿时,启
动2个计数器,分别对被测信号和基准时钟计数,关闭计数闸门必须满足, gate为低电平,且在clk_fx的上升沿。若在一次实际闸门时间GATE_TIME中,计数器对被测信号的计数值为fx_cnt,对基准时钟的计数值为fs_cnt,而基准时钟的频率为CLK_FS,则被测信号的频率为clk_fx,则
由公式推出:
image482.png


image483.png


图 27.1.2中的所有功能都在FPGA端实现。


image484.png
图 27.1.2 FPGA实现的功能的原理图

27.2 实验任务
板载50MHz的时钟通过分频产生某一频率的时钟信号,作为被测时钟,然后用Verilog HDL编写的等精度测量模块测量被测时钟,并通过数码管显示。
27.3 硬件设计
本次实验只需将FPGA的两个扩展口使用跳帽或者杜邦线连接即可。虽然理论上可以使用开发板上的任意两个IO扩展口,但是由于我们使用输入的被测时钟作为FPGA内部信号的操作时钟,所以对输入的被测时钟的信号质量要求比较高,并且我们开拓者FPGA开发板上的扩展口大多数
都是和开发板外设复用到一起(比如VGA的引脚全部复用到扩展口上,而VGA的引脚连接到了电阻上,所以连接VGA扩展口上的引脚都不可以使用)。因此本次实验将FPGA的F2引脚做为分频产生的时钟的输出端, F3引脚做为被测时钟的输入端,通过一根导线(杜邦线)或者跳帽进行连接。
image485.png

图 27.3.1 硬件原理图


本实验中, 各端口信号的管脚分配如下表所示:
表 27.3.1 等精度频率计实验管脚分配


image486.png
image486-1.png





27.4 程序设计
根据实验任务,我们可以大致规划出系统的控制流程: 首先我们设计一个测试时钟模块用于生成被测的时钟,然后用等精度频率计模块测量被测时钟的频率,并将测得的时钟频率值送入数码管显示模块进行显示。 由此画出系统的功能框图如下所示:

image486-2.png

图 27.4.1 等精度频率计实验系统框图


由系统框图可知, FPGA部分包括四个模块: 顶层模块(top_cymometer)、 等精度频率计模块(cymometer) 、时钟产生模块(clk_test)、以及数码管显示模块(seg_led) 。 各模块功能如下:
顶层模块(top_cymometer):顶层模块完成了对其它三个模块的例化,实现各模块之间的数据交互。 时钟产生模块产生被测时钟输出,并从外部接入至等精度频率计模块,以进行频率测量,将测量的结果传输给数码管驱动模块进行显示。 顶层模块的原理图如下图所示:
image487.png

图 27.4.2 顶层模块原理图

等精度频率计模块(cymometer): 等精度频率计模块测量输入的被测时钟的频率。并将测得的频率结果输出。时钟产生模块(clk_test):时钟产生模块产生被测的时钟。数码管显示模块(seg_led) :将等精度频率计测得的时钟频率值在数码管上显示出来。
顶层模块的代码如下:
1 module top_cymometer(
2 //system clock
3 input sys_clk , // 时钟信号
4 input sys_rst_n , // 复位信号
5 6
//cymometer interface
7 input clk_fx , // 被测时钟
8 output clk_out , // 输出时钟
9 //user interface
10 output [5:0] sel , // 数码管位选
11 output [7:0] seg_led // 数码管段选
12 );
13
14
//parameter define
15 parameter CLK_FS = 26'd50000000; // 基准时钟频率值
16
17
//wire define
18 wire [19:0] data_fx; // 被测信号测量值
19
20
//*****************************************************
21 //** main code
22 //*****************************************************
23
24
//例化等精度频率计模块
25 cymometer #(.CLK_FS(CLK_FS) // 基准时钟频率值
26 ) u_cymometer(
27 //system clock
28 .clk_fs (sys_clk) , // 基准时钟信号
29 .rst_n (sys_rst_n) , // 复位信号
30 //cymometer interface
31 .clk_fx (clk_fx), // 被测时钟信号
32 .data_fx(data_fx) // 被测时钟频率输出
33 );
34
35
//例化测试时钟模块,产生测试时钟
36 clk_test #(.DIV_N(7'd100) // 分频系数
37 ) u_clk_test(
38 //源时钟
39 .clk_in (sys_clk ), // 输入时钟
40 .rst_n (sys_rst_n), // 复位信号
41 //分频后的时钟
42 .clk_out(clk_out ) // 测试时钟
43 );
44
45
//例化数码管显示模块
46 seg_led u_seg_led(
47 //module clock
48 .clk (sys_clk ), // 数码管驱动模块的驱动时钟
49 .rst_n (sys_rst_n ), // 复位信号
50 //seg_led interface
51 .sel (sel ), // 数码管位选
52 .seg_led (seg_led ), // 数码管段选
53 //user interface
54 .data (data_fx ), // 被测频率值
55 .point (6'd0 ), // 数码管显示的点控制
56 .en (1'b1 ), // 数码管驱动使能信号
57 .sign (1'b0 ) // 控制符号位显示
58 );
59
60
endmodule
顶层代码主要完成对各模块的例化并实现模块信号间的交互。第15行的基准时钟频率值参数为基准时钟频率值,当用不同的基准时钟时修改此参数即可。
时钟产生模块的代码如下:
1 module clk_test #(parameter DIV_N = 7'd100) //分频系数
2 (
3 //源时钟
4 input clk_in , // 输入时钟
5 input rst_n , // 复位信号
6 //分频后的时钟
7 output reg clk_out // 输出时钟
8 );
9
10
//reg define
11 reg [9:0] cnt; // 时钟分频计数
12
13
//*****************************************************
14 //** main code
15 //*****************************************************
16
17
//时钟分频
18 always @(posedge clk_in or negedge rst_n) begin
19 if(rst_n == 1'b0) begin
20 cnt <= 0;
21 clk_out <= 0;
22 end
23 else begin
24 if(cnt == DIV_N/2 - 1'b1) begin
25 cnt <= 10'd0;
26 clk_out <= ~clk_out;
27 end
28 else
29 cnt <= cnt + 1'b1;
30 end
31 end
32
33
endmodule
时钟产生模块通过分频产生被测时钟,这里是用偶数分频方法产生,修改代码第一行的DIV_N分频参数,可得到不同频率的时钟信号,时钟频率为clk_in/DIV_N 。由于该模块在顶层例化时clk_in为系统时钟50MHz,分频参数为100,产生的时钟频率为50000000/100 = 500000Hz。
等精度频率计模块的代码如下:
1 module cymometer
2 #(parameter CLK_FS = 26'd50_000_000) // 基准时钟频率值
3 ( //system clock
4 input clk_fs , // 基准时钟信号
5 input rst_n , // 复位信号
6 7
//cymometer interface
8 input clk_fx , // 被测时钟信号
9 output reg [19:0] data_fx // 被测时钟频率输出
10 )/*synthesis preserve*/;
11
12 //parameter define
13 localparam MAX = 6'd32; // 定义fs_cnt、 fx_cnt的最大位宽
14 localparam GATE_TIME = 16'd50_000; // 门控时间设置(预置闸门)
15
16
//reg define
17 reg reckon_en ; // 计算使能信号
18 reg reckon_fs_d0; // 计算信号打拍0(基准时钟下)
19 reg reckon_fs_d1; // 计算信号打拍1(基准时钟下)
20 reg reckon_fx_d0; // 计算信号打拍0(被测时钟下)
21 reg reckon_fx_d1; // 计算信号打拍1(被测时钟下)
22 reg gate ; // 门控信号
23 reg gate_fs_d0 ; // 基准时钟对门控时钟采沿打拍
24 reg gate_fx_d0 ; // 被测时钟对门控时钟采沿打拍
25 reg fs_cnt_en ; // 基准时钟对门控时钟采沿打拍
26 reg fx_cnt_en ; // 被测时钟对门控时钟采沿打拍
27 reg [ 15:0] gate_cnt ; // 门控计数
28 reg [MAX-1:0] fs_cnt ; // 门控信号下的基准时钟计数值
29 reg [MAX-1:0] fs_cnt_t ; // 门控信号下的基准时钟计数临时值
30 reg [MAX-1:0] fx_cnt ; // 门控信号下的被测时钟计数值
31 reg [MAX-1:0] fx_cnt_t ; // 门控信号下的被测时钟计数临时值
32
33
//wire define
34 wire pos_reckon_fs; // 在基准时钟信号下采样的计算信号的上升沿
35 wire pos_reckon_fx; // 在被测时钟信号下采样的计算信号的上升沿
36 wire [31:0] data_fx_t; // 被测信号频率数据的暂存值
37
38
//*****************************************************
39 //** main code
40 //*****************************************************
41
42
//不同时钟下计算信号的上升沿
43 assign pos_reckon_fs = ~reckon_fs_d0 & reckon_fs_d1;
44 assign pos_reckon_fx = ~reckon_fx_d0 & reckon_fx_d1;
45 //计算被测信号频率
46 assign data_fx_t = reckon_en ? (CLK_FS / fs_cnt) * fx_cnt : data_fx_t;
47
48
//被测时钟频率数值
49 always @(posedge clk_fs or negedge rst_n) begin
50 if(!rst_n) begin
51 data_fx <= 20'd0;
52 end
53 else if(reckon_en == 1'b0)
54 data_fx <= data_fx_t;
55 end
56
57
//门控信号控制闸门时间及计算使能信号(门控信号低电平使能计算)
58 always @(posedge clk_fx or negedge rst_n) begin
59 if(!rst_n) begin
60 reckon_en <= 1'b0;
61 gate <= 1'b0;
62 gate_cnt <= 16'd0;
63 end
64 else if(gate_cnt < 4'd10) begin
65 gate <= 1'b0;
66 reckon_en <= 1'b1;
67 gate_cnt <= gate_cnt + 1'b1;
68 end
69 else if(gate_cnt < GATE_TIME + 4'd10) begin
70 reckon_en <= 1'b0;
71 gate <= 1'b1;
72 gate_cnt <= gate_cnt + 1'b1;
73 end
74 else if(gate_cnt < GATE_TIME + 5'd20) begin
75 gate <= 1'b0;
76 reckon_en <= 1'b1;
77 gate_cnt <= gate_cnt + 1'b1;
78 end
79 else begin
80 gate <= 1'b0;
81 gate_cnt <= 16'd0;
82 end
83 end
84
85
//打拍采门控信号上升沿(基准时钟下)
86 always @(posedge clk_fs or negedge rst_n) begin
87 if(!rst_n) begin
88 gate_fs_d0 <= 1'b0;
89 fs_cnt_en <= 1'b0;
90 end
91 else begin
92 gate_fs_d0 <= gate;
93 fs_cnt_en <= gate_fs_d0;
94 end
95 end
96
97
//打拍采门控信号上升沿(被测时钟下)
98 always @(posedge clk_fx or negedge rst_n) begin
99 if(!rst_n) begin
100 gate_fx_d0 <= 1'b0;
101 fx_cnt_en <= 1'b0;
102 end
103 else begin
104 gate_fx_d0 <= gate;
105 fx_cnt_en <= gate_fx_d0;
106 end
107 end
108
109
//打拍采fs_cnt_en的下降沿(基准时钟下)
110 always @(posedge clk_fs or negedge rst_n) begin
111 if(!rst_n) begin
112 reckon_fs_d0 <= 1'b0;
113 reckon_fs_d1 <= 1'b0;
114 end
115 else begin
116 reckon_fs_d0 <= fs_cnt_en;
117 reckon_fs_d1 <= reckon_fs_d0;
118 end
119 end
120
121
//打拍采fx_cnt_en的下降沿(被测时钟下)
122 always @(posedge clk_fx or negedge rst_n) begin
123 if(!rst_n) begin
124 reckon_fx_d0 <= 1'b0;
125 reckon_fx_d1 <= 1'b0;
126 end
127 else begin
128 reckon_fx_d0 <= fx_cnt_en;
129 reckon_fx_d1 <= reckon_fx_d0;
130 end
131 end
132
133
//实际闸门下的被测时钟计数
134 always @(posedge clk_fx or negedge rst_n) begin
135 if(!rst_n) begin
136 fx_cnt <= 32'd0;
137 fx_cnt_t <= 32'd0;
138 end
139 else if(fx_cnt_en)
140 fx_cnt_t <= fx_cnt_t + 1'b1;
141 else if(pos_reckon_fx) begin
142 fx_cnt <= fx_cnt_t;
143 fx_cnt_t <= 32'd0;
144 end
145 end
146
147
//实际闸门的基准时钟计数
148 always @(posedge clk_fs or negedge rst_n) begin
149 if(!rst_n) begin
150 fs_cnt <= 32'd0;
151 fs_cnt_t <= 32'd0;
152 end
153 else if(fs_cnt_en)
154 fs_cnt_t <= fs_cnt_t + 1'b1;
155 else if(pos_reckon_fs) begin
156 fs_cnt <= fs_cnt_t;
157 fs_cnt_t <= 32'd0;
158 end
159 end
160
161
endmodule
在前面的等精度频率计简介中,我们知道需要在设计中让实际测量门控信号与被测信号建立一定的关系。基于这种思想,设计中以被测信号的上升沿作为开启门控和关闭门控的驱动信号,同时,为了方便表示和控制测量之后对被测时钟频率的计算,我们定义了一个计算使能信
号reckon_en,此处我们使其与门控信号gate同步,即gate为高电平时reckon为低电平不进行计算, gate为低电平时reckon为高电平,开始计算被测信号频率,当然了,也可不同步。门控时间由参数GATE_TIME设置,此处设为50000。为了防止复位对测量造成的干扰,门控信号在复
位后延迟了10个被测信号的周期(第64~68行)。建立了门控信号之后,我们需要通过门控信号分别使能基准时钟和被测时钟的计数。因为门控信号对基准时钟而言是异步信号,所以这里我们对门控信号进行了两次打拍处理得到基准频率下的计数使能信号fs_cnt_en(代码第86行的always语句块),为了方便同步化处理,我们对被测时钟下的门控信号也进行相应打拍处理得到被测频率下的计数使能信号fx_cnt_en。在计数使能信号的下降沿将计数值寄存并清零计数寄存器。在取得数值后,我们需要计算被测信号的频率值,由于在计算周期内数值已不再发生变化
(门控信号未开启),而且保留了足够的计算时间,所以可以不用FIFO进行异步处理。计算完之后,把所得的结果赋给寄存器变量data_fx,鉴于本开发板的数码管最大显示为6位数,换成二进制表示为20bit,所以data_fx的位宽设为20位,可以根据需要进行修改。另外需要说明的
是,这里的闸门时间我们为了方便处理,将其定义在被测信号的时钟周期上,当然也可以修改为时间值,如多少秒,此时可通过基准时钟生成一个计时器,来控制闸门gate的开启和关闭。

图 27.4.3为等精度频率计运行过程中SignalTap抓取的波形图。从图中可以看到当门控gate信号为高电平时, fx_cnt开始计数,当gate为低电平时停止计数,计数的值为门控时间GATE_TIME,测得的结果data_fx为500000,等于被测时钟频率。
波形.JPG

图 27.4.3 SignalTap抓取的波形图

至此,我们的实验已基本完成了,现在我们来做一下误差分析吧。
image491.png

其中clk_fxe为被测频率信号的准确值。在测量中,由于clk_fx计数的起停时间都是由该信号的上升沿触发的,在闸门时间GATE_TIME内对clk_fx的计数fx_cnt无误差(
GATE_TIME = fx_cnt/clk_fxe);对clk_fs的计数fs_cnt最多相差一个时钟的误差,即|Δfs_cnt|≤1,其测量频率如式(1-4):


将式(1-2)和(1-4)代入式(1-3),并整理如式
image492.png
image493.png

由上式可以看出,测量频率的相对误差与被测信号频率的大小无关,仅与闸门时间和基准时钟频率有关,即实现了整个测试频段的等精度测量。闸门时间越长,基准时钟频率越高,测频的相对误差就越小。基准时钟频率可由稳定度好、精度高的高频率晶体振荡器产生,在保证
测量精度不变的前提下,提高基准时钟频率,可使闸门时间缩短,即提高测试速度。
27.5 下载验证
首先我们打开等精度频率计实验工程,在工程所在的路径下打开top_cymometer/par文件夹,在里面找到“top_cymometer.qpf”并双击打开。注意工程所在的路径名只能由字母、数
字以及下划线组成,不能出现中文、空格以及特殊字符等。工程打开后如图 27.5.1所示:
image495.png

图 27.5.1 等精度频率计实验工程

然后将FPGA的F3引脚和F2引脚用一根杜邦线或者跳帽连接起来, 最后连接电源线并打开电源开关。接下来我们下载程序,等精度频率计实验功能。工程打开后通过点击工具栏中的“Programmer ” 图 标 打 开 下 载 界 面 , 通 过 “Add File ” 按 钮 选 择 top_cymometer
/par/output_files目录下的“top_cymometer.sof”文件。开发板电源打开后,在程序下载界面点击“Hardware Setup”,在弹出的对话框中选择当前的硬件连接为“USB-Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如图 27.5.2所示:
image496.png

图 27.5.2 程序下载界面


下载完成后开发板上的数码管显示500000,如下图所示,与时钟产生模块产生的时钟频率一致,等精度频率计实验下载验证成功。
实物图.JPG

图 27.5.3 实验结果  


出0入0汤圆

发表于 2019-6-13 20:59:26 | 显示全部楼层
收藏了!

出0入12汤圆

发表于 2019-6-13 21:03:11 | 显示全部楼层
那么,前级整形电路怎么设计?

出0入0汤圆

发表于 2019-8-16 16:37:43 | 显示全部楼层
楼主 后来搞定了没

出0入0汤圆

发表于 2019-8-26 08:39:53 | 显示全部楼层
造福群众啊,好样的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 10:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表