2016-05-04 44 views
1

我正在研究VHDL設計,我已經開始工作了,但代碼非常醜陋,而且我似乎試圖圍繞語言的設計來實現我的目標,這讓我感覺有點不對勁。我對VHDL相當陌生,但我一直在爲這個項目的小塊工作近一個月,所以我有了一個總體想法。但是,這部分有點複雜。使用rising_edge對非時鐘信號的不良做法是什麼?有替代品嗎?

我需要一個過程,它將在信號的上升沿(END_ADC)後創建一個時鐘週期的長脈衝(LOAD_PULSE),但直到從該信號的最後一個上升沿開始經過4個時鐘週期(END_ADC)或第二個信號(LVAL)的下降沿。

要完成的觀望期,我已經建立了統計微秒和週期,在此定時器模塊:

entity uS_generator is 
    generic(
     Frequency  : integer := 66          -- Frequency in MHz 
    ); 
    Port ( 
     CLK  : in STD_LOGIC; 
     RESET : in STD_LOGIC; 
     T_CNT : out integer range Frequency downto 1 := 1; 
     uS_CNT : out integer range 65535 downto 0 := 0 
    ); 
end uS_generator; 

architecture behavior of uS_generator is 

    signal T_CNT_INT  : integer range Frequency downto 1 := 1;  -- Counter for 1 uS 
    signal uS_CNT_INT  : integer range 65535 downto 0 := 0; 

begin 

    COUNT: process(CLK, RESET) 
    begin 
     if RESET = '1' then 
      T_CNT_INT <= 1; 
      uS_CNT_INT <= 0; 
     elsif rising_edge(CLK) then 
      if T_CNT_INT = (Frequency - 1) then        -- Increment one clock early so last rising edge sees one uS elapsed. 
       uS_CNT_INT <= uS_CNT_INT + 1; 
       T_CNT_INT <= T_CNT_INT + 1; 
       if uS_CNT_INT = 65535 then 
        uS_CNT_INT <= 0; 
       end if; 
      elsif T_CNT_INT = Frequency then 
       T_CNT_INT <= 1; 
      else 
       T_CNT_INT <= T_CNT_INT + 1; 
      end if; 
     end if; 
    end process COUNT; 

    T_CNT <= T_CNT_INT; 
    uS_CNT <= uS_CNT_INT; 

end behavior; 

我使用設計的脈衝生成部的流程如下:

loadPulseProc: process(PIXEL_CLK, END_ADC, RESET) 
begin 

    if RESET = '1' then 
     PULSE_FLAG <= '0'; 
     LOAD_PULSE <= '0'; 
    elsif rising_edge(END_ADC) then 
     PULSE_FLAG <= '1'; 
    end if; 

    if rising_edge(PIXEL_CLK) then 
     if PULSE_FLAG = '1' and END_ADC = '1' and LVAL <= '0' and ADC_TMR_T >= 4 and LVAL_TMR_T >= 4 then 
      LOAD_PULSE <= '1', '0' after PIXEL_CLK_T; 
      PULSE_FLAG <= '0'; 
     end if; 
    end if; 

end process loadPulseProc; 

ADCTimerProc: process(END_ADC, RESET) 
begin 

    if RESET = '1' then 
     ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if; 

    if rising_edge(END_ADC) then 
     ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if; 

    if falling_edge(END_ADC) then 
     ADC_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if; 

end process ADCTimerProc; 

LVALTimerProc: process(LVAL, RESET) 
begin 

    if RESET = '1' then 
     LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if; 

    if rising_edge(LVAL) then 
     LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if; 

    if falling_edge(LVAL) then 
     LVAL_TMR_RST <= '1', '0' after PIXEL_CLK_T/10; 
    end if;   

end process LVALTimerProc; 

PIXEL_CLK_T是時鐘的週期,15.152ns。

這個設計的工作原理是,仿真表明它按照我的要求工作,但是隻有在避免由於使用falling_edge調用的多個rising_edge而將錯誤分離爲單獨的if語句而導致錯誤發生後纔會發生錯誤。據我讀到的使用rising_edge和falling_edge似乎只保留給時鐘,那麼這只是不好的做法?如何避免這種行爲,但仍然創造相同的輸出?

謝謝!

+0

您的代碼不符合綜合條件,它不會以硬件描述語言描述硬件。在PIXEL_CLK_T/10之後施加的延遲不會被作用,也不會超過信號分配中的一個波形元素。不可能使用兩條邊來控制相同的信號(雙數據速率寄存器是FPGA中的特定I/O單元)。請參閱現在撤消的IEEE Std 1076.6-2004(RTL綜合)或您最喜愛的供應商的綜合文檔。 – user1155120

+0

如果您使用'rising_edge'(或等效的「事件和= 1」形式),您已創建了一個時鐘信號。有時候這是合適的,但通常這是不好的做法(並且您最好重新計時信號,並比較新舊值)。 –

回答

5

是的,rising_edge()/falling_edge()只能用於時鐘信號。雖然它在模擬中起作用,但它可能會導致合成中的問題和意外硬件。

綜合工具根據函數的參數推斷出一個時鐘,並將這些信號/電線放置在FPGA中的特殊軌道上(假設您針對您的設計採用FPGA)。該工具將進一步推斷特殊的時鐘緩衝器,並警告您的輸入時鐘引腳是否不支持時鐘引腳。

引入多個時鐘可能會導致異步設計並使其容易受到交叉時鐘故障的影響。

檢測信號的上升沿或下降沿由類似於以下的邊沿檢測電路完成,該電路將前一個時鐘週期中的信號與當前值進行比較。

所需的信號:

signal mySignal_d : std_logic := '0'; 
signal mySignal_re : std_logic; 

所需邏輯:

mySignal_d <= mySignal when rising_edge(Clock); 
mySignal_re <= not mySignal_d and mySignal; 

此第一線轉換爲一個1位的d觸發器(也可以使用的處理)。當mySignal由低變爲高時,第二行產生一個週期的選通信號。我使用*_d來指示原始輸入的延遲信號和*_re的上升沿。

生成的信號仍與Clock同步。

+0

我明白了,謝謝澄清。所以當試圖創建一些只用於模擬的東西,比如創建測試臺時,它是沒問題的?例如,一系列等待直到rising_edge()語句根據輸出的上升沿創建我想要的正確時間的輸入流? – Jemimacakes

+0

簡而言之:是:) – Paebbels

+0

對於類似的解決方案來檢測輸出邊緣有什麼建議嗎?我希望創建一段代碼來替換'PIXEL_CLK_T/10'實例之後的''。我還需要在所有輸出的上升沿和下降沿創建一個時鐘週期長的脈衝,但不能使用您的好解決方案,因爲我無法從'out'對象讀取數據。我應該爲此做一個單獨的問題嗎? – Jemimacakes

相關問題