检测两个时钟域之间的脉冲的最佳方法是什么?

What is the best way to detect pulses between two clock domains?

我想将一个脉冲从一个时钟域clk1传输到另一个时钟域clk2,但我们不知道哪个比另一个快! 最好的方法是什么?

谢谢,

你需要一个频闪同步器。

频闪同步器将输入的上升沿转换为电平变化 (T-FF)。该电平变化通过 2-FF 同步器传输到第二个时钟域。然后通过 XOR 门恢复信息。 (注意:T-FF 是一个 D-FF,带有 XOR 以反转每个高输入的状态。)

另外,还可以计算出busy状态,通知发送时钟域整个电路的状态。此忙信号可用于锁定输入的上升沿检测。

电路是这样的:

一次多位的源代码:

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

您的问题的另一个解决方案是 Flancter,Doulos 对此做出了最好的解释:

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

嘿,我有一个与 xilinx 工具兼容的此代码的 verilog 版本,

src_pulse -> src_clk level_convertor-> 2 级目标同步器 -> dest_pulse 检测器

这是在 2 个相关未知时钟域之间传输脉冲时要遵循的序列步骤。

   module pulse_cdc(
        input         src_clk,
        input         src_pulse,
        input         dest_clk,
        output logic  dest_pulse
    );

    (* ASYNC_REG = "TRUE" *)logic [2:0] dest_sync;
                            logic       src_clk_level = '0;

    //------------------------------//
    //-- Pulse to level convertor --//
    //------------------------------//
        always_ff @(posedge src_clk)
            if(src_pulse) src_clk_level <= #10 ~src_clk_level;
            else          src_clk_level <= #10  src_clk_level;

    //----------------------------//
    //------- Synchronizer -------//
    //----------------------------//
        always_ff @(dest_clk)begin
            dest_sync[0] <= #10 src_clk_level;
            dest_sync[1] <= #10 dest_sync[0];
            dest_sync[2] <= #10 dest_sync[1];
        end

    //-------------------------//
    //--- Pulse Generator -----//
    //-------------------------//
        always_comb dest_pulse = dest_sync[1] ^ dest_sync[2];

    endmodule