2017-03-15 172 views
1

我有一個項目,需要將數據從Windows 10計算機發送到BASYS 3板(ARTIX7 FPGA)。我使用UART來做到這一點。要發送的數據輸入到PuTTY串行控制檯。計算機和BASYS之間的UART通信3 FPGA

出於測試目的,我決定使用板上的8個LED顯示接收到的數據。

我正在使用Vivado 2016.4。

我遇到的問題是我在LED上獲得的數據與應該是完全不同的。我想這是PuTTY的波特率和我的VHDL模塊之間的同步問題。

請找到下文.vhd文件和該項目的文件.xdc:

將.vhd是基於有限狀態機(FSM)上,並有兩個信號允許同步:

tick_UART:每隔10417個時鐘週期打勾一次。由於時鐘週期爲10納秒,tick_UART每秒上升9600次(我打算在9600波特使用)。

double_tick_UART:tick_UART頻率的兩倍,用於採樣中間位。

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use IEEE.NUMERIC_STD.ALL; 


entity UART_RX is 
    Port (RxD : in STD_LOGIC; 
      clk : in STD_LOGIC; 
       RAZ : in STD_LOGIC; 
      data_out : out STD_LOGIC_VECTOR (7 downto 0)); 
end UART_RX; 

architecture Behavioral of UART_RX is 

    signal tick_UART : STD_LOGIC;              -- Signal "top" passage d'un état à l'autre selon vitesse connexion série 
    signal double_tick_UART : STD_LOGIC;            -- Signal précédent, fréquence * 2 
    signal compteur_tick_UART : integer range 0 to 10420;       -- Compteur pour tick_UART 
    signal double_compteur_tick_UART : integer range 0 to 5210;     -- Compteur pour demi-périodes 
    type state_type is (idle, start, demiStart, b0, b1, b2, b3, b4, b5, b6, b7, stop); -- Etats de la FSM 
    signal state :state_type := idle;             -- Etat par défaut 
    signal RAZ_tick_UART : STD_LOGIC;             -- RAZ du signal tick_UART; 

begin 

process(clk, RAZ, state, RAZ_tick_UART) -- Compteur classique (tick_UART) 
begin 
    if (raz='1') or (state = idle) or (RAZ_tick_UART = '1') then 
     compteur_tick_UART <= 0; 
     tick_UART <= '0'; 
    elsif clk = '1' and clk'event then 
      if compteur_tick_UART = 10417 then 
       tick_UART <= '1'; 
       compteur_tick_UART <= 0; 
      else 
       compteur_tick_UART <= compteur_tick_UART + 1; 
       tick_UART <= '0'; 
      end if; 
    end if; 
end process; 

process(clk, RAZ, state) -- Compteur demi-périodes (double_tick_UART car fréquence double) 
begin 
    if (raz='1') or (state = idle) then 
     double_compteur_tick_UART <= 0; 
     double_tick_UART <= '0'; 
    elsif clk = '1' and clk'event then 
      if double_compteur_tick_UART = 5209 then 
       double_tick_UART <= '1'; 
       double_compteur_tick_UART <= 0; 
      else 
       double_compteur_tick_UART <= double_compteur_tick_UART + 1; 
       double_tick_UART <= '0'; 
      end if; 
    end if; 
end process; 

fsm:process(clk, RAZ) -- Machine à état 
begin 
    if (RAZ = '1') then 
     state <= idle; 
     data_out <= "00000000"; 
     RAZ_tick_UART <= '1'; 
    elsif clk = '1' and clk'event then 
     case state is 
      when idle => if RxD = '0' then -- Si front descendant de RxD et en idle 
           state <= start; 
          RAZ_tick_UART <= '1'; 
          end if; 
      when start => if double_tick_UART = '1' then 
            state <= demiStart; 
            RAZ_tick_UART <= '0'; 
           end if; 
          data_out <= "00000000"; 
      when demiStart => if tick_UART = '1' then 
             state <= b0; 
             RAZ_tick_UART <= '0'; 
            end if; 
          data_out(0) <= RxD; -- Acquisition bit 0 
      when b0 => if tick_UART = '1' then 
           state <= b1; 
          end if; 
          data_out(1) <= RxD; -- Acquisition bit 1 
      when b1 => if tick_UART = '1' then 
           state <= b2; 
          end if; 
          data_out(2) <= RxD; -- Acquisition bit 2 
      when b2 => if tick_UART = '1' then 
           state <= b3; 
          end if; 
          data_out(3) <= RxD; -- Acquisition bit 3 
      when b3 => if tick_UART = '1' then 
           state <= b4; 
          end if; 
          data_out(4) <= RxD; -- Acquisition bit 4 
      when b4 => if tick_UART = '1' then 
           state <= b5; 
          end if; 
          data_out(5) <= RxD; -- Acquisition bit 5 
      when b5 => if tick_UART = '1' then 
           state <= b6; 
          end if; 
          data_out(6) <= RxD; -- Acquisition bit 6 
      when b6 => if tick_UART = '1' then 
           state <= b7;  
          end if; 
          data_out(7) <= RxD; -- Acquisition bit 7 
      when b7 => if tick_UART = '1' then 
           state <= stop; 
          end if; 
      when stop => if tick_UART = '1' then 
           state <= idle;  -- Renvoi en idle 
          end if; 
     end case; 
    end if; 
