Каков наилучший способ обнаружения импульсов между двумя тактовыми доменами? - PullRequest
0 голосов
/ 13 апреля 2019

Я хочу передать импульс из часового домена clk1 в другой тактовый домен clk2, но мы не знаем, какой из них быстрее другого!Каков наилучший способ сделать это?

Спасибо,

Ответы [ 2 ]

0 голосов
/ 17 апреля 2019

Другим решением вашей проблемы является Flancter, лучше всего объясненный Доулосом:

https://www.doulos.com/knowhow/fpga/fastcounter/

0 голосов
/ 14 апреля 2019

Вам нужен синхронизатор строба.

Синхронизатор строба преобразует передний фронт на входе в изменение уровня (T-FF). Это изменение уровня передается во второй тактовый домен через синхронизатор 2-FF. Затем информация восстанавливается с помощью шлюза XOR. (Примечание: T-FF - это D-FF с XOR для инвертирования состояния на каждом высоком входном сигнале.)

Кроме того, состояние занятости может быть рассчитано для уведомления отправляющего тактового домена о состоянии всей цепи. Этот сигнал занятости может использоваться для блокировки обнаружения переднего фронта входа.

Схема выглядит следующим образом:
enter image description here

Исходный код для нескольких битов одновременно:

library IEEE;
use     IEEE.STD_LOGIC_1164.all;
use     IEEE.NUMERIC_STD.all;

library PoC;
use     PoC.sync.all;


entity sync_Strobe is
    generic (
        BITS                : positive            := 1;                       -- number of bit to be synchronized
        GATED_INPUT_BY_BUSY : boolean             := TRUE;                    -- use gated input (by busy signal)
        SYNC_DEPTH          : T_MISC_SYNC_DEPTH   := T_MISC_SYNC_DEPTH'low    -- generate SYNC_DEPTH many stages, at least 2
    );
    port (
        Clock1              : in  std_logic;                            -- <Clock>  input clock domain
        Clock2              : in  std_logic;                            -- <Clock>  output clock domain
        Input               : in  std_logic_vector(BITS - 1 downto 0);  -- @Clock1:  input bits
        Output              : out std_logic_vector(BITS - 1 downto 0);  -- @Clock2:  output bits
        Busy                : out  std_logic_vector(BITS - 1 downto 0)  -- @Clock1:  busy bits
    );
end entity;


architecture rtl of sync_Strobe is
    attribute SHREG_EXTRACT : string;

    signal syncClk1_In      : std_logic_vector(BITS - 1 downto 0);
    signal syncClk1_Out     : std_logic_vector(BITS - 1 downto 0);
    signal syncClk2_In      : std_logic_vector(BITS - 1 downto 0);
    signal syncClk2_Out     : std_logic_vector(BITS - 1 downto 0);

begin
    gen : for i in 0 to BITS - 1 generate
        signal D0             : std_logic      := '0';
        signal T1             : std_logic      := '0';
        signal D2             : std_logic      := '0';

        signal Changed_Clk1   : std_logic;
        signal Changed_Clk2   : std_logic;
        signal Busy_i         : std_logic;

        -- Prevent XST from translating two FFs into SRL plus FF
        attribute SHREG_EXTRACT of D0  : signal is "NO";
        attribute SHREG_EXTRACT of T1  : signal is "NO";
        attribute SHREG_EXTRACT of D2  : signal is "NO";

    begin
        process(Clock1)
        begin
            if rising_edge(Clock1) then
                -- input delay for rising edge detection
                D0    <= Input(i);

                -- T-FF to converts a strobe to a flag signal
                if GATED_INPUT_BY_BUSY then
                    T1  <= (Changed_Clk1 and not Busy_i) xor T1;
                else
                    T1  <= Changed_Clk1 xor T1;
                end if;
            end if;
        end process;

        -- D-FF for level change detection (both edges)
        D2  <= syncClk2_Out(i) when rising_edge(Clock2);

        -- assign syncClk*_In signals
        syncClk2_In(i)  <= T1;
        syncClk1_In(i)  <= syncClk2_Out(i);         -- D2

        Changed_Clk1    <= not D0 and Input(i);     -- rising edge detection
        Changed_Clk2    <= syncClk2_Out(i) xor D2;  -- level change detection; restore strobe signal from flag
        Busy_i          <= T1 xor syncClk1_Out(i);  -- calculate busy signal

        -- output signals
        Output(i)        <= Changed_Clk2;
        Busy(i)          <= Busy_i;
    end generate;

    syncClk2 : entity PoC.sync_Bits
        generic map (
            BITS        => BITS,          -- number of bit to be synchronized
            SYNC_DEPTH  => SYNC_DEPTH
        )
        port map (
            Clock       => Clock2,        -- <Clock>  output clock domain
            Input       => syncClk2_In,   -- @async:  input bits
            Output      => syncClk2_Out   -- @Clock:  output bits
        );

    syncClk1 : entity PoC.sync_Bits
        generic map (
            BITS        => BITS,          -- number of bit to be synchronized
            SYNC_DEPTH  => SYNC_DEPTH
        )
        port map (
            Clock       => Clock1,        -- <Clock>  output clock domain
            Input       => syncClk1_In,   -- @async:  input bits
            Output      => syncClk1_Out   -- @Clock:  output bits
        );
end architecture;

Исходный код можно найти здесь: PoC.misc.sync.Strobe

...