Verilog设计练习 基于FPGA的等精度频率计

很重要的一点就是弄明白等精度测频的原理,我在网上找了很多,看似简单但是实操起来还是自认为很复杂的。。况且在verilog里面时序分析又特别重要,稍有不慎就弄不出结果来。

计算的公式倒是很简单、、

{\begin{equation} f=\frac{N_x}{N_b}f_b \end{equation}}

Nx和Nb分别是被测信号和基准时钟的脉冲数,fb是基准时钟频率。

这里直接用EGO板子的100MHz内部时钟源当作基准时钟。

核心是测频,剩下的就是数码管的显示,之前做过很多练习,直接可以把以前的显示程序拿来用(比如某番茄钟)。 

总体思路:

        1.生成一段一定时长的,与输入信号同步的闸门信号;

        2.在该信号上升沿开始脉冲计数,下降沿停止脉冲计数并立即将有关数据进行寄存留待计算;

        3.由于使用ip核进行计算,将计算结束标志信号作为ip的reset信号,将闸门信号下降沿作为计算开始信号。

虽然没什么必要,但还是当时不知道脑子怎么想的去用ip核做浮点运算。不管怎么说,本来可以通过乘以10或者100来获取小数点后一位或第二位(以此类推)的数值,但是貌似在verilog书写计算式的时候会有一个位宽的要求。

所以完全可以用下面写法直接算结果、、

wire [31:0]fx;
assign fx=Nx*(fre_b/Nb);

加了括号,先算除法,不然Nx很大,fre_b=100M很大,乘出来可能因为超过位宽导致结果不对。

其实这次走点弯路也相当于学了一点新的知识,毕竟floating-point这个ip核还能实现指数幂、平方根、取对数、比较器等功能,也许以后会有点用、、

上面的U2_1 和U2_2是为了产生闸门信号。闸门信号时长自己定,本工程设计的闸门信号有效时间约为0.5s。

接下来就是计数Nx和Nb。。这里涉及到异步时序的问题。以前写的工程都是同步的,也就是只有系统时钟clk或者由其产生的信号作为always里的条件,但是这次设计到了输入信号边沿的测量,捣腾了很长时间。

(注:下述代码仅仅为一部分代码,不是整个.v文件)

上图中我一开始写的是红色部分的代码,也就是考虑通过寄存来获取被测信号上升沿(当然也可以寄存两次),但是最后结果总是和实际值有很大偏差(5%到10%左右),仿真波形却完全没有问题,实在是百思不得其解。

最后参考了一下其他写法,改为绿色部分就OK了。

绿色部分直接将被测信号signal摆到always的边沿条件里。一开始是这样写的,发现在implementation时会报错(place design error),所以就参考之前写的dht温度传感器的形式用寄存方法,没想到最后还是有问题。。

按绿色写法的话,在约束文件里面要加一条语句:

set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports signal]

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets signal]

下面给出一些仿真波形的示例

上图中,cal_start和cal_rst_over是用来控制ip核的相关信号的。如上所述,这里设计的在闸门信号下降沿使能ip核以进行浮点运算。之后需要对ip核进行reset以进行下一次运算。

ip核的大致配置见上,其余端口配置均类似。

仿真波形图给出一个示例,可以看到ip核运算需要一定的时间。在valid信号变为1后结果才可信。ip的result_valid需要通过reset拉低,否则valid将一直保持高有效状态。

至于输出的浮点数,采用的是IEEE 754那一套标准,比较麻烦。

详细定义可以见我室友写的博客:

IEEE浮点数_howardSunJiahao的博客-CSDN博客

关于该ip的运算更多细节可以参考xilinx的官方文档。

​​​​​​https://www.xilinx.com/content/dam/xilinx/support/documentation/ip_documentation/floating_point/v7_1/pg060-floating-point.pdf

这里也仅仅是一个很简单的应用,甚至也许会有错误我没发现。人比较菜、、、

gate_a是一个方波信号,gate_s同样,只不过gate_s和输入信号signal同步。

Example1

                  生成1Hz方波(闸门信号gate_a)

                  每(49999999+1)/100M=0.5s取反

                  生成其他频率时钟同理  

    reg [26:0] clkcnt;  //位宽由所需位数决定。99999999的二进制数为27位
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            clkcnt<=0;
            gate_a<=1;
        end
        else if(clkcnt==27'd49999999)begin
            clkcnt<=0;
            gate_a<=~gate_a;
        end
        else begin
            clkcnt<=clkcnt+1;
            gate_a<=gate_a;
        end
    end

Example2   

生成与输入信号同步的闸门信号gate_s

    reg gate_a_r;
    always @(posedge signal or negedge rst_n)begin
        if(!rst_n)
            gate_a_r<=0;
        else 
            gate_a_r<=gate_a;
    end
    assign gate_s=gate_a_r;

之前虽说是在闸门信号下降沿立即进行Nx和Nb的寄存,但是实际上写的代码还是有点时间间隔。

 Nx比Nb赋值的时间晚一点,因为Nb是在posedge clk被赋值,而Nx是在posedge signal被赋值。

目前这样做好像暂时没遇到什么问题。当然都在posedge clk被赋值也是可以的。

作者有时间再深究吧。。

下面分别是20kHz和2kHz的测量效果。方波来自硬木口袋信号发生器。输入信号接普通I/O引脚。

该信号源质量不是很好- -

貌似应该接全局时钟引脚什么的,还没有研究到这个份上。

  

srds,有时候仍然会显示出一些奇怪的数出来= = 

实际上之前在MSP430尝试开发了等精度测频,不过误差很大很大,比通常的测周法测频法还要大很多。。(5000Hz测得5030Hz之类的)

思路:用两个定时器,一个定时器计基准时钟脉冲(内部16MHz DCO),另一个定时器用capture模式计数输入信号脉冲数Nx。

但是16MHz 系统时钟貌似不是很稳定,之后得想办法进一步减小误差才行。

总结:

调试是一个艰辛的过程,有时候莫名其妙就好了,莫名其妙就坏了。。有些问题深邃而不可解,直呼自己水平太菜,不如直接开摆,嘻嘻。

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值