2016-11-08 31 views
0

所以我有用于RS232通信链路的这个接收器代码,我应该发送8位带1个起始位“0”和一个停止位“1”,无奇偶校验尽管有些人告诉我我的问题是测试平台而不是代码,但它在FPGA实现中永远不起作用,我发送的第一个信号始终是在那之后的任何信号都是正确的地方是错的。VHDL RS232接收器与Xilinx ISE无法正常工作

这里是低于

entity Rs232Rxd is 

     port(Reset, Clock16x, Rxd: in std_logic; 

     DataOut1: out std_logic_vector (7 downto 0)); 

     end Rs232Rxd; 

architecture Rs232Rxd_Arch of Rs232Rxd is 

attribute enum_encoding: string; 

-- state definitions 

type stateType is (stIdle, stData, stStop, stRxdCompleted); 

attribute enum_encoding of statetype: type is "00 01 11 10"; 

signal iReset : std_logic; 

signal iRxd1, iRxd2 : std_logic := '1'; 

signal presState: stateType; 

signal nextState: stateType; 

signal iClock1xEnable, iClock1x, iEnableDataOut: std_logic :='0' ; 

signal iClockDiv: std_logic_vector (3 downto 0) := (others=>'0') ; 

signal iDataOut1, iShiftRegister: std_logic_vector (7 downto 0):= (others=>'0'); 

signal iNoBitsReceived: std_logic_vector (3 downto 0):= (others=>'0') ; 

begin 

process (Clock16x) begin 

     if rising_edge(Clock16x) then 

      if Reset = '1' or iReset = '1' then 

       iRxd1 <= '1'; 

       iRxd2 <= '1'; 

       iClock1xEnable <= '0'; 

       iClockDiv <= (others=>'0'); 

      else 

       iRxd1 <= Rxd; 

       iRxd2 <= iRxd1; 

      end if; 

      if iRxd1 = '0' and iRxd2 = '1' then 

       iClock1xEnable <= '1'; 

      end if; 

      if iClock1xEnable = '1' then 

       iClockDiv <= iClockDiv + '1'; 

     end if; 

     end if; 

end process; 


iClock1x <= iClockDiv(3); 

process (iClock1xEnable, iClock1x) 

begin 

    if iClock1xEnable = '0' then 

      iNoBitsReceived <= (others=>'0'); 

      presState <= stIdle; 

    elsif rising_edge(iClock1x) then 

       iNoBitsReceived <= iNoBitsReceived + '1'; 

       presState <= nextState; 

       if iEnableDataOut = '1' then 

       iDataOut1 <= iShiftRegister; 

       --iShiftRegister <= (others=>'0'); 

        else 

         iShiftRegister <= Rxd & iShiftRegister(7 downto 1); 

      end if; 
     end if; 

end process; 

DataOut1 <= iDataOut1; 

process (presState, iClock1xEnable, iNoBitsReceived) 

begin 

-- signal defaults 

iReset <= '0'; 

iEnableDataOut <= '0'; 


case presState is 

    when stIdle => 

    if iClock1xEnable = '1' then 

    nextState <= stData; 

    else 
     nextState <= stIdle; 

    end if; 

    when stData => 

    if iNoBitsReceived = "1000" then 

    iEnableDataOut <= '1'; 

    nextState <= stStop; 

    else 

    iEnableDataOut <= '0'; 

    nextState <= stData; 

    end if; 
    when stStop => 

    nextState <= stRxdCompleted; 

    when stRxdCompleted => 

    iReset <= '1'; 

    nextState <= stIdle; 

    end case; 

end process; 

end Rs232Rxd_Arch; 

回答

0

代码你的问题并不存在一个Minimal Complete and Verifiable Example。如果不编写测试台,问题就不会重复,而且问题缺乏特异性(这里使用的'信号'和'错误'是不精确的)。

有一些意见。

一个停止位后跟一个连续字符的起始位,为状态stRxdCompleted留下了空间。此外iNoBitsReceived未设置为全0时iClock1xEnable变为无效,这意味着采样点不被起始位的连续字符的下降沿确定:

rs232rxd_orig_tb.png

