Monday, October 12, 2015

Basic Frequency Meter with FPGA , Verilog HDL , WireFrame FPGA

   In the series of learning FPGA project , here is simple little project to measure frequency with counter and few 7 segment display.

Measuring Maxim DS32Khz output absolute bang on


Theory Of operation 


there is nothing much to it actually , you need a counter (count)  which increments with the rising edge of input signal (sigin)  and you have to have a control (gate) through gate when counter counts when it does not. so if you keep gate open for 1sec flat , so after 1sec the value you have with the counter (count ) is your frequency.


lets look at this timing diagram , it has a signal input sigin, gate pulse gate, counter value count , frequency display freq, 

the gate goes high (active ) for a fixed amount of time ,1 Second ,when gate is high(active) counter start increment on every rising edge of the sigin  and keep on increment till gate is high , as soon as gate goes low , counter stop at the value how many rising edge was there in the sigin during the gate was high(active) .  as gate time is 1 Second so what ever value is there in the count is your frequency , 

Now we need to update this value to frequency display . as soon as gate time expires it put the value of count to frequency display register.

for next sample gate pulse again go high and clear the count register also. 



Verilog Model 

 first of all you need a counter , which increment on input and give a output , we have already implemented such counter in our last project but still here is the code
module timer(rst, clk, count);// a counter

parameter size = 32;

input rst;                                                  // These inputs/outputs represent
input clk;                                                  // connections to the module.

output [size-1:0] count;

reg [size-1:0] count=0; // Signals assigned
                      // within an always
                      // (or initial)block
                      // must be of type reg



// The always statement below is a parallel
// execution statement that
// executes any time the signals
// rst high to low or clk transition from low to high
always @ (posedge clk or negedge rst )
    begin
      if (!rst) // This causes reset of the cntr
count = 0;
     else if(count<32'hFFFFFFFF)
 begin
count = count + 1'b1;
 end

end

endmodule


you will the another module to drive counter modules input  , it will be the freq_meter module which will control this timer module by providing it gate (rst) , input signal (clk) and taking it's count value and putting it to a 7 segment display

freq_meter.v
module freq_meter(
    clk,
segment,
    digit,
sigin

    );
output [7:0]segment;
output [7:0]digit;
input clk;
input sigin;

reg [7:0]digit = 8'b01;
reg [31:0]freq;
wire [3:0]dispdata[7:0];
reg [2:0]digit_scan;
reg [23:0]disp_scanner;

reg [31:0]gatecounter;
reg gate;
wire [31:0]count;
bcd_to_seg s1(dispdata[digit_scan],segment);
bin_to_bcd b1(freq,dispdata[0],dispdata[1],dispdata[2],dispdata[3],dispdata[4],dispdata[5],
dispdata[6],dispdata[7]);

counter c1(gate,sigin,count);
always @(posedge clk )
begin



if(!gatecounter)
begin

gatecounter = 'd25000000;
gate =0;
freq = count;

end // if  !gatecounter end
else
begin
gate =1;
end

gatecounter = gatecounter - 1'b1;


disp_scanner = disp_scanner +1'b1;
if(disp_scanner=='d50000)
begin
digit = {digit[6:0],digit[7]};
digit_scan=digit_scan+'d1;
  disp_scanner = 0;
end

end // always end

endmodule



after this you have a binary data in freq but to be displayed at 7 segment display you need to first covert it into BCD , which will be done by bin_to_bcd.v module, and then take that bcd and covert it to 7 segment code that is done by bcd_to_seg.v ,  all the source code is available at my github repo. 

Hardware. 

Test & Validation 
Accuracy depended on the on board 25Mhz crystal  and +/- 1 digit

Maxim DS32KHZ TCXO, ouput , very accurate very stable
Maxim DS32KHZ TCXO, ouput , very accurate very stable
30 Mhz square wave output of Signal gen
This signal is square wave output of my home made signal gen
i have very crude home made  DDS based signal gen , at 30Mhz singal drift with temp , as seen at the time of image it drifted to 30.003446Mhz from 30Mhz


Same Module tested with Altera Cyclone II FPGA






Source Code and Design file 
all the source code is available in the github repo 
https://github.com/circuitvalley/WireFrame-FPGA/tree/master/VerilogHDL-Modules/Frequency_Meter/

8 comments:

  1. What would be the maximum frequency this could detect? Would it work up to 125MHz?

    ReplyDelete
    Replies
    1. certainly it can , but as it has only 8 digit , either you add one more digit or you have resolution of 10Hz instead 1Hz. in both case little modification to verilog code is required.

      Delete
  2. Are you using a 555 timer to generate the waveform and frequency for the FPGA board?

    ReplyDelete
  3. if you cant make a tachometer with FPGA cyclone IV

    ReplyDelete
  4. Could this work with a spartan 3e starter pack fpga? Thanks for the post.

    ReplyDelete
    Replies
    1. it will work with any FPGA with enough cells to fit model.

      Delete
  5. Hi Great Work,

    I am new to FPGA. Pl let me know how to send freq [reg [7:0]freq;] value to serial monitor. In verilog I am using an array [ wire [7:0] BIT_ARRAY[7:0] ;] to assign value to array elemnts & sending it to Serial Monitor.

    ReplyDelete