How to compute the frequency of a clock

Clock and digital design

When you use an FPGA you always need a clock. When you start the debug of your VHDL layout code on FPGA, often your design doesn’t work as it should!

It’ the hardware my friend!

Digital design has a big advantage w.r.t analog design:

if you implement a (good) synchronous design and simulate it, you are very confident that the design can work as it should.

But the reality is different!

I have a bad news when you start to debug your design on FPGA it always doesn’t work… Did it happen to you?

Figure1 – clock signal example
Figure1 – clock signal example

There is also a good news… If you did a good simulation of your digital design, often the problems you get during the test on a board are of the same type:

  1. you didn’t handle the reset pin
  2. the clock signal is absent or of a wrong value

Maybe you are thinking… it is not possible that the main errors are the clock and reset!

Well, if you did simulate your VHDL design, and you did respect the golden rules for a digital design (you can find some example and the available courses here) external reset and clock are often the main issues of your design!


How can we detect the clock?

For the reset pin, the solution is very simple: you can map reset to an output pin connected to a LED so you can check if the reset signal is working fine…

What about the clock?

Here the issue is a bit different. The clock is a periodic signal changing very fast, so you cannot directly connect to a LED but…. if you divide the clock rate to a “human” frequency you can use it to blink a LED.

I mean, connect the clock to a module that implements a counter to generate a slow signal that can drive a LED for instance at the toggling rate of one second. Doing this you can monitor if your clock is present.

It is a good solution but…. How can you measure the clock frequency? You can guess something from the blinking rate but is only a rough estimation.


Click Here to enroll the free course

“How To Measure Clock Frequency in FPGA”

Compute the clock frequency digitally

If we need to verify the clock frequency, we can

  1. use an oscilloscope
  2. count the clock rate

The first solution maybe didn’t need a blog post or further explanation

So let’s see how to implement a clock frequency counter.

The basic idea is reported in the figure

Figure2 – Clock counter architecture
Figure2 – Clock counter architecture


As you can see, we use a reference clock to detect a test clock.

The reference clock counts for a fixed number clock cycles. This defines a time interval. For instances if the test clock is 50 MHz, i.e. 20 ns, the counting value is 2^12, counting time period is:

20 ns * 2^12 = 81.920ns = 81,920 us

In order to compute the test clock frequency, we need to know how many clock cycles of the test clock are present into the reference interval. So we can use the reference clock counter to start and stop the clock test counter.

Maybe an example should clarify:

  • REF clock = 50 MHz (20 ns)
  • REF clock count = 2^12

every 2^12 reference clock counting the test clock counts for 10240 as in simulation reported in Figure3

The test clock frequency will be:

10240/4096* 50 MHz = 2.5*50 = 125 MHz (8 ns)

Figure3 – VHDL code clock counter simulation with test clock 125 MHz
Figure3 – VHDL code clock counter simulation with test clock 125 MHz


A second example, if test clock counter counts for 2048

The test clock frequency will be: 2048/4096* 50 = 0.5 * 50 = 25 MHz (40 ns)

as in simulation reported in Figure4

Figure4 – VHDL code clock counter simulation with test clock 25 MHz
Figure4 – VHDL code clock counter simulation with test clock 25 MHz

VHDL code for the clock frequency counter

As we saw, the basic idea in clock frequency computing is very simple, but we have to pay attention in implementing the VHDL component.

As you can see the two clock, reference clock, and test clock, are asynchronous.

When we have to handle two different asynchronous clock domain we need to pay attention in clock domain crossing (CDC)

In the Figure2, it is clear that the control signal for the test counter is resynchronized in the test clock domain in order to control the counter test. If you do not perform such re-synchronization the layout tool could implement the correct control logic for the clock test domain.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity clock_freq_counter is
port (
  i_clk_ref            : in  std_logic;
  i_clk_test           : in  std_logic;
  i_rstb               : in  std_logic;
  o_clock_freq         : out std_logic_vector(15 downto 0));
end clock_freq_counter;

architecture rtl of clock_freq_counter is

-- r1_  register con clock reference domain
-- r2_  register con clock test domain

--  CLOCK REFERENCE signal declaration
signal r1_counter_ref              : unsigned(12 downto 0);  -- 12+1 bit: extra bit used for test counter control
signal r1_counter_test_ena         : std_logic;
signal r1_counter_test_strobe      : std_logic;
signal r1_counter_test_rstb        : std_logic;
--  CLOCK TEST signal declaration
signal r2_counter_test             : unsigned(15 downto 0); -- clock test can be up-to 16 times clock ref
signal r2_counter_test_ena         : std_logic;
signal r2_counter_test_strobe      : std_logic;
signal r2_counter_test_rstb        : std_logic;

