Как найти частоту делителя часов? - PullRequest
0 голосов
/ 09 мая 2018

Предположим, у меня на плате есть часы с тактовой частотой 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 Ответ

0 голосов
/ 09 мая 2018

Часовые делители бывают разных вкусов. Если вы смотрите на высокоскоростные часы, например, при использовании памяти с двойной скоростью передачи данных (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;
...