【问题标题】:VHDL RS232 Receiver not working correctly with Xilinx ISEVHDL RS232 接收器无法与 Xilinx ISE 一起正常工作
【发布时间】:2016-11-08 18:27:40
【问题描述】:

所以我有这个 RS232 通信链路的接收器代码,我应该发送 8 位,1 个起始位“0”和一个停止位“1”,没有奇偶校验位,我已经尝试使用这些代码大多数方法,但模拟从未正确工作,即使有人告诉我我的问题是测试台不是代码,但它在 FPGA 实现上从来没有工作,我发送的第一个信号总是错误的,因为之后的任何信号都是正确的.

下面是代码

    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;

【问题讨论】:

    标签: serial-port vhdl


    【解决方案1】:

    您的问题没有提供Minimal Complete and Verifiable Example。如果不编写测试平台就无法复制问题,而且您的问题缺乏特异性(此处使用的“信号”和“错误”不准确)。

    有一些观察。

    一个停止位后跟一个连续字符的起始位,没有为状态 stRxdCompleted 留下空间。当 iClock1xEnable 变为无效时,iNoBitsReceived 也不会设置为全 0,这意味着采样点不是由连续字符的起始位的下降沿决定的:

    这是一个大写的“A”紧跟一个小写的“a”,停止位紧跟第二个字符的开始位(这是合法的)。

    在第一个字符中,您会看到起始位被计为一个字符位。

    您还看到,当使能无效时,位计数器未重置,这将导致采样点漂移(并最终可能导致采样错误,具体取决于时钟差异或传输失真以及缺少同步采样点重置)。

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

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

    您不需要状态机,您有一个名为 iNoBitsReceived 的计数器,它可以存储所有状态,如果 ishiftregister 足够长以容纳开始(可能还有停止)位,如果您还检测到帧错误。

    在没有单独的状态机的情况下将操作绑定到特定的计数,以及在空闲时清除位计数器:

    为我们提供了一些不太复杂的东西:

    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 基本标识符不区分大小写,而且名称也不是特别有启发性。以上两个波形的格式表示名称的变化很方便。

    如果将移位寄存器长度增加一到两个,您可以在停止位期间检测到帧错误。更改移位寄存器长度需要对移位寄存器输出进行切片以写入数据输出。

    请注意,此架构是为使用包 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;
    

    您可以看到新架构具有所有相同的基本元素,尽管时钟进程元素位于单独的进程语句中。

    没有状态机进程。

    该架构可扩展为全功能 UART 接收器,方法是使用移位寄存器的分离输入(用于奇偶校验、两个停止位、7 个数据位等)。奇偶校验可以串行执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多