7

(我会在 EE 中发布此内容,但似乎这里有更多 VHDL 问题......)

背景:我将 Xilinx Spartan-6LX9 FPGA 与 Xilinx ISE 14.4 (webpack) 一起使用。

今天我偶然发现了可怕的“PhysDesignRules:372 - 门控时钟”警告,我看到有很多关于这个的讨论。共识似乎是使用 FPGA 上的 DCM 之一进行时钟分频,但是......我的 DCM 似乎无法从 32 MHz 变为 4.096 KHz(根据向导,它在 5MHz 时触底32MHz ......而且为了这个低频目的而尝试链接多个 DCM 似乎很荒谬)。

我当前的设计使用 clk_in 计数到指定值 (15265),将该值重置为零并切换 clk_out 位(因此我最终得到 50% 的占空比,FWIW)。它完成了这项工作,我可以轻松地使用 clk_out 的上升沿来驱动我设计的下一阶段。它似乎工作得很好,但是......门控时钟(即使它不在恕我直言时钟偏差非常相关的范围内)。(注意:所有时钟测试都是在对给定时钟敏感的进程中使用rising_edge() 函数完成的。)

所以,我的问题:

  • 如果我们谈论从更快的 clk_in 派生相对较慢的clk_out,门控仍然被认为是坏的吗?或者这种“计数到 x 并发送脉冲”对于 FPGA来说是非常典型的,以在 KHz 范围内生成“时钟”,而其他一些不必要的副作用可能会触发这个警告?

  • 有没有更好的方法可以从 MHz 范围的主时钟创建一个低 KHz 范围的时钟,请记住,在这里使用多个 DCM 似乎是过大的(如果考虑到非常低的输出频率可能的话)?我意识到 50% 的占空比可能是多余的,但假设一个时钟输入而不使用板载 DCM,否则如何使用 FPGA 执行主要时钟分频?

编辑:鉴于以下情况(其中 CLK_MASTER 是 32 MHz 输入时钟,CLK_SLOW 是所需的慢速时钟,而 LOCAL_CLK_SLOW 是存储整个占空比事物的时钟状态的一种方式),我了解到这种配置导致警告:

architecture arch of clock is
    constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
    constant CLK_SLOW_FREQ: natural := 2048;
    constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
    shared variable counter: natural := 0;
    signal LOCAL_CLK_SLOW: STD_LOGIC := '0';
begin
    clock_proc: process(CLK_MASTER)
    begin
        if rising_edge(CLK_MASTER) then
            counter := counter + 1;
            if (counter >= MAX_COUNT) then
                counter := 0;
                LOCAL_CLK_SLOW <= not LOCAL_CLK_SLOW;
                CLK_SLOW <= LOCAL_CLK_SLOW;
            end if;
        end if;
    end process;
end arch;

而此配置不会导致警告:

architecture arch of clock is
    constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns
    constant CLK_SLOW_FREQ: natural := 2048;
    constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ;
    shared variable counter: natural := 0;
begin
    clock_proc: process(CLK_MASTER)
    begin
        if rising_edge(CLK_MASTER) then
            counter := counter + 1;
            if (counter >= MAX_COUNT) then
                counter := 0;
                CLK_SLOW <= '1';
            else
                CLK_SLOW <= '0';
            end if;
        end if;
    end process;
end arch;

因此,在这种情况下,这完全是因为缺少 else (就像我说的,50% 占空比最初很有趣,但最终不是必需的,并且“本地”时钟位的切换似乎很聪明时间......)我大部分时间都在正确的轨道上。

在这一点上我不清楚的是为什么使用计数器(存储大量位)不会导致警告,但存储和切换输出位导致警告。想法?

4

4 回答 4

11

如果您只需要一个时钟来驱动 FPGA 中逻辑的另一部分,那么简单的答案就是使用时钟使能。

也就是说,在与其他所有东西相同的(快速)时钟上运行您的慢速逻辑,但使用慢速启用它。例子:

signal clk_enable_200kHz  : std_logic;
signal clk_enable_counter : std_logic_vector(9 downto 0);

--Create the clock enable:
process(clk_200MHz)
begin
  if(rising_edge(clk_200MHz)) then
    clk_enable_counter <= clk_enable_counter + 1;
    if(clk_enable_counter = 0) then
      clk_enable_200kHz <= '1';
    else
      clk_enable_200kHz <= '0';
    end if;
  end if;
end process;


--Slow process:
process(clk_200MHz)
begin
  if(rising_edge(clk_200MHz)) then
    if(reset = '1') then
      --Do reset
    elsif(clk_enable_200kHz = '1') then
      --Do stuff
    end if;
  end if;