p_counter_ref : process (i_rstb,i_clk_ref)
  if(i_rstb='0') then
    r1_counter_ref                 <= (others=>'0');
    r1_counter_test_ena            <= '0';
    r1_counter_test_strobe         <= '0';
    r1_counter_test_rstb           <= '0';
  elsif(rising_edge(i_clk_ref)) then
    r1_counter_ref            <= r1_counter_ref + 1;  -- free running
    -- use MSB to control test counter
    r1_counter_test_ena       <= not r1_counter_ref(r1_counter_ref'high);
    -- enable storing for 1024 clock cycle after 256 clock cycle
    if(r1_counter_ref>16#1100#) and (r1_counter_ref<16#1500#) then
      r1_counter_test_strobe     <= '1';
      r1_counter_test_strobe     <= '0';
    end if;

    -- enable reset for 1024 clock cycle; after 1024 clock cycle from storing
    if(r1_counter_ref>16#1900#) and (r1_counter_ref<16#1D00#) then
      r1_counter_test_rstb    <= '0';
      r1_counter_test_rstb    <= '1';
    end if;

  end if;
end process p_counter_ref;


p_clk_test_resync : process (i_clk_test)
  if(rising_edge(i_clk_test)) then
    r2_counter_test_ena        <= r1_counter_test_ena     ;
    r2_counter_test_strobe     <= r1_counter_test_strobe  ;
    r2_counter_test_rstb       <= r1_counter_test_rstb    ;
  end if;
end process p_clk_test_resync;

p_counter_test : process (r2_counter_test_rstb,i_clk_test)
  if(r2_counter_test_rstb='0') then
    r2_counter_test         <= (others=>'0');
  elsif(rising_edge(i_clk_test)) then
    if(r2_counter_test_ena='1') then
      r2_counter_test    <= r2_counter_test + 1;
    end if;
  end if;
end process p_counter_test;

p_counter_test_out : process (i_rstb,i_clk_test)
  if(i_rstb='0') then
    o_clock_freq         <= (others=>'1');  -- set all bit to '1' at reset and if test clock is not present
  elsif(rising_edge(i_clk_test)) then
    if(r2_counter_test_strobe='1') then
      o_clock_freq         <= std_logic_vector(r2_counter_test);
    end if;
  end if;
end process p_counter_test_out;

end rtl;

In the VHDL code, the r1_ and r2_ prefixes denote the reference and test clock domain respectively.

As clear the “p_clock_test_resync” process resynchronize the control signal versus the test clock domain, and this guarantee the layout tool to work fine in the test clock domain.

In the VHDL code for clock counter, the reference counter is set to 12 bit and the test counter is 16 bit: the test clock can run up to 16 times (16-12 bit: 2^4 = 16) faster than the reference clock. If the test clock runs faster than 16 times, the 16-bit counter will wrap around and the frequency we detect the wrong frequency.

In this case, if we know the point we can compensate the wrap around in the clock computation equation adding 2^16 to the clock test counter.

For instance, reference clock = 1 MHz, test clock = 18 MHz

Every 2^12 clock reference cycle, the test clock counter will count

2^12*18 = 73728

but if we are using a 16 bit counter the value we get will be:

73728-65536 = 8192

In this case, if we do not take into account the counter wrapping the frequency we are computing will be

2^12/8192 * 1 MHz = 0.5 MHz

instead of 18 MHz!


Clock Domain Crossing strategy

In the VHDL code of the clock frequency counter, we are using an extra bit on the reference counter. This trick is used to guarantee the correct clock domain crossing. As you can see, the strobe signal will be stable for 256 clock reference cycle then the reset signal will be asserted after 1024 clock reference cycle after the strobe signal de-assertion.

Using this strategy, we will assure that our clock frequency counter can work also with test clock slower than reference clock. How slow?

In this implementation 256 times slower!

In the simulation of Figure3 and Figure4, there are some examples that simulate test clock faster than reference and test clock slower than reference clock.


Click Here to enroll the free course

“How To Measure Clock Frequency in FPGA” 


Clock Counter VHDL code live demo

In the video below you can watch an example of clock frequency counter implementation.

The design is implemented on a DE0 Altera board where we use an internal PLL to generate different internal clocks selected by dip switch as clarified in Figure5

Figure5 – Clock counter test architecture on DE0 board
Figure5 – Clock counter test architecture on DE0 board

The selected clock will be used as test clock. The reference clock is the 50 MHz board clock.

In the seven segment display is reported the clock frequency counter value of hexadecimal value.

The clock frequency estimated will be:

HEX_VALUE/2^12 * 50 MHz

In the video to can watch the implementation


If you appreciated this post, please help us to share it with your friend.

If you need to contact us, please write to:

We appreciate any of your comment, please post below:


Leave a Reply

Your email address will not be published.