【问题标题】:What is the best way to detect pulses between two clock domains? [closed]检测两个时钟域之间的脉冲的最佳方法是什么? [关闭]
【发布时间】:2019-04-13 20:57:15
【问题描述】:

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

谢谢,

【问题讨论】:

    标签: vhdl verilog


    【解决方案1】:

    您需要一个频闪同步器。

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

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

    电路如下所示:

    一次多个位的源代码:

    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

    【讨论】:

    • 感谢您的解释!我尝试根据我的理解创建自己的 VHDL 代码,然后我将与您的解决方案进行比较!干杯,
    • 此代码是开源的,并在 Apache License 2.0 下获得许可。
    【解决方案2】:

    您的问题的另一个解决方案是 Flancter,Doulos 对此进行了最佳解释:

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

    【讨论】:

      【解决方案3】:

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

      src_pulse -> src_clk level_convertor-> 2-Stage dest Synchronizer -> 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多