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?
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:
- you didn’t handle the reset pin
- 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.
Compute the clock frequency digitally
If we need to verify the clock frequency, we can
- use an oscilloscope
- 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
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)
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
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; begin -- CLOCK REFERENCE domain p_counter_ref : process (i_rstb,i_clk_ref) begin 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'; else 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'; else r1_counter_test_rstb <= '1'; end if; end if; end process p_counter_ref; ------------------------------------------------------------------------------------------------------------------------ p_clk_test_resync : process (i_clk_test) begin 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) begin 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) begin 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!
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
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: firstname.lastname@example.org
We appreciate any of your comment, please post below: