首页 > 解决方案 > 在 VHDL 中使用 UART

问题描述

我正在尝试将 UART 通信与 Lattice machox3 和 ft232R 一起使用。我正在尝试使用在 eewiki(此处)上找到的 VHDL 文件。出于某种原因,当我模拟它时,我无法让 tx 工作。我究竟做错了什么?我可以使用一个简单的 uart 实现吗?我试着自己做,我只是想传播,但我没有不成功。

这是Active hdl给我的波形

在此处输入图像描述

这是我用来让这个组件工作的顶级文件。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--library machXO3;
--use machXO3.all;

entity UART_TOP is  generic (
        divisor    : integer := 2604    -- Set the Baud Rate Divisor here.  
                                        -- Some common values:  300 Baud = 83333, 9600 Baud = 2604, 115200 Baud = 217, 921600 Baud = 27
            );
    PORT(

            reset_n :   IN      STD_LOGIC;                                      --ascynchronous reset
            tx_ena  :   IN      STD_LOGIC;                                      --initiate transmission load on H
            tx_busy :   OUT STD_LOGIC;                                          --transmission in progress
            tx          :   OUT STD_LOGIC;


        CLOCK_UART : in STD_LOGIC;
        DIN   : IN STD_LOGIC_VECTOR(15 downto 0)
    );
end UART_TOP;

architecture Behavior of UART_TOP is
    SIGNAL INTERNAL_CLOCK : STD_LOGIC; 
    SIGNAL MUX_0 : STD_LOGIC_VECTOR(7 downto 0);
    SIGNAL MUX_1 : STD_LOGIC_VECTOR(7 downto 0);
    SIGNAL MUX_S : STD_LOGIC_VECTOR(1 downto 0);
    SIGNAL txEN: STD_LOGIC_VECTOR(0 downto 0);
    SIGNAL counter : STD_LOGIC;
    SIGNAL DATAsnd : STD_LOGIC_VECTOR(7 downto 0);
    SIGNAL LOAD : STD_LOGIC;

    ---------------------------------------------------
    --  Buffer Input                                 --
    ---------------------------------------------------
    COMPONENT NOTM is
        PORT(
            Input   : in  STD_LOGIC;
            Output : out  STD_LOGIC
            );   
    END COMPONENT;

    ---------------------------------------------------
    --  Buffer Input                                 --
    ---------------------------------------------------
    COMPONENT InputBuffer is
        generic(n: natural);
        PORT(
            clk    : in STD_LOGIC;
            En     : in STD_LOGIC;  -- 0 is enabled
            Input   : in  STD_LOGIC_VECTOR (n-1 downto 0);
            Output : out  STD_LOGIC_VECTOR (n-1 downto 0)
            );   
    END COMPONENT;

    ---------------------------------------------------
    --  MUX04_2_1                                    --
    ---------------------------------------------------
    COMPONENT MUX421 is
        generic (
            DATAWIDTH : natural := 8
        );
        port(
            A : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
            B : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
            C : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
            D : in STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0);
            S : in STD_LOGIC_VECTOR(1 downto 0);
            O : OUT STD_LOGIC_VECTOR(DATAWIDTH-1 downto 0)
        );
    END COMPONENT;

    ---------------------------------------------------
    --  Binary Counter                               --
    ---------------------------------------------------
    COMPONENT binary_counter is
        generic(
            MIN_COUNT : natural := 0;
            MAX_COUNT : natural := 17
        );
        port(
            clk       : in std_logic;
            reset     : in std_logic;
            enable    : in std_logic;   -- 0 is enabled
            q         : out STD_LOGIC_VECTOR(MAX_COUNT-1 downto 0)
        );
    END COMPONENT;

    ---------------------------------------------------
    --  UART. Mach0X3                                --
    ---------------------------------------------------
    COMPONENT uart_c IS
        GENERIC(
            clk_freq        :   INTEGER     := 50_000_000;  --frequency of system clock in Hertz
            baud_rate   :   INTEGER     := 19_200;      --data link baud rate in bits/second
            os_rate     :   INTEGER     := 16;          --oversampling rate to find center of receive bits (in samples per baud period)
            d_width     :   INTEGER     := 8;           --data bus width
            parity      :   INTEGER     := 1;               --0 for no parity, 1 for parity
            parity_eo   :   STD_LOGIC   := '0');            --'0' for even, '1' for odd parity
        PORT(
            clk     :   IN      STD_LOGIC;                                      --system clock
            reset_n :   IN      STD_LOGIC;                                      --ascynchronous reset
            tx_ena  :   IN      STD_LOGIC;                                      --initiate transmission load on H
            tx_data :   IN      STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);           --data to transmit
            rx          :   IN      STD_LOGIC;                                  --receive pin
            rx_busy :   OUT STD_LOGIC;                                          --data reception in progress
            rx_error    :   OUT STD_LOGIC;                                      --start, parity, or stop bit error detected
            rx_data :   OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);               --data received
            tx_busy :   OUT STD_LOGIC;                                          --transmission in progress
            tx          :   OUT STD_LOGIC);                                     --transmit pin
    END COMPONENT;


