How to find frequency of a clock divider ?

660 Views Asked by At

Supposing i have on my board a 100Mhz clock and the following clock divider:

entity div is
port(clk:in std_logic;
     clk_out:out std_logic);


architecture ar of div is

begin
process(clk)
variable aux:integer := 0;
variable aux2:std_logic := '0';
begin
if clk = '1' and clk'event then
aux := aux + 1;

if aux = 1600500 and aux2='0' then
aux = 0;
aux2 = 1;
end if;




if aux = 1600500 and aux2 ='1' then
aux = 0;
aux2 = 1;
end if;
end if;

clk_out <= aux2;
end process;
end;

What will be the frequency of the new clock(clk_out) ?

1

There are 1 best solutions below

0
On

Clock dividers come in many flavors. If you are looking at high speed clocks, for instance when using dual-data rate (DDR) memory, you actually want to use the FPGA's clock manager. E.g. Xilinx Digital Clock Manager (DCM). These provide a very stable, edge synchronous clock output.

For lower speed clocks, you could use the divider you suggest. However, these also come in multiple flavors. If the division ratio is integer, you can use the simple counter like you do. For this next example, the clock divider will always divide the input frequency by 2 (e.g. 50 MHz-> 25 MHz) and then further divide by the ratio set (e.g. 25/3 = 8 1/3 MHz)

library ieee;
use ieee.std_logic_1164.all;

entity simp_clk_div is
    generic(
        half_clk_div_ratio  : positive);
    port(
        input_clk  : in  std_logic;
        output_clk : out std_logic);
end entity;

architecture rtl of simp_clk_div is
    constant clk_div_cnt : natural := half_clk_div_ratio - 1;
    signal cnt : natural := clk_div_cnt;
    signal output_clk_i :  std_logic := '0';
begin
    divide : process(input_clk) begin
        if rising_edge(input_clk) then
            if cnt = 0 then
                cnt <= clk_div_cnt;
                output_clk_i <= not output_clk_i;
            else
                cnt <= cnt - 1;
            end if;
        end if;
    end process;

    output_clk <= output_clk_i;
end architecture;

entity simp_clk_div_tb is end entity;

library ieee;

architecture behavior of simp_clk_div_tb is
    use ieee.std_logic_1164.all;
    signal input_clk, output_clk : std_logic;
begin
    DUT : entity work.simp_clk_div
        generic map(
            clk_div_ratio => 3) 
        port map(
            input_clk => input_clk,
            output_clk => output_clk);

    clk_stim : process begin
        input_clk <= '0', '1' after 1 ns;
        wait for 2 ns;
        if (now > 200 ns) then wait; end if;
    end process;
end architecture;

If you want more freedom, e.g. convert 50MHz to 3 MHz, you can use a fractional clock divider. However, this component requires a lot more resources. Plus, there's a lot of jitter on the clock output, in the form of unequal length clock pulses. But that's usually not a big problem with low speed clocks.

library ieee;
use ieee.std_logic_1164.all;

entity frac_clk_div is
    generic(
        input_freq  : positive;
        output_freq : positive);
    port(
        input_clk  : in  std_logic;
        output_clk : out std_logic);
end entity;

architecture rtl of frac_clk_div is
    constant cnt_sub : positive := output_freq*2;
    signal cnt : natural := input_freq;
    signal output_clk_i :  std_logic := '0';
begin
    divide : process(input_clk) begin
        if rising_edge(input_clk) then
            if cnt < cnt_sub then
                cnt <= input_freq - (cnt_sub - cnt);
                output_clk_i <= not output_clk_i;
            else
                cnt <= cnt - cnt_sub;
            end if;
        end if;
    end process;

    output_clk <= output_clk_i;
end architecture;

entity frac_clk_div_tb is end entity;

library ieee;

architecture behavior of frac_clk_div_tb is
    use ieee.std_logic_1164.all;
    signal input_clk, output_clk : std_logic;
begin
    DUT : entity work.frac_clk_div
        generic map(
            input_freq => 50_000_000,
            output_freq => 3_000_000)
        port map(
            input_clk => input_clk,
            output_clk => output_clk);

    clk_stim : process begin
        input_clk <= '0', '1' after 1 ns;
        wait for 2 ns;
        if (now > 200 ns) then wait; end if;
    end process;
end architecture;