这是一个大写的‘A’立即后跟一个小写字母'a',停止位紧接着第二个字符的起始位(这是合法的)。

在第一个字符中,您会看到起始位被计为字符位之一。当启用变为无效时,您将看到位计数器未被复位,这将导致采样点漂移(并且可能最终导致取决于时钟差异或传输失真的采样错误以及缺少同步采样点复位)。

您还会在第一个字符的最后一个数据位期间看到presState为stStop,但第二个字符是正确的。仔细观察一下,我们看到第一个字符的起始位在stData期间发生,而第二个字符不会发生。

当iClock1x停止时,状态数和状态转换有一个基本问题。

你不需要状态机,你有一个名为iNoBitsReceived的计数器,它可以存储所有的状态,如果你还检测到帧错误,应该在ishiftregister足够长的时间内容纳启动(也可能是停止)位。

与清零位计数器,空闲时绑到特定计数操作,而没有单独的状态机,沿:

rs232_tb.png

给我们的东西,用少了几分复杂的工作原理:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity Rs232Rxd is 
    port ( 
     Reset, 
     Clock16x, 
     Rxd:  in std_logic; 
     DataOut1: out std_logic_vector (7 downto 0) 
    ); 
end entity Rs232Rxd; 

architecture foo of Rs232Rxd is 
    signal rxd1:    std_logic; 
    signal rxd2:    std_logic; 
    signal baudctr:    unsigned (3 downto 0); 
    signal ctr16x:    unsigned (3 downto 0); 
    signal enab1xstart:   std_logic; 
    signal enable1x:   std_logic; 
    signal ninthbit:   std_logic; 
    signal sampleenab:   std_logic; 
    signal shiftregister:  std_logic_vector(7 downto 0); 

begin 
CLOCK_DOMAIN: 
    process (clock16x) 
    begin 
     if rising_edge(clock16x) then 
      rxd1 <= rxd; 
      rxd2 <= rxd1; 
     end if; 
    end process; 

    enab1xstart <= not rxd1 and rxd2 and not enable1x; 

ENABLE_1X: 
    process (clock16x, reset) 
    begin 
     if reset = '1' then 
      enable1x <= '0'; 
     elsif rising_edge(clock16x) then 
      if enab1xstart = '1' then 
       enable1x <= '1'; 
      elsif ninthbit = '1' then 
       enable1x <= '0'; 
      end if; 
     end if; 
    end process; 

SAMPLE_COUNTER: 
    process (clock16x, reset, ninthbit) 
    begin 
     if reset = '1' or ninthbit = '1' then 
      ctr16x <= (others => '0'); -- for simulation 
     elsif rising_edge(clock16x) then 
      if enab1xstart = '1' or enable1x = '1' then 
       ctr16x <= ctr16x + 1; 
      end if; 
     end if; 
    end process; 

    sampleenab <= not ctr16x(3) and ctr16x(2) and ctr16x(1) and ctr16x(0); 

BAUD_COUNTER: 
    process (clock16x, reset) 
    begin 
     if reset = '1' then 
      baudctr <= (others => '0'); 
     elsif rising_edge(clock16x) and sampleenab = '1' then 
      if baudctr = 8 then 
       baudctr <= (others => '0'); 
      else 
       baudctr <= baudctr + 1; 
      end if; 
     end if; 
    end process; 

NINTH_BIT: -- one clock16x period long, after baudctr changes 
    process (clock16x, reset) 
    begin 
     if reset = '1' then 
      ninthbit <= '0'; 
     elsif rising_edge(clock16x) then 
      ninthbit <= sampleenab and  baudctr(3) and not baudctr(2) and 
             not baudctr(1) and not baudctr(0); 
     end if; 
    end process; 

SHIFT_REG: 
    process (clock16x, reset) 
    begin 
     if reset = '1' then 
      shiftregister <= (others => '0'); -- for pretty waveforms 
     elsif rising_edge(clock16x) and sampleenab = '1' then 
      shiftregister <= rxd2 & shiftregister(7 downto 1); 
     end if; 
    end process; 

OUTREG: 
    process (clock16x, reset) 
    begin 
     if reset = '1' then 
      dataout1 <= (others => '0'); 
     elsif rising_edge(clock16x) and ninthbit = '1' then 
      dataout1 <= shiftregister; 
     end if; 
    end process; 