begin
    -- UART
        DATAOUT: UART_c
        PORT MAP (  CLK => CLOCK_UART,  --system clock
                    reset_n =>reset_n,      --ascynchronous reset
                    tx_ena => tx_ena,--txEN(0),         --initiate transmission
                    tx_data => DIN(7 downto 0), --data to transmit
                    rx =>'0' ,          --receive pin
                    tx => tx,           --transmit pin
                    tx_busy => tx_busy
                    );

        --UART LOAD 
        --LOADER: NOTM
        --PORT MAP (INPUT => LOAD, OUTPUT => counter);

        -- DATA to MUX
        --MUX: MUX421
        --PORT MAP (s => MUX_S, A => MUX_0, B => MUX_1, C => X"0D", D => X"0A", O => DO-- DATAsnd
        --); -- C => X"0D", D => X"0A" cartidge return and line feed

        -- Counter to mux
        --cntr: binary_counter
        --generic map (MAX_COUNT => 2)
        --PORT MAP (
            --clk         => counter,
            --reset   => RESET,
            --enable      => ENABLE,
            --q       => MUX_S
        --);

        -- Counter to load
        --Load_UART: binary_counter
        --generic map (MAX_COUNT => 1)
        --PORT MAP (
            --clk         => CLOCK_UART,
            --reset   => RESET,
            --enable      => LOAD,
            --q       => txEN
        --);

         --DATA to UART
        --UARTBUFFER_0: InputBuffer
        --generic map (N   => 8)
        --PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(15 downto 8), OUTPUT => MUX_0);   

         --DATA to UART
        --UARTBUFFER_1: InputBuffer
        --generic map (N   => 8)
        --PORT MAP ( clk => CLOCK_UART, En =>ENABLE, Input => DIN(7 downto 0), OUTPUT => MUX_1);


end Behavior;

这是UART本身

--------------------------------------------------------------------------------
--
--   FileName:         uart_c.vhd
--   Dependencies:     none
--   Design Software:  Quartus II 64-bit Version 13.1.0 Build 162 SJ Web Edition
--
--   HDL CODE IS PROVIDED "AS IS."  DIGI-KEY EXPRESSLY DISCLAIMS ANY
--   WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
--   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
--   PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
--   BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
--   DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
--   PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
--   BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
--   ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
--
--   Version History
--   Version 1.0 5/26/2017 Scott Larson
--     Initial Public Release
--    
--------------------------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY uart_c IS
    GENERIC(
        clk_freq        :   INTEGER     := 50_000_000;  --frequency of system clock in Hertz
        baud_rate   :   INTEGER     := 19_200;      --data link baud rate in bits/second
        os_rate     :   INTEGER     := 16;          --oversampling rate to find center of receive bits (in samples per baud period)
        d_width     :   INTEGER     := 8;           --data bus width
        parity      :   INTEGER     := 1;               --0 for no parity, 1 for parity
        parity_eo   :   STD_LOGIC   := '0');            --'0' for even, '1' for odd parity
    PORT(
        clk     :   IN      STD_LOGIC;                                      --system clock
        reset_n :   IN      STD_LOGIC;                                      --ascynchronous reset
        tx_ena  :   IN      STD_LOGIC;                                      --initiate transmission
        tx_data :   IN      STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);  --data to transmit
        rx          :   IN      STD_LOGIC;                                      --receive pin
        rx_busy :   OUT STD_LOGIC;                                      --data reception in progress
        rx_error    :   OUT STD_LOGIC;                                      --start, parity, or stop bit error detected
        rx_data :   OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);   --data received
        tx_busy :   OUT STD_LOGIC;                                      --transmission in progress
        tx          :   OUT STD_LOGIC);                                     --transmit pin
END uart_c;

ARCHITECTURE logic OF uart_c IS
    TYPE        tx_machine IS(idle, transmit);                                      --tranmit state machine data type
    TYPE        rx_machine IS(idle, receive);                                           --receive state machine data type
    SIGNAL  tx_state                :   tx_machine;                                     --transmit state machine
    SIGNAL  rx_state                :   rx_machine;                                     --receive state machine
    SIGNAL  baud_pulse          :   STD_LOGIC := '0';                               --periodic pulse that occurs at the baud rate
    SIGNAL  os_pulse                :   STD_LOGIC := '0';                           --periodic pulse that occurs at the oversampling rate
    SIGNAL  parity_error        :   STD_LOGIC;                                      --receive parity error flag
    SIGNAL  rx_parity           :   STD_LOGIC_VECTOR(d_width DOWNTO 0);     --calculation of receive parity
    SIGNAL  tx_parity           :   STD_LOGIC_VECTOR(d_width DOWNTO 0);     --calculation of transmit parity
    SIGNAL  rx_buffer           :   STD_LOGIC_VECTOR(parity+d_width DOWNTO 0) := (OTHERS => '0');   --values received
    SIGNAL  tx_buffer           :   STD_LOGIC_VECTOR(parity+d_width+1 DOWNTO 0) := (OTHERS => '1'); --values to be transmitted
BEGIN

    --generate clock enable pulses at the baud rate and the oversampling rate
    PROCESS(reset_n, clk)
        VARIABLE count_baud :   INTEGER RANGE 0 TO clk_freq/baud_rate-1 := 0;           --counter to determine baud rate period
        VARIABLE count_os       :   INTEGER RANGE 0 TO clk_freq/baud_rate/os_rate-1 := 0;   --counter to determine oversampling period
    BEGIN
        IF(reset_n = '0') THEN                                          --asynchronous reset asserted
            baud_pulse <= '0';                                              --reset baud rate pulse
            os_pulse <= '0';                                                    --reset oversampling rate pulse
            count_baud := 0;                                                    --reset baud period counter
            count_os := 0;                                                      --reset oversampling period counter
        ELSIF(clk'EVENT AND clk = '1') THEN
            --create baud enable pulse
            IF(count_baud < clk_freq/baud_rate-1) THEN          --baud period not reached
                count_baud := count_baud + 1;                               --increment baud period counter
                baud_pulse <= '0';                                          --deassert baud rate pulse
            ELSE                                                                --baud period reached
                count_baud := 0;                                                --reset baud period counter
                baud_pulse <= '1';                                          --assert baud rate pulse
                count_os := 0;                                                  --reset oversampling period counter to avoid cumulative error
            END IF;
            --create oversampling enable pulse
            IF(count_os < clk_freq/baud_rate/os_rate-1) THEN    --oversampling period not reached
                count_os := count_os + 1;                                   --increment oversampling period counter
                os_pulse <= '0';                                                --deassert oversampling rate pulse      
            ELSE                                                                --oversampling period reached
                count_os := 0;                                                  --reset oversampling period counter
                os_pulse <= '1';                                                --assert oversampling pulse
            END IF;
        END IF;
    END PROCESS;

    --receive state machine
    PROCESS(reset_n, clk)
            VARIABLE rx_count   :   INTEGER RANGE 0 TO parity+d_width+2 := 0;       --count the bits received
            VARIABLE    os_count    :   INTEGER RANGE 0 TO os_rate-1 := 0;              --count the oversampling rate pulses
    BEGIN
        IF(reset_n = '0') THEN                                                              --asynchronous reset asserted
            os_count := 0;                                                                          --clear oversampling pulse counter
            rx_count := 0;                                                                          --clear receive bit counter
            rx_busy <= '0';                                                                     --clear receive busy signal
            rx_error <= '0';                                                                        --clear receive errors
            rx_data <= (OTHERS => '0');                                                     --clear received data output
            rx_state <= idle;                                                                       --put in idle state
        ELSIF(clk'EVENT AND clk = '1' AND os_pulse = '1') THEN                      --enable clock at oversampling rate
            CASE rx_state IS
                WHEN idle =>                                                                        --idle state
                    rx_busy <= '0';                                                                 --clear receive busy flag
                    IF(rx = '0') THEN                                                               --start bit might be present
                        IF(os_count < os_rate/2) THEN                                                   --oversampling pulse counter is not at start bit center
                            os_count := os_count + 1;                                                       --increment oversampling pulse counter
                            rx_state <= idle;                                                                   --remain in idle state
                        ELSE                                                                                    --oversampling pulse counter is at bit center
                            os_count := 0;                                                                      --clear oversampling pulse counter
                            rx_count := 0;                                                                      --clear the bits received counter
                            rx_busy <= '1';                                                                 --assert busy flag
                            rx_state <= receive;                                                                --advance to receive state
                        END IF;
                    ELSE                                                                                    --start bit not present
                        os_count := 0;                                                                      --clear oversampling pulse counter
                        rx_state <= idle;                                                                   --remain in idle state
                    END IF;
                WHEN receive =>                                                                 --receive state
                    IF(os_count < os_rate-1) THEN                                                   --not center of bit
                        os_count := os_count + 1;                                                       --increment oversampling pulse counter
                        rx_state <= receive;                                                                --remain in receive state
                    ELSIF(rx_count < parity+d_width) THEN                                       --center of bit and not all bits received
                        os_count := 0;                                                                      --reset oversampling pulse counter      
                        rx_count := rx_count + 1;                                                       --increment number of bits received counter
                        rx_buffer <= rx & rx_buffer(parity+d_width DOWNTO 1);                   --shift new received bit into receive buffer
                        rx_state <= receive;                                                                --remain in receive state
                    ELSE                                                                                    --center of stop bit
                        rx_data <= rx_buffer(d_width DOWNTO 1);                                 --output data received to user logic
                        rx_error <= rx_buffer(0) OR parity_error OR NOT rx;                 --output start, parity, and stop bit error flag
                        rx_busy <= '0';                                                                 --deassert received busy flag
                        rx_state <= idle;                                                                   --return to idle state
                    END IF;
            END CASE;
        END IF;
    END PROCESS;

    --receive parity calculation logic
    rx_parity(0) <= parity_eo;
    rx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
        rx_parity(i+1) <= rx_parity(i) XOR rx_buffer(i+1);
    END GENERATE;
    WITH parity SELECT  --compare calculated parity bit with received parity bit to determine error
        parity_error <=     rx_parity(d_width) XOR rx_buffer(parity+d_width) WHEN 1,    --using parity
                                '0' WHEN OTHERS;                                                        --not using parity

    --transmit state machine
    PROCESS(reset_n, clk)
        VARIABLE tx_count       :   INTEGER RANGE 0 TO parity+d_width+3 := 0;  --count bits transmitted
    BEGIN
        IF(reset_n = '0') THEN                                                              --asynchronous reset asserted
            tx_count := 0;                                                                          --clear transmit bit counter
            tx <= '1';                                                                              --set tx pin to idle value of high
            tx_busy <= '1';                                                                     --set transmit busy signal to indicate unavailable
            tx_state <= idle;                                                                       --set tx state machine to ready state
        ELSIF(clk'EVENT AND clk = '1') THEN
            CASE tx_state IS
                WHEN idle =>                                                                    --idle state
                    IF(tx_ena = '1') THEN                                                       --new transaction latched in
                        tx_buffer(d_width+1 DOWNTO 0) <=  tx_data & '0' & '1';          --latch in data for transmission and start/stop bits
                        IF(parity = 1) THEN                                                         --if parity is used
                            tx_buffer(parity+d_width+1) <= tx_parity(d_width);                  --latch in parity bit from parity logic
                        END IF;
                        tx_busy <= '1';                                                             --assert transmit busy flag
                        tx_count := 0;                                                                  --clear transmit bit count
                        tx_state <= transmit;                                                       --proceed to transmit state
                    ELSE                                                                                --no new transaction initiated
                        tx_busy <= '0';                                                             --clear transmit busy flag
                        tx_state <= idle;                                                               --remain in idle state
                    END IF;
                WHEN transmit =>                                                                --transmit state
                    IF(baud_pulse = '1') THEN                                                   --beginning of bit
                        tx_count := tx_count + 1;                                                   --increment transmit bit counter
                        tx_buffer <= '1' & tx_buffer(parity+d_width+1 DOWNTO 1);            --shift transmit buffer to output next bit
                    END IF;
                    IF(tx_count < parity+d_width+3) THEN                                    --not all bits transmitted
                        tx_state <= transmit;                                                       --remain in transmit state
                    ELSE                                                                                --all bits transmitted
                        tx_state <= idle;                                                               --return to idle state
                    END IF;
            END CASE;
            tx <= tx_buffer(0);                                                             --output last bit in transmit transaction buffer
        END IF;
    END PROCESS;    

    --transmit parity calculation logic
    tx_parity(0) <= parity_eo;
    tx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
        tx_parity(i+1) <= tx_parity(i) XOR tx_data(i);
    END GENERATE;

END logic;

这是测试台

-- VHDL Test Bench Created from source file UART_TOP.vhd -- Sun Aug 19 12:41:55 2018

--
-- Notes: 
-- 1) This testbench template has been automatically generated using types
-- std_logic and std_logic_vector for the ports of the unit under test.
-- Lattice recommends that these types always be used for the top-level
-- I/O of a design in order to guarantee that the testbench will bind
-- correctly to the timing (post-route) simulation model.
-- 2) To use this template as your testbench, change the filename to any
-- name of your choice with the extension .vhd, and use the "source->import"
-- menu in the ispLEVER Project Navigator to import the testbench.
-- Then edit the user defined section below, adding code to generate the 
-- stimulus for your design.
-- 3) VHDL simulations will produce errors if there are Lattice FPGA library 
-- elements in your design that require the instantiation of GSR, PUR, and
-- TSALL and they are not present in the testbench. For more information see
-- the How To section of online help.  
--
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY testbench IS
END testbench;

ARCHITECTURE behavior OF testbench IS 

    COMPONENT UART_TOP
    PORT(
        reset_n : IN std_logic;
        tx_ena : IN std_logic;
        CLOCK_UART : IN std_logic;
        DIN : IN std_logic_vector(15 downto 0);          
        tx_busy : OUT std_logic;
        tx : OUT std_logic
        );
    END COMPONENT;

    SIGNAL reset_n :  std_logic;
    SIGNAL tx_ena :  std_logic;
    SIGNAL tx_busy :  std_logic;
    SIGNAL tx :  std_logic;
    SIGNAL CLOCK_UART :  std_logic;
    SIGNAL DIN :  std_logic_vector(15 downto 0);
    constant half_period : time := 10 ns;

BEGIN

-- Please check and add your generic clause manually
    uut: UART_TOP PORT MAP(
        reset_n => reset_n,
        tx_ena => tx_ena,
        tx_busy => tx_busy,
        tx => tx,
        CLOCK_UART => CLOCK_UART,
        DIN => DIN
    );


-- *** Test Bench - User Defined Section ***
   tb : PROCESS
   BEGIN     
       reset_n <= '1'; 
       tx_ena <= '0';
        DIN <= B"0101010101010101";
        CLOCK_UART <= '1';
        wait for half_period ;
        CLOCK_UART <= '0';
        wait for half_period ;
        CLOCK_UART <= '1';
        wait for half_period ;
        CLOCK_UART <= '0';
        wait for half_period ;

        tx_ena <= '1';
    loop
         CLOCK_UART <= '1';
        wait for half_period ;
        tx_ena <= '0';
        CLOCK_UART <= '0';
        wait for half_period ;
    end loop;       

   END PROCESS;
-- *** End Test Bench - User Defined Section ***


END;

标签: vhdluartlattice-diamond

解决方案


推荐阅读