end process; 


end Behavioral; 

XDC文件:

## Clock signal 
set_property PACKAGE_PIN W5 [get_ports clk]       
    set_property IOSTANDARD LVCMOS33 [get_ports clk] 
    create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk] 

## LEDs 
set_property PACKAGE_PIN U16 [get_ports data_out[0]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[0]] 
set_property PACKAGE_PIN E19 [get_ports data_out[1]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[1]] 
set_property PACKAGE_PIN U19 [get_ports data_out[2]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[2]] 
set_property PACKAGE_PIN V19 [get_ports data_out[3]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[3]] 
set_property PACKAGE_PIN W18 [get_ports data_out[4]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[4]] 
set_property PACKAGE_PIN U15 [get_ports data_out[5]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[5]] 
set_property PACKAGE_PIN U14 [get_ports data_out[6]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[6]] 
set_property PACKAGE_PIN V14 [get_ports data_out[7]]      
    set_property IOSTANDARD LVCMOS33 [get_ports data_out[7]] 

##Buttons 
set_property PACKAGE_PIN T18 [get_ports RAZ]       
    set_property IOSTANDARD LVCMOS33 [get_ports RAZ] 

##USB-RS232 Interface 
set_property PACKAGE_PIN B18 [get_ports RxD]       
    set_property IOSTANDARD LVCMOS33 [get_ports RxD] 

你發現任何錯誤?

我也嘗試使用另一個.vhd(不是我自己寫的,應該工作)。 這並沒有工作,要麼:https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html (我很好修飾按照通用g_CLKS_PER_BIT我的時鐘&波特率)

的問題可能來自膩子,但我給自己定9600波特,8個數據的波特率位,1個停止位,沒有奇偶校驗,所以我沒有看到有什麼可能是錯的!

如果您有進一步的想法/評論,因爲我找不到有什麼問題!

非常感謝!


EDIT 2017年3月16日:

繼@ J.H.Bonarius & @ user1155120 recommandations,我添加了一個2級觸發器同步器,用於從RxD輸入信號與我的100 MHz的時鐘域同步。

我還修改了一些異步重置。 不過,我仍然有同樣的問題(LED不對應通過PuTTY發送的內容)。

查找hearafter新的.vhd代碼:

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use IEEE.NUMERIC_STD.ALL; 


entity UART_RX is 
    Port (RxD_in : in STD_LOGIC; 
      clk : in STD_LOGIC; 
      RAZ : in STD_LOGIC; 
      data_out : out STD_LOGIC_VECTOR (7 downto 0)); 
end UART_RX; 

architecture Behavioral of UART_RX is 

    signal tick_UART : STD_LOGIC;              -- Signal "top" passage d'un état à l'autre selon vitesse connexion série 
    signal double_tick_UART : STD_LOGIC;             -- Signal précédent, fréquence * 2 
    signal compteur_tick_UART : integer range 0 to 10420;        -- Compteur pour tick_UART 
    signal double_compteur_tick_UART : integer range 0 to 5210;       -- Compteur pour demi-périodes 
    type state_type is (idle, start, demiStart, b0, b1, b2, b3, b4, b5, b6, b7);   -- Etats de la FSM 
    signal state :state_type := idle;             -- Etat par défaut 
    signal RAZ_tick_UART : STD_LOGIC;             -- RAZ du signal tick_UART; 
    signal RxD_temp : STD_LOGIC;               -- RxD provisoire entre deux FF 
    signal RxD_sync : STD_LOGIC;               -- RxD synchronisé sur l'horloge 

begin 

D_flip_flop_1:process(clk) -- Clock crossing 
begin 
    if clk = '1' and clk'event then 
     RxD_temp <= RxD_in; 
    end if; 
end process; 

D_flip_flop_2:process(clk) -- Clock crossing 
begin 
    if clk = '1' and clk'event then 
     RxD_sync <= RxD_temp; 
    end if; 
end process; 

