-- -------------------------------------------------------------------------- -- -- uart_rx.vhd: Basic UART (rx) -- -- Copyright (C) 2017 Markus Koch -- -- This Source Code Form is subject to the terms of the Mozilla Public -- License, v. 2.0. If a copy of the MPL was not distributed with this -- file, You can obtain one at http://mozilla.org/MPL/2.0/. -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity uart_rx is port( clk : in std_logic; rst : in std_logic; data : out std_logic_vector(7 downto 0); byte_ready : out std_logic; error : out std_logic; ckDiv : in std_logic_vector(15 downto 0); parityEnable : in std_logic; parityOdd : in std_logic; twoStopBits : in std_logic; rx : in std_logic ); end entity uart_rx; architecture RTL of uart_rx is constant SYNCH_COUNT : integer := 11; -- Min. 8 constant BITCOUNT : integer := 8; type state_t is (SYNCH, IDLE, START, RECEIVE, PARITY, STOP); signal state : state_t; signal clkDivider : unsigned(15 downto 0); signal bitCounter : integer range 0 to SYNCH_COUNT; signal data_i : std_logic_vector(7 downto 0); signal rx_edge : std_logic; signal parity_calc : std_logic; signal rx_i : std_logic; begin synchronizer_inst : entity work.synchronizer generic map( COUNT => 1 ) port map( clk => clk, rst => rst, dIn(0) => rx, dOut(0) => rx_i ); edgeDetector_inst : entity work.edgeDetector port map(clk => clk, rst => rst, sig => rx_i, risingEdge => open, fallingEdge => open, anyEdge => rx_edge); rxFSM : process(clk, rst, parityOdd, ckDiv) is begin if rst = '1' then state <= SYNCH; bitCounter <= SYNCH_COUNT; clkDivider <= unsigned(ckDiv); error <= '0'; parity_calc <= parityOdd; data_i <= x"00"; data <= x"00"; byte_ready <= '0'; elsif rising_edge(clk) then byte_ready <= '0'; error <= '0'; if (clkDivider = 0) then clkDivider <= unsigned(ckDiv); else clkDivider <= clkDivider - 1; end if; case state is when SYNCH => -- Wait for 11 consecutive ones if (clkDivider = to_unsigned(0, clkDivider'length)) then if rx_i = '1' then if bitCounter = 0 then state <= IDLE; else bitCounter <= bitcounter - 1; end if; else bitCounter <= SYNCH_COUNT; end if; end if; when IDLE => -- Detect transition for sync if rx_i = '0' then state <= START; clkDivider <= unsigned('0' & ckDiv(15 downto 1)); -- cMax_half. After that we are in the middle of the start bit parity_calc <= parityOdd; end if; when START => if (clkDivider = to_unsigned(0, clkDivider'length)) then if rx_i = '0' then state <= RECEIVE; bitCounter <= 0; else report "uart_rx: START BIT ERROR" severity warning; error <= '1'; state <= SYNCH; end if; end if; when RECEIVE => if (clkDivider = to_unsigned(0, clkDivider'length)) then data_i(bitCounter) <= rx_i; if rx_i = '1' then parity_calc <= not parity_calc; end if; if bitCounter = BITCOUNT - 1 then bitCounter <= 0; if parityEnable = '1' then state <= PARITY; else state <= STOP; end if; else bitCounter <= bitCounter + 1; end if; end if; when PARITY => if (clkDivider = to_unsigned(0, clkDivider'length)) then if parity_calc = rx_i then state <= STOP; else state <= SYNCH; error <= '1'; report "uart_rx: PARITY ERROR" severity warning; end if; end if; when STOP => if (clkDivider = to_unsigned(0, clkDivider'length)) then if (rx_i = '1') then bitCounter <= bitCounter + 1; if bitCounter = 1 or twoStopBits = '0' then state <= IDLE; data <= data_i; byte_ready <= '1'; end if; else error <= '1'; state <= SYNCH; report "uart_rx: STOP BIT ERROR" severity warning; end if; end if; end case; end if; end process rxFSM; end architecture RTL;