LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; entity UART_VHDL is port ( clock: in std_logic; reset_N: in std_logic; address: in std_logic; writeData: in std_logic_vector(7 downto 0); write: in std_logic; readData: out std_logic_vector(7 downto 0); read: in std_logic; serialIn: in std_logic; serialOut: out std_logic ); end UART_VHDL; ARCHITECTURE DUFF OF UART_VHDL IS constant ONCE: integer := 0; constant TWICE: integer := 1; type t_TxState is ( IDLE, SEND ); type t_RxState is ( IDLE, START, RECEIVE, STOP, CHECK_STOP_BIT, ON_ERROR, FULL, ERROR ); constant c_TX: std_logic := '0'; constant c_RX: std_logic := '0'; constant c_STATUS: std_logic := '1'; constant c_RxReady: integer := 0; constant c_RxError: integer := 1; constant c_TxReady: integer := 2; signal status: std_logic_vector(2 downto 0); signal RxState: t_RxState; signal TxState: t_TxState; signal serialInRetimed: std_logic_vector(1 downto 0); signal Tx, Rx: std_logic_vector(7 downto 0); signal TxShiftReg: std_logic_vector(9 downto 0); signal RxShiftReg: std_logic_vector(8 downto 0); signal RxSampleCount, RxBitCount, TxSampleCount, TxBitCount: integer range 0 to 8; signal TxWritten, clearTxWritten, loadTxShiftReg, shiftTx, checkStopBit: std_logic; signal clearRxError, RxHasBeenRead, copyRxShiftReg, shiftRx: std_logic; signal RxError, RxErrorEarly: std_logic; begin --++++++++++++++++++++++++++++ -- + -- Writeable Registers. + -- + --++++++++++++++++++++++++++++ process (clock, reset_N) begin if reset_N = '0' then TxWritten <= '0'; else if clearTxWritten = '1' then TxWritten <= '0'; elsif write = '1' and address = c_TX then Tx <= writeData; TxWritten <= '1'; end if; end if; end process; --+++++++++++++++++++++++++++++++ -- + -- Transmit State Machine. + -- + --+++++++++++++++++++++++++++++++ process (clock, reset_N) begin if reset_N = '0' then TxState <= IDLE; TxSampleCount <= 0; TxBitCount <= 0; loadTxShiftReg <= '0'; shiftTx <= '0'; elsif clock'event and clock='1' then case TxState is when IDLE => shiftTx <= '0'; if( TxWritten = '1' ) then TxSampleCount <= 0; TxBitCount <= 0; TxState <= SEND; loadTxShiftReg <= '1'; clearTxWritten <= '1'; else loadTxShiftReg <= '0'; clearTxWritten <= '0'; TxState <= IDLE; end if; when SEND => loadTxShiftReg <= '0'; if TxSampleCount = 7 then -- Start Bit, Eight Data Bits and Stop Bit. TxSampleCount <= 0; shiftTx <= '1'; if TxBitCount=9 then TxState <= IDLE; else TxBitCount <= TxBitCount+1; TxState <= SEND; end if; else shiftTx <= '0'; TxSampleCount <= TxSampleCount+1; TxState <= SEND; end if; end case; end if; end process; --++++++++++++++++++++++++++++++++ -- + -- Transmit Shift Register. + -- + --++++++++++++++++++++++++++++++++ process (clock, reset_N) begin if reset_N = '0' then TxShiftReg <= (others=>'1'); elsif clock'event and clock='1' then if loadTxShiftReg = '1' then TxShiftReg <= ('1' & Tx & '0' ); -- Stop bit, eight data bits, start bit. elsif shiftTx = '1' then TxShiftReg(8 downto 0) <= TxShiftReg(9 downto 1); end if; end if; end process; serialOut <= TxShiftReg(0); --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -- + -- Re-time any asynchronous signals before use in order + -- to avoid race hazards or problems of metastability + -- + --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ serialInRetimed <= ( serialInRetimed(ONCE) & serialIn ) when clock'event and clock='1'; --++++++++++++++++++++++++++++++ -- + -- Receive State Machine. + -- + --++++++++++++++++++++++++++++++ process (clock, reset_N) begin if reset_N = '0' then RxState <= IDLE; RxSampleCount <= 0; RxBitCount <= 0; shiftRx <= '0'; checkStopBit <= '0'; copyRxShiftReg <= '0'; elsif clock'event and clock='1' then shiftRx <= '0'; checkStopBit <= '0'; copyRxShiftReg <= '0'; case RxState is when IDLE => if serialInRetimed(TWICE) = '0' then -- Falling Edge of Start Bit. RxSampleCount <= 0; RxBitCount <= 0; RxState <= RECEIVE; else RxState <= IDLE; end if; when START => if RxSampleCount = 3 then -- Centre of Start Bit RxState <= RECEIVE; else RxSampleCount <= RxSampleCount+1; RxState <= START; end if; when RECEIVE => if RxSampleCount = 7 then -- Eight Data Bits. if RxBitCount=7 then RxSampleCount <= 0; RxState <= STOP; shiftRx <= '1'; else RxSampleCount <= 0; RxBitCount <= RxBitCount+1; shiftRx <= '1'; end if; else RxSampleCount <= RxSampleCount+1; RxState <= RECEIVE; end if; when STOP => if RxSampleCount = 7 then -- Check Stop Bit shiftRx <= '1'; RxState <= CHECK_STOP_BIT; else RxSampleCount <= RxSampleCount+1; RxState <= STOP; end if; when CHECK_STOP_BIT => checkStopBit <= '1'; RxState <= ON_ERROR; when ON_ERROR => if RxErrorEarly = '1' then copyRxShiftReg <= '1'; RxState <= ERROR; else copyRxShiftReg <= '1'; RxState <= FULL; end if; when FULL => if RxHasBeenRead = '1' then RxState <= IDLE; end if; when ERROR => if clearRxError = '1' then RxState <= IDLE; end if; end case; end if; end process; --+++++++++++++++++++++++++++++++ -- + -- Receive Shift Register. + -- + --+++++++++++++++++++++++++++++++ process (clock, reset_N) begin if reset_N = '0' then RxShiftReg <= (others=>'1'); RxError <= '0'; elsif clock'event and clock='1' then if shiftRx = '1' then RxShiftReg(8 downto 0) <= serialInRetimed(TWICE) & RxShiftReg(8 downto 1); elsif checkStopBit = '1' then if RxShiftReg(8) = '0' then RxError <= '1'; else RxError <= '0'; end if; end if; if clearRxError = '1' then RxError <= '0'; end if; if copyRxShiftReg = '1' then Rx <= RxShiftReg(7 downto 0); end if; end if; end process; RxErrorEarly <= '1' when checkStopBit = '1' and RxShiftReg(8) = '0' else '0'; --+++++++++++++++++++++++++++ -- + -- Readable Registers. + -- + --+++++++++++++++++++++++++++ status(c_RxError) <= RxError; status(c_RxReady) <= '1' when RxState=FULL else '0'; status(c_TxReady) <= '1' when TxState=IDLE else '0'; process (clock, reset_N) begin if reset_N = '0' then readData <= (others=>'0'); clearRxError <= '0'; elsif clock'event and clock='1' then if read = '1' then case address is when c_RX => readData <= Rx; clearRxError <= '0'; RxHasBeenRead <= '1'; when c_STATUS => readData <= ( "00000" & status ); if status(c_RxError) = '1' then clearRxError <= '1'; else clearRxError <= '0'; end if; RxHasBeenRead <= '0'; when others => readData <= (others=>'0'); clearRxError <= '0'; RxHasBeenRead <= '0'; end case; else clearRxError <= '0'; RxHasBeenRead <= '0'; end if; end if; end process; end DUFF;