end process;

虽然 200kHz 是近似值,但以上基本上可以扩展到您需要的任何时钟使能频率。此外,大多数 FPGA 中的 FPGA 硬件应该直接支持它(至少在 Xilinx 部件中)。

门控时钟几乎总是一个坏主意,因为人们经常忘记他们正在创建新的时钟域,因此在它们之间连接信号时没有采取必要的预防措施。它还在 FPGA 内部使用了更多的时钟线,因此如果您有很多门控时钟,您可能会很快用完所有可用的线。

时钟使能没有这些缺点。一切都在相同的时钟域中运行(尽管速度不同),因此您可以轻松使用相同的信号,而无需任何同步器或类似设备。

于 2013-03-06T10:50:55.623 回答
3

注意这个例子在这条线上工作,

信号 clk_enable_counter : std_logic_vector(9 down to 0);

必须改为

信号 clk_enable_counter : unsigned(9 down to 0);

你需要包含这个库,

图书馆 ieee;使用 ieee.numeric_std.all;

于 2014-08-20T17:49:32.170 回答
0

您的两个样本都会产生一个信号,其中一个以慢速切换,其中一个以“慢速”脉冲窄脉冲。如果这两个信号都进入其他触发器的时钟输入,我预计会收到有关时钟路由非最佳的警告。

我不确定您为什么会收到门控时钟警告,这通常发生在您这样做时:

gated_clock <= clock when en = '1' else '0';
于 2013-03-07T09:57:19.983 回答
-2

这是一个完整的示例代码:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY Test123 IS

    GENERIC (
        clk_1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32); -- Presented in Hz
        clk_in1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32) -- Presented in Hz, Also
    );

    PORT (
        clk_in1 : IN std_logic := '0';
        rst1 : IN std_logic := '0';
        en1 : IN std_logic := '0';
        clk_1 : OUT std_logic := '0'
    );

END ENTITY Test123;

ARCHITECTURE Test123_Arch OF Test123 IS
    --
    SIGNAL clk_en_en : std_logic := '0';
    SIGNAL clk_en_cntr1 : unsigned(31 DOWNTO 0) := (OTHERS => '0');
    --
    SIGNAL clk_1_buffer : std_logic := '0';
    SIGNAL clk_1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz, Also
    SIGNAL clk_in1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz
    --
    SIGNAL clk_prescaler1 : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Cycles (Relative To The Input Clk.)
    SIGNAL clk_prescaler1_halved : unsigned(31 DOWNTO 0) := (OTHERS => '0');
    --

BEGIN
    clk_en_gen : PROCESS (clk_in1)
    BEGIN
        IF (clk_en_en = '1') THEN

            IF (rising_edge(clk_in1)) THEN
                clk_en_cntr1 <= clk_en_cntr1 + 1;

                IF ((clk_en_cntr1 + 1) = clk_prescaler1_halved) THEN   -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Comparison Is Done This Way !

                    clk_1_buffer <= NOT clk_1_buffer;
                    clk_1 <= clk_1_buffer;
                    clk_en_cntr1 <= (OTHERS => '0');

                END IF;

            END IF;

        ELSIF (clk_en_en = '0') THEN

            clk_1_buffer <= '0';
            clk_1 <= clk_1_buffer;
            clk_en_cntr1 <= (OTHERS => '0'); -- Clear Counter 'clk_en_cntr1'

        END IF;

    END PROCESS;

    update_clk_prescalers : PROCESS (clk_in1_freq, clk_1_freq)
    BEGIN
        clk_prescaler1 <= (OTHERS => '0');
        clk_prescaler1_halved <= (OTHERS => '0');
        clk_en_en <= '0';

        IF ((clk_in1_freq > 0) AND (clk_1_freq > 0)) THEN

            clk_prescaler1 <= (clk_in1_freq / clk_1_freq); -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Assignment Is Done This Way !
            clk_prescaler1_halved <= ((clk_in1_freq / clk_1_freq) / 2); -- (Same Thing Here)

            IF (((clk_in1_freq / clk_1_freq) / 2) > 0) THEN -- (Same Thing Here, Too)
                clk_en_en <= '1';
            END IF;

        ELSE
            NULL;
        END IF;

    END PROCESS;

    clk_1_freq <= clk_1_freq_generic;
    clk_in1_freq <= clk_in1_freq_generic;

END ARCHITECTURE Test123_Arch;
于 2017-07-04T00:21:33.857 回答