tickUART:process(clk, RAZ, state, RAZ_tick_UART) -- Compteur classique (tick_UART) 
begin 
    if clk = '1' and clk'event then 
     if (RAZ='1') or (state = idle) or (RAZ_tick_UART = '1') then 
      compteur_tick_UART <= 0; 
      tick_UART <= '0'; 
     elsif compteur_tick_UART = 10417 then 
      tick_UART <= '1'; 
      compteur_tick_UART <= 0; 
     else 
      compteur_tick_UART <= compteur_tick_UART + 1; 
      tick_UART <= '0'; 
     end if; 
    end if; 
end process; 

doubleTickUART:process(clk, RAZ, state) -- Compteur demi-périodes (double_tick_UART car fréquence double) 
begin 
    if clk = '1' and clk'event then 
     if (RAZ='1') or (state = idle) then 
      double_compteur_tick_UART <= 0; 
      double_tick_UART <= '0'; 
     elsif double_compteur_tick_UART = 5209 then 
      double_tick_UART <= '1'; 
      double_compteur_tick_UART <= 0; 
     else 
      double_compteur_tick_UART <= double_compteur_tick_UART + 1; 
      double_tick_UART <= '0'; 
     end if; 
    end if; 
end process; 

fsm:process(clk, RAZ) -- Machine à état 
begin 
    if (RAZ = '1') then 
     state <= idle; 
     data_out <= "00000000"; 
     RAZ_tick_UART <= '1'; 
    elsif clk = '1' and clk'event then 
     case state is 
      when idle => if RxD_sync = '0' then   -- Si front descendant de RxD (= bit de start) et en idle 
          state <= start; 
          RAZ_tick_UART <= '1'; 
         end if; 
      when start =>if double_tick_UART = '1' then -- Demi période écoulée (pour échantillonage) 
          state <= demiStart; 
          RAZ_tick_UART <= '0';  -- Le compteur tick_UART commence à compter 
         end if; 
         data_out <= "00000000";   -- Reset des anciennes données   
      when demiStart => if tick_UART = '1' then 
           state <= b0; 
           RAZ_tick_UART <= '0'; 
          end if; 
          data_out(0) <= RxD_sync; -- Acquisition bit 0 
      when b0 => if tick_UART = '1' then 
          state <= b1; 
         end if; 
         data_out(1) <= RxD_sync; -- Acquisition bit 1 
      when b1 => if tick_UART = '1' then 
          state <= b2; 
         end if; 
         data_out(2) <= RxD_sync; -- Acquisition bit 2 
      when b2 => if tick_UART = '1' then 
          state <= b3; 
         end if; 
         data_out(3) <= RxD_sync; -- Acquisition bit 3 
      when b3 => if tick_UART = '1' then 
           state <= b4; 
          end if; 
          data_out(4) <= RxD_sync; -- Acquisition bit 4 
      when b4 => if tick_UART = '1' then 
          state <= b5; 
         end if; 
         data_out(5) <= RxD_sync; -- Acquisition bit 5 
      when b5 => if tick_UART = '1' then 
          state <= b6; 
         end if; 
         data_out(6) <= RxD_sync; -- Acquisition bit 6 
      when b6 => if tick_UART = '1' then 
          state <= b7;  
         end if; 
         data_out(7) <= RxD_sync; -- Acquisition bit 7 
      when b7 => if tick_UART = '1' then 
          state <= idle; -- state <= stop; 
         end if; 
     end case; 
    end if; 
end process; 
end Behavioral; 

你對我的問題的根源任何想法? 非常感謝!

+1

您的uart_rx模擬成功,每個時鐘添加一個通用的時鐘(以縮短模擬中的時鐘數)。 JHB建議將觸發器(兩個,基於100 MHz時鐘)與rxd一致是有效的。 – user1155120

+0

編輯問題時我們不會收到更新。但無論如何:也許你還應該寫一個測試臺,來模擬RS232輸入信號的行爲。然後你可以看到你的代碼是否錯誤,如果是的話:出了什麼問題。在綜合之前測試你的代碼總是一個好主意...... – JHBonarius

回答

1

第一個if (raz='1') or (state = idle) or (RAZ_tick_UART = '1')然後不要在異步復位輸入中放置太多東西。實際上:根本不要使用異步重置。他們將在時鐘路徑中引入邏輯。

第二件事:在您的UART RxD上放置一些時鐘域同步可能是個好主意。只是一個兩級同步器。否則when idle => if RxD = '0' then將受到故障的影響。

+0

非常感謝你們倆。 的確,我可以使用通用時鐘而不是兩個不同的時鐘。 我試圖刪除兩個時鐘的異步重置,但在觀察行爲方面沒有任何成功。 你會有關於兩個拖鞋的互聯網參考?用電路圖或任何東西?因爲我是VHDL的新手,並且我不太明白你的意思,並且那些翻轉觸發器的用法是什麼。 將不勝感激!非常感謝你 ! – aib765

+1

只是谷歌「時鐘域同步」或「兩階段同步器」 – JHBonarius

相關問題