prince2010 发表于 2016-2-27 15:25:35

计数器的Verilog代码怎么写才能满足高频计数?

需求:采集两个信号上升沿之间的时间间隔。

思路:把外部高精度的晶振信号(10MHz)通过FPGA内部的PLL倍频后(如400MHz)作为时间计量单位,第1个信号来时,计数器开始计数,第2个信号来时,计数器停止计数,通过计算计数器在两个信号上升沿之间的计数值之差来得到二者的时间间隔。

问题:Verilog代码该怎么写?

说明:计数器32位。

PS:没接触过FPGA,而据说Verilog代码写法很讲究。恳请大伙指点一下。{:handshake:}

90999 发表于 2016-2-27 15:32:10

PLL 内部精度够? 你要采样多少频率的信号?

jm2011 发表于 2016-2-27 15:41:21

感觉实现起来不难啊,

可能还有没有考虑到的地方,听大家的讨论;

Oliver 发表于 2016-2-27 15:46:27

32位这么长的进位线跑几十兆吧,
随便一本书都有讲的,建议沉下心基础搞懂

jm2011 发表于 2016-2-27 16:26:01

明白了,主要是时序不好满足吧?

不过如果两个信号比较近可以使用移位而不是加法来记数;

但要是长的话怎么办?

a9191389 发表于 2016-2-27 17:37:11

小菜一碟,
fpga都不懂,给你verilog代码又如何呢?

prince2010 发表于 2016-2-28 07:57:01

90999 发表于 2016-2-27 15:32
PLL 内部精度够? 你要采样多少频率的信号?

频率不高,两个信号都是1HZ,也就是秒脉冲啦

prince2010 发表于 2016-2-28 07:59:12

jm2011 发表于 2016-2-27 16:26
明白了,主要是时序不好满足吧?

不过如果两个信号比较近可以使用移位而不是加法来记数;


就是两个秒脉冲信号。
主要问题应该就是你说的时序不好满足。

wenfeiexe 发表于 2016-2-28 09:15:44

现在都啥年代了,综合器已经非常强大了,你只要加好时序约束就行了,如果综合不下去,那肯定行不通,书上那些小技巧肯定也不管用

always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
                start_d1 <= 1'b0;
        else
                start_d1 <= start;
end

assign start_det = start & (~start_d1);


always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
                stop_d1 <= 1'b0;
        else
                stop_d1 <= stop;
end

assign stop_det = stop & (~stop_d1);

always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
                cnt_en <= 1'b0;
        else if(start_det)
                cnt_en <= 1'b1;
        else if(stop_det)
                cnt_en <= 1'b0;
end

always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
                cnt <= 32'b0;
        else if(cnt_en)
                cnt <= cnt + 1'b1;
end

start, stop 是异步信号要先用clk 打2拍同步

FPGA_WALKER 发表于 2016-2-28 10:16:21

wenfeiexe 发表于 2016-2-28 09:15
现在都啥年代了,综合器已经非常强大了,你只要加好时序约束就行了,如果综合不下去,那肯定行不通,书上那 ...

你这个想法是错的,小型设计可能通过时序约束就解决了问题,但在大型设计里面尽量少的通过时序约束去解决问题,要从重构rtl的方向解决复杂的时序问题,比如说你可以看xilinx的时序方面文档,里面提到时序约束的其中一条原则是:约束越少越好,尽量通过重构代码解决时序问题,而不是通过约束解决时序问题。

lllaaa 发表于 2016-2-28 10:30:29

建议换成tdc-gp22来完成你要的工作。目测lz是做驯服钟

FPGA_WALKER 发表于 2016-2-28 10:36:07

楼主想要的是可以跑到很高频率下的计数器,其实方法有很多,比如:超前进位加法器,LFSR实现的计数器等等。

3DA502 发表于 2016-2-28 10:56:51

本帖最后由 3DA502 于 2016-2-28 11:16 编辑

波浪计数器也可以的,反正读取是低速的,用一个TFF做400MHz闸门控制就行了

边沿信号触发TFF寄存器,控制400MHz乒乓切换到两个计数通道

空闲计数器在秒脉冲的下降沿锁存输出,并清零

module SecondCount(clk, in, out);

input clk, in;
output out;

sunshulin 发表于 2016-2-28 14:06:15

楼住的这种测量方法是不对的 根本就测不准的 ,打个比方说看看千分尺的测量原理,测量时间也是这个原理,既然没接触过FPGA那就推荐你一个芯片tdc7200

prince2010 发表于 2016-2-28 17:18:15

wenfeiexe 发表于 2016-2-28 09:15
现在都啥年代了,综合器已经非常强大了,你只要加好时序约束就行了,如果综合不下去,那肯定行不通,书上那 ...

现在我的代码和你的基本一致,静态时序分析过不了。。。。。。。

prince2010 发表于 2016-2-28 17:22:36

