Как найти частоту делителя часов?

Предположим, у меня есть на моей плате часы 100 МГц и следующий делитель часов:

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;

Какова будет частота новых часов (clk_out)?

1 ответ

Делители часов бывают разных вкусов. Если вы смотрите на высокоскоростные часы, например, при использовании памяти с двойной скоростью передачи данных (DDR), вы действительно хотите использовать менеджер часов FPGA. Например, Xilinx Digital Clock Manager (DCM). Они обеспечивают очень стабильный выходной синхроимпульс.

Для часов с более низкой скоростью вы можете использовать предложенный вами делитель. Тем не менее, они также бывают разных вкусов. Если коэффициент деления является целым числом, вы можете использовать простой счетчик, как вы делаете. В следующем примере делитель тактовых импульсов всегда делит входную частоту на 2 (например, 50 МГц -> 25 МГц), а затем делит далее на установленное соотношение (например, 25/3 = 8 1/3 МГц).

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;

Если вам нужна большая свобода, например, преобразование 50 МГц в 3 МГц, вы можете использовать дробный тактовый делитель. Однако этот компонент требует гораздо больше ресурсов. Кроме того, на выходе синхроимпульсов много джиттера в виде синхроимпульсов неравной длины. Но это обычно не большая проблема с низкоскоростными часами.

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;
Другие вопросы по тегам