end architecture; 

VHDL基本标识符不区分大小写,名称不是特别有启发性。上述两个波形的格式表明名称的变化很方便。

如果将移位寄存器的长度延长1或2,则可以在停止位期间检测到帧错误。改变移位寄存器的长度将需要对移位寄存器输出进行限幅,以写入数据输出。

请注意,此体系结构是使用软件包numeric_std编写的,而不是Synopsys软件包std_logic_arith。您也没有提供实体声明之前的上下文条款。

该体系结构还产生使能和使用16x时钟,而不是产生1x时钟。

它是在找到原始架构中纠正问题的变化量之后编写的,似乎势不可挡。 (如有疑问,重新来过。)用于

这个测试平台:

library ieee; 
use ieee.std_logic_1164.all; 

entity rs232rxd_tb is 
end entity; 

architecture foo of rs232rxd_tb is 
    signal reset:  std_logic := '0'; 
    signal clock16x: std_logic := '0'; 
    signal rxd:   std_logic := '1'; 
    signal dataout1: std_logic_vector (7 downto 0); 
begin 
DUT: 
    entity work.rs232rxd 
     port map (
      reset => reset, 
      clock16x => clock16x, 
      rxd => rxd, 
      dataout1 => dataout1 
     ); 
CLOCK: 
    process 
    begin 
     wait for 3.255 us; -- 16X clock divided by 2, 9600 baud 104.16 us 
     clock16x <= not clock16x; 
     if now > 2.30 ms then 
      wait; 
     end if; 
    end process; 

    STIMULI: 
    process 
    begin 
     wait for 6.51 us; 
     reset <= '1'; 
     wait for 13.02 us; 
     reset <= '0'; 
     wait for 13.02 us; 
     wait for 40 us; 
     rxd <= '0'; 
     wait for 104.16 us; -- start bit 
     rxd <= '1'; 
     wait for 104.16 us; -- first data bit, bit 0 = '1' 
     rxd <= '0'; 
     wait for 104.16 us; -- second data bit, bit 1 = '0' 
     rxd <= '0'; 
     wait for 104.16 us; -- third data bit, bit 2 = '0'; 
     wait for 104.16 us; -- fourth data bit, bit 3 = '0'; 
     wait for 104.16 us; -- fifth data bit, bit 4 = '0'; 
     wait for 104.16 us; -- sixth data bit, bit 5 = '0'; 
     rxd <= '1'; 
     wait for 104.16 us; -- seventh data bit, bit 6 = '1'; 
     rxd <= '0'; 
     wait for 104.16 us; -- eigth data bit, bit 7 = '0'; 
     rxd <= '1'; 
     wait for 104.16 us; -- stop bit (= '1') 
     --wait for 104.16 us; -- idle 
     rxd <= '0'; 
     wait for 104.16 us; -- start bit 
     rxd <= '1'; 
     wait for 104.16 us; -- first data bit, bit 0 = '1' 
     rxd <= '0'; 
     wait for 104.16 us; -- second data bit, bit 1 = '0' 
     rxd <= '0'; 
     wait for 104.16 us; -- third data bit, bit 2 = '0'; 
     wait for 104.16 us; -- fourth data bit, bit 3 = '0'; 
     wait for 104.16 us; -- fifth data bit, bit 4 = '0'; 
     rxd <= '1'; 
     wait for 104.16 us; -- sixth data bit, bit 5 = '1'; 
     wait for 104.16 us; -- seventh data bit, bit 6 = '1'; 
     rxd <= '0'; 
     wait for 104.16 us; -- eigth data bit, bit 7 = '0'; 
     rxd <= '1'; 
     wait for 104.16 us; -- stop bit (= '1') 
     wait; 
    end process; 
end architecture; 

你可以看到,新的架构都具有相同的基本要素,虽然主频工艺元素在单独的进程中声明。

没有状态机进程。通过与移位寄存器(奇偶校验,两个停止位,7个数据位等)分开输入来实现全功能UART接收器,该架构可扩展。奇偶校验可以连续执行。