2017-03-15 31 views
1

Windows 10コンピュータからBASYS 3ボード(ARTIX7 FPGA)にデータを送信する必要があるプロジェクトがあります。私はそうするためにUARTを使います。送信するデータはPuTTYシリアルコンソールに入力されます。コンピュータとBASYS 3 FPGA間のUART通信

テスト目的で、私はボード上の8個のLEDを使用して受信データを表示することに決めました。

私はVivado 2016.4を使用しています。

私が抱えている問題は、私がLEDで取得したデータが、はっきりとは違うということです。私はPuTTYのボーレートと私のVHDLモジュールの間の同期の問題だと思います。

.vhdファイルと、このプロジェクトの.xdcファイルを以後見つけてください:

の.vhdは、有限状態機械(FSM)に基づいて、同期が可能に二つの信号がありますされています

は、

tick_UART:10417クロック周期ごとに目盛りをつけます。クロック周期は10nsなので、tick_UARTは9600回/秒(私は9600ボーで使用する予定です)に上昇します。

double_tick_UART:tick_UARTの頻度の2倍で、中央のビットをサンプリングするために使用されます。

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を修正)

を問題は、PuTTYのから来ることができましたが、私は9600ボーのボーレート、8データを設定しましたビット、1ストップビット、パリティなし、私は何が間違っているかはわかりません!

何か問題が見つからないため、さらにアイデアやコメントがある場合は、

ありがとうございました!


EDIT 2017年3月16日:

user1155120 recommandations @ J.H.Bonarius & @の後、私は私の100 MHzのクロックドメインとRxDの入力信号を同期させるための2段階のフリップフロップシンクロナイザを追加しました。

また、一部の非同期リセットを変更しました。 しかし、私はまだ同じ問題があります(LEDはPuTTY経由で送信されたものに対応していません)。

新しいの.vhdコードhearafter検索:あなたは私の問題の起源についてどんな考えを

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は、(シミュレーションのクロック数を減らすために)1ビットあたりのクロック数を追加して正常にシミュレートします。 JHBがrxdに沿ってフリップフロップ(100MHzクロックに基づく2つ)を入れることの提案が有効です。 – user1155120

+0

質問を編集したときに更新が反映されません。しかし、とにかく:RS232入力信号の動作をシミュレートするために、テストベンチを作成する必要があります。次に、あなたのコードが間違っているかどうか、そしてそれが何か間違っているかどうかを見ることができます。合成前にコードをテストすることは常に良い考えです... – JHBonarius

答えて

1

最初にif (raz='1') or (state = idle) or (RAZ_tick_UART = '1')非同期リセット入力にはあまり多くのものを置かないでください。実際には、非同期リセットを一切使用しないでください。彼らはクロックパスにロジックを導入します。

2番目のこと:おそらく、クロックドメインの同期をUART RxDに設定することをお勧めします。 2段シンクロナイザ。 Else when idle => if RxD = '0' thenはグリッチの影響を受けます。

+0

ありがとうございます。 2つの異なるクロックではなく、一般的なクロックを使用できたことは事実です。 両方のクロックの非同期リセットを削除しようとしましたが、観測された動作に関しては成功しませんでした。 2つのフリップフロップについてのインターネット参照はありますか?スケマティックなどで?私はVHDLを初めて使っているので、あなたが何を意味しているのか、そしてそのフリップフロップを使うのはどういうものなのでしょうか? 大変ありがとうございます。どうもありがとうございました ! – aib765

+1

Googleの「クロックドメイン同期」または「2ステージ同期」 – JHBonarius

関連する問題