2017-03-15 20 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의 빈도의 두 배입니다.

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 정지 비트, 패리티 없음, 그래서 내가 뭘 잘못 볼 수 없어!

이상한 것을 찾을 수 없기 때문에 더 많은 아이디어/의견이 있으시면!

대단히 감사합니다!


편집 2017년 3월 16일 :

는 @ J.H.Bonarius & @ recommandations user1155120 후, 나는 내 100 MHz 클럭 도메인으로 때 RxD 입력 신호를 동기화하는 2 단계 플립 플롭 동기를 추가했다.

또한 수정 된 일부 비동기식 재설정을 수정했습니다. 그럼에도 불구하고, 나는 여전히 동일한 문제를 가지고 있습니다 (LED는 PuTTY를 통해 전송 된 것과 일치하지 않습니다).

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; 

당신은 내 문제의 근원에 대해 어떤 생각을 가지고 있습니까 :

는 hearafter에게 새로운하여 .vhd 코드를 찾기? 대단히 감사합니다!

+1

uart_rx는 비트 당 클럭 수에 대한 추가 일반을 시뮬레이션합니다 (시뮬레이션에서 클럭 수를 줄이기 위해). JHB가 rxd에 맞춰 플립 플롭 (두 개는 100MHz 클럭을 기준으로 함)을 넣는 것이 좋습니다. – user1155120

+0

질문을 편집 할 때 업데이트가 제공되지 않습니다. 그러나 어쨌든 : 아마도 RS232 입력 신호 동작을 시뮬레이션하기 위해 테스트 벤치를 작성해야합니다. 그렇다면 코드가 잘못되었는지, 그리고 무엇이 잘못되었는지 확인할 수 있습니다. 합성 전에 코드를 테스트하는 것은 항상 좋은 생각입니다 ... – JHBonarius

답변

1

처음으로 if (raz='1') or (state = idle) or (RAZ_tick_UART = '1') 비동기식 리셋 입력에 많은 것을 넣지 마십시오. 실제로 : 비동기 리셋을 전혀 사용하지 마십시오. 그들은 클럭 경로에 로직을 도입 할 것입니다.

두 번째 사항 : UART RxD에 시계 도메인 동기화를 적용하는 것이 좋습니다. 2 단 싱크로 나이저. 기타 when idle => if RxD = '0' then은 고장의 영향을받습니다.

+0

대단히 감사합니다. 두 개의 서로 다른 시계 대신 일반 시계를 사용할 수 있다는 것은 사실입니다. 두 동작 모두에 대해 비동기식 재설정을 제거하려고했지만 관찰 된 동작은 성공하지 못했습니다. 두 개의 플립 플에 대한 인터넷 참조 정보가 있습니까? 설계도 같은 것이 있나요? VHDL을 처음 접했을 때 나는 당신이 무엇을 의미하는지 이해하지 못했고 그 플립 플롭을 어떻게 사용하는지 이해할 수 없었습니다. 대단히 감사하겠습니다. 고마워요! – aib765

+1

그냥 구글 "클럭 도메인 동기화"또는 "2 단계 동기화" – JHBonarius