FPGA_WALKER 发表于 2016-2-28 10:36
楼主想要的是可以跑到很高频率下的计数器,其实方法有很多,比如:超前进位加法器,LFSR实现的计数器等等。 ...

是的。其实就是加1计数器。

DWDM 发表于 2016-2-28 17:42:28

{:lol:} 那么准有什么用 ,最牛的GPS1pps都有15~60ns 抖动,数字锁相环+长时间统计才是王道

zaldy30 发表于 2016-2-28 17:45:17

我这样行不行?
module test(clk,trg,outcnt);
input clk;
input trg;
output outcnt;
reg    outcnt;


reg cnt;
reg sty;

always @(posedge clk)
begin

sty<=sty;
sty<=trg;

if(sty==2'b01)begin outcnt<=cnt; cnt<=1; end
else            cnt<=cnt+1'b1;
end

endmodule

3DA502 发表于 2016-2-28 18:57:30

本帖最后由 3DA502 于 2016-2-29 21:54 编辑

周末好无聊,这个是可以把每一个脉冲宽度都输出的方案,看看大家能不能给出更好的
module test(clk,trg,outcnt);
input clk;/* 这是400MHz时钟*/
input trg;/* 这是GPS的1pps信号*/
output outcnt;/* 这是计数值定义输出*/
reg    outcnt;/* 这是计数值缓存*/
reg rValve;/* 这是AB计数器切换*/


reg cnt1;/* 这是A计数器*/
reg cnt0;/* 这是B计数器*/

/**************************/
always@(posedge trg)/* 每个1pps信号上升沿,触发AB计数器切换*/
begin
    rValve <= ~rValve;
end

/**************************/

always @(posedge clk)
begin
        if(rValve == 1'b01 )
        begin
                cnt1 <= cnt1 + 1;/* 当切换控制是1时,A计数器对400MHz计数*/
        end
        else
        begin
                cnt0 <= cnt0 + 1; ;/* 当切换控制是0时,B计数器对400MHz计数*/
        end
end

/**************************/
always @(negeage trg)/* 当1pps信号的下降沿时候,把空闲的AB计数值进行转移,并置零,为下个上升沿切换做准备*/
begin
        if(rValve == 1'b00 )
        begin
                outcnt <= cnt1 ; /* 非阻塞赋值*/
                cnt1 <= 32'b0;   /* 非阻塞赋值*/
        end
        else
        begin
                outcnt <= cnt0; /* 非阻塞赋值*/
                cnt0 <= 32'b0; /* 非阻塞赋值*/
        end
end

/**************************/
endmodule

prince2010 发表于 2016-2-28 18:58:28

DWDM 发表于 2016-2-28 17:42
那么准有什么用 ,最牛的GPS1pps都有15~60ns 抖动,数字锁相环+长时间统计才是王道
...

没错,但是我的装置要求在GPS失锁后还能输出PPS信号,如果采样频率太低,这个PPS信号精度怎么保证?

amote 发表于 2016-2-28 20:00:45

prince2010 发表于 2016-2-28 18:58
没错,但是我的装置要求在GPS失锁后还能输出PPS信号,如果采样频率太低,这个PPS信号精度怎么保证? ...

楼主 你好! 可能需要增加些时统的概念;选了篇小册子,希望有帮助:
=============================================

prince2010 发表于 2016-2-29 08:26:09

3DA502 发表于 2016-2-28 18:57
周末好无聊

代码有些看不太明白,可否注释一下,比如trg是啥?测试原理是什么?{:handshake:}

wiser803 发表于 2016-2-29 09:20:28

写个fpga计数器程序并不难,关键是输入波形带干扰怎么处理。

YFM 发表于 2016-2-29 19:32:46

一般计数器结构是D触发器的输出通过组合逻辑加1后反馈到D触发器的输入,在下一个时钟来的时候这个加1的组合逻辑需要输出稳定,然后时钟来的时候D触发器输出加1的值。所以影响速度的因素是这个加1组合逻辑的时延。楼主可以先400MHz二分频,然后再二分频,最后再高比率分频。这样高频端分频系数小对应的分频器的组合逻辑规模小时延小。缺点是后续的分频的时钟是前一级分频的输出,也就是说后级输出的信号是没有完全同步在系统clk时钟上的。

NJ8888 发表于 2016-2-29 19:39:06

YFM 发表于 2016-2-29 19:32
一般计数器结构是D触发器的输出通过组合逻辑加1后反馈到D触发器的输入,在下一个时钟来的时候这个加1的组合 ...

同意楼上

prince2010 发表于 2016-2-29 20:29:40

YFM 发表于 2016-2-29 19:32
一般计数器结构是D触发器的输出通过组合逻辑加1后反馈到D触发器的输入,在下一个时钟来的时候这个加1的组合 ...

我也想到了这点,就是因为网上说异步不好才不敢用{:sad:}

页: [1]
查看完整版本: 计数器的Verilog代码怎么写才能满足高频计数?