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

时间:2019-04-13 20:57:16

标签: vhdl verilog

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

谢谢

3 个答案:

答案 0 :(得分:0)

您需要一个选通同步器。

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

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

电路如下:
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

答案 1 :(得分:0)

另一种解决方法是Flancter,由Doulos最好地解释:

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

答案 2 :(得分:0)

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

src_pulse-> src_clk level_convertor-> 2级dest同步器-> 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