2013-03-06 54 views
6

(我會發布這EE但似乎這裏還有更多VHDL問題...)VHDL:創建基於一個非常快的時鐘速度很慢時鐘脈衝

背景:我使用Xilinx Spartan-6LX9 FPGA和Xilinx ISE 14.4(webpack)。

今天我偶然發現了一個令人畏懼的「PhysDesignRules:372 - 門控時鐘」警告,並且我看到有很多關於這個問題的討論。一致認爲似乎是使用FPGA上的一個DCM來進行時鐘分割,但是......我的DCM看起來沒有能力從32 MHz到4.096 KHz(根據向下5 MHz的嚮導) 32MHz ......並且爲了這種低頻目的嘗試鏈接多個DCM似乎是荒謬的)。我現在的設計使用clk_in來計數到指定的值(15265),將該值重置爲零,並切換clk_out位(所以我最終的佔空比爲50%,FWIW)。它完成了這項工作,我可以輕鬆使用clk_out的上升沿來驅動設計的下一個階段。它似乎工作得很好,但... 門控時鐘(即使它不在時鐘偏移將恕我直言,非常相關的範圍內)。 (注:所有時鐘測試是使用在給定的時鐘敏感過程rising_edge()函數來完成)

所以,我的問題:

  • 如果我們談論得出一個相對緩慢的CLK_OUT從快得多 clk_in,門控仍然認爲不好? 或者這種「計數到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; 

因此,在這種情況下,這一切都是因爲缺乏的其他的(就像我說的,50%的佔空比最初很有趣,但最終並不需要,當時的「本地」時鐘的切換看起來相當聰明......)我大部分在右邊跟蹤它出現。

什麼在這一點上並不清楚,我就是用計數器(存儲大量的位)不會導致警告,但受存儲和切換輸出位確實原因警告。想法?

回答

7

如果您只需要一個時鐘來驅動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內部使用更多的時鐘線,所以如果你有很多門控時鐘,你可能會很快耗盡所有可用的線路。

時鐘使能沒有這些缺點。一切運行在相同的時鐘域(儘管速度不同),所以你可以很容易地使用相同的信號,而無需任何同步器或類似的。

+0

耐人尋味......這幾乎是我在做什麼已經,雖然我是用邏輯來切換本地STD_LOGIC位,當它達到規定值(沒有「其他「條款),然後將其分配給輸出(無論如何,不​​再需要50%佔空比的東西)。將其切換出來,然後添加一個else子句(相當於上面的「clk_enable_200kHz <='0';」)擺脫了警告!所以我有正確的想法,除了我試圖以這種方式獲得50%的任務週期...因此我想知道,是否真的有效地創造了一個觸發器,事實是這一切的原因? – MartyMacGyver 2013-03-06 11:06:31

+0

這聽起來很奇怪。您是否在這兩種情況下都以相同的方式使用了門控時鐘信號?警告應取決於邏輯信號被用作時鐘,而不取決於如何生成該邏輯信號。 – sonicwave 2013-03-06 12:15:11

+0

我已經用「之前和之後」代碼更新了我的問題(我測試了兩個表單,只有「之前」之一觸發了這個錯誤......雖然顯然它有一個額外的存儲位,你會看到)。在這一點上,這是一個有點學術的人,但是理解爲什麼我在第一個地方做的是「錯誤的」(我能想到的是這與無其他「別的」或額外的位有關切換或兩者的結合,所有其他事情在整個過程中都是相同的。) – MartyMacGyver 2013-03-06 12:18:53

0

您的樣品都會產生一個信號,其中一個信號以慢速切換,其中一個信號以「慢速」脈衝脈衝窄脈衝。如果這兩個信號都進入其他觸發器的時鐘輸入端,我希望警告有關時鐘佈線不是最優的。

我不知道爲什麼你得到一個門控時鐘的警告,這通常是當你做一下:

gated_clock <= clock when en = '1' else '0'; 
+0

我在想LOCAL_CLK_SLOW *是這裏的門控時鐘......雖然爲什麼計數器變量*沒有這種效果,我仍然不清楚。 – MartyMacGyver 2013-03-08 04:08:38

+0

但LOCAL_CLOCK_SLOW只是一個寫入同步的信號,就像所有其他正常的同步代碼一樣......一些非常奇怪的事情正在發生! – 2013-03-08 11:56:02

2

請注意這個示例工作這一行,

信號clk_enable_counter:std_logic_vector( 9 downto 0);

必須改變,以

信號clk_enable_counter:無符號(9 DOWNTO 0);

並且您需要包含此庫,

庫ieee; 使用ieee.numeric_std.all;

-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; 
+1

您挖掘了一個已有公認答案的四年前的問題,並通過發佈大量不正確縮進的代碼來回答問題。它甚至不是一個完整的最小可驗證的例子。請不要這樣做 – JHBonarius 2017-07-05 09:25:52

+0

@JHBonarius:那麼,該'接受的答案'中的代碼不工作對我和我的「散裝代碼」僅僅是~40 LOC長無論如何。 – 2017-07-06 10:24:14

+0

對不起,但你的代碼沒有解釋或評論。例如,看一下proc1_running_at_clk_1的過程:它是空的......爲什麼'clk_in1_freq'和'clk_1_freq'信號看起來應該是常量....並且甚至沒有64位'無符號'的信號,但只是整數。進一步考慮你的代碼,它只是沒有任何意義。 – JHBonarius 2017-07-06 10:59:16