Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20713 Discussions

Reciprocal Counter

Altera_Forum
Honored Contributor II
1,322 Views

Hi all,  

 

I'm trying to build a reciprocal frequency counter in an FPGA (A cyclone 2 on a DE2 board to be exact). I've been floundering the last 2 weeks with getting it working correctly  

 

I'm interfacing it to a nios2 running uClinux (hardware driver is written and sending data via ethernet to my PC for saving and analysis).  

 

 

The reciprocal counter consists of 3 individual counters. One is a simple 32 bit counter clocked by the input signal, this gives you the number of signal pulses over which to average the phase over. The other two are period counters, they count the duration of the input signal HIGH in numbers of fast clock pulses (100 Mhz system clock - 10Mhz Oven controlled external oscillator times 10 in a pll). The only difference is that one of the counters counts the negative pulse duration and the other counts the positive pulses - this takes allows you to count non-50% duty signals.  

 

A global trigger (1, 10, 100hz selectable) is used to save the counters and to interrupt the cpu. The OS reads the values of the three counters and sends them off to the PC, synchronously with the trigger. The pc simply averages the positive and negative period counts and divides by the number of pulses in order to get an average period. One over which is the average frequency  

 

Since the input signal is not synchronous with the trigger, it is quite possible that you get a trigger in the middle of a period count. This throws off the average because you are really measuring less full signal periods than the coarse counter would suggest. The average is thrown off enough that the frequency dances +-3 Hz, which with a counting time of 1second is about 3 times higher than it should be.  

 

The sollution I came up with is a scheme where you count each period individually and then add it to the total count only if you see negative edge of the signal.  

 

The problem is that it isn't working properly. The period count dances around as much as with the simple version of the counter. And Quartus is throwing me a clock hold violation - the timing constraints are not met.  

 

In general I just need a second (third, fourth, etc.) pair of eyes to look over my code and tell me what I could do to improve it. 

 

module phase_counter_hw( input clock, input sig, input trigger, output reg phase ); parameter PHASE_RESOLUTION = 32; reg full_count; reg buffer; reg ready, ignore; always @(posedge(trigger)) begin phase <= full_count; end always @(posedge(clock) or posedge(trigger)) begin if (trigger) begin full_count<=0; buffer <= 0; ready <= 0; ignore <= 1; end else if (sig) begin ready <= 1; buffer <= buffer + 1; end /* if we triggered in the middle of a signal pulse we need to ignore that count, so after sig goes low we just drop that buffer*/ else if (ignore) begin ready<=0; buffer<=0; ignore <=0; end else if (ready) begin ready <= 0; full_count <= full_count + buffer; buffer <= 0; end end endmodule  

 

And if anyone cares: BSD licensed, so copy at will. 

 

If anyone reads fpga4fun I apologize for the spam, that forum seems pretty dead so I decided to repost here.
0 Kudos
3 Replies
Altera_Forum
Honored Contributor II
497 Views

What is the nature of the trigger signal? It appears to be asynchronous to the clock. What is it's expected duration? 

 

You at least need to resynchronize "trigger" to your clock domain before you attempt to make use of it. You are using it as an asynchronous clear or set to 66 flip-flops. you have no way to guarantee that they all take the action at the same time (due to routing delays, variations in the fabric, etc.). You need to make a "safe" copy of the trigger signal in your clock domain. 

 

something like this maybe: 

 

reg trigger_r; wire trigger_edge; assign trigger_edge = trigger_r & ~trigger_r; always @(posedge clock) trigger_r <= {trigger_r,trigger}; 

 

Then use "trigger_edge" as a synchronous input to your logic and do not use "trigger". This of course implies a few things: 

1 - You're okay with some latency on trigger. 

2 - trigger is at least two clock periods in duration. 

 

If neither of these is acceptable, there are more fancy methods that you can use to latch trigger into the clock domain. Specifically, you'll have to asynchronously latch trigger and synchronously clear it. 

 

Jake
0 Kudos
Altera_Forum
Honored Contributor II
497 Views

Currently the trigger is synchronous with the clock since its being generated in the FPGA as a divider. It is one clock cycle wide (i.e with a 100Mhz clock - 99,999,999 cycles off, 1 cycle on to have a rising edge once every second). The beauty of the reciprocal counter is that your trigger doesn't have to be very accurate, it being off by a few us is unimportant. It might be offloaded to an atomic clock as an exercise in pedantry, but thats far off in the future.  

 

The thing is, when I use a synchronously generated input signal - i.e. a divider in the fpga. Then the reading I get from the counter is exactly correct (and my fancy $10K professional counter agrees with it). When I migrate to an external signal source, it begins to act wacky even though the clock domains are supposed to be synchronized since I'm using the Oven clock out from the signal source as my external clock source. 

 

If it matters, the frequency I'm trying to measure is ~420Khz. 

 

edit: Could the problem be that since it is synchronous with the clock then the dual condition (posedge clock or posedge trigger) be causing the circuit to trigger twice in quick succession? i,e, the asynch clear is propogating through the registers while the clock is making the registers increment?
0 Kudos
Altera_Forum
Honored Contributor II
497 Views

 

--- Quote Start ---  

When I migrate to an external signal source, it begins to act wacky even though the clock domains are supposed to be synchronized since I'm using the Oven clock out from the signal source as my external clock source. 

--- Quote End ---  

 

Same clock source doesn't necessarily mean that the setup and hold times are kept for the external signal. It should be treated as unrelated in any case. 

 

It's generally easy to get setup and hold timing conflicts with asynchronous inputs. I would try to avoid them. Otherwise, the output of the respective registers must be regarded unrelated to the system clock and must be synchronized anew.
0 Kudos
Reply