0
\$\begingroup\$

I'm implementing some modules using VHDL and for some of them I need the FPGA's global clock signal, and for some others I need to update to two different frequencies. A common solution to this is using frequency dividers based on counters, so if I have a 8MHz clock and I need 2KHz, I can just count up to 4000 and generate and enable signal for the other components.

But when many clocks are needed, a way of reducing the size for frequency dividers could be cascading them. For example, to generate 2KHz and 1Hz, I could count up to 2000 using the previous generated 2KHz enable signal.

My problem is that, since it's a good practice for scalability and performance the use of a single global clock, using the previous clocks as enable signals causes delays on subsequent clock generation. This is my VHDL code to generate two new clocks based on the global one:

library ieee;
use ieee.std_logic_1164.all;

entity clock_generator is
    generic(
        global_freq  : integer;
        display_freq : integer
    );
    port(
        clk      : in  std_logic;
        reset    : in  std_logic;
        clk_2KHz : out std_logic;
        clk_1min : out std_logic
    );
end clock_generator;

architecture behavioral of clock_generator is

    constant MAX_2KHz : integer := (global_freq / display_freq) - 1;
    constant MAX_1min : integer := (display_freq * 60) - 1;

    signal cnt_2KHz : integer range 0 to MAX_2KHz;
    signal en_2KHz  : std_logic;

    signal cnt_1min : integer range 0 to MAX_1min;

begin

    gen_2KHz : process(clk, reset)
    begin
        if reset = '0' then
            cnt_2KHz <= 0;
        elsif rising_edge(clk) then
            if cnt_2KHz = MAX_2KHz then
                cnt_2KHz <= 0;
            else
                cnt_2KHz <= cnt_2KHz + 1;
            end if;
        end if;
    end process;

    en_2KHz <= '1' when cnt_2KHz = MAX_2KHz else '0';

    gen_1min : process(clk, reset)
    begin
        if reset = '0' then
            cnt_1min <= 0;
        elsif rising_edge(clk) then
            if en_2KHz = '1' then
                if cnt_1min = MAX_1min then
                    cnt_1min <= 0;
                else
                    cnt_1min <= cnt_1min + 1;
                end if;
            end if;
        end if;
    end process;

    clk_2KHz <= en_2KHz;
    clk_1min <= '1' when cnt_1min = MAX_1min else '0';

end behavioral;

If I simulate its behavior, we can see that the first clock is generated synchronized with the global one, but since the second depends on the first one's activation, it's delayed one cycle of the global clock:

enter image description here

So my questions are:

  1. How can I get full clock synchronization without using individual frequency dividers?
  2. Could this synchronization cause any problem on some kind of special systems or is this just negligible?
\$\endgroup\$
  • 1
    \$\begingroup\$ "using the previous clocks as enable signals causes delays on subsequent clock generation." That assumption is wrong. In fact they do NOT cause delays as everything changes on the one (master) clock edge signal. In contrast to using the derived signals in subsequent rising_edge(generated_clock) which DOES generate clock skew. \$\endgroup\$ – Oldfart Dec 9 '18 at 19:35
  • \$\begingroup\$ Using a cascade of clock enabled instead of a cascade of "user defined clocks" is the right design approach. The first principle in design is to write a FULLY synchronous design. So every register output is driven by the same clock. The second design principle should be use synchronous resets and the third principle use high-active logic. \$\endgroup\$ – Paebbels Dec 9 '18 at 23:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.