library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.gen_pkg.all; entity uart_rx is generic ( CLK_FREQ : integer := 33000000; BAUDRATE : integer := 115200 ); port( sys_clk : in std_logic; sys_res_n : in std_logic; rxd : in std_logic; rx_data : out std_logic_vector(7 downto 0); rx_new : out std_logic ); end entity uart_rx; architecture beh of uart_rx is constant BAUD : integer := CLK_FREQ/BAUDRATE; type STATE_UART_RX is (IDLE, STARTBIT, DBITS, STOPBIT); signal state : STATE_UART_RX; signal startbitdetection : std_logic_vector(1 downto 0); signal bitcnt : integer range 0 to 7; signal baudcnt : integer range 0 to BAUD + 2; signal rx_data_int : std_logic_vector(7 downto 0); begin rx_data <= rx_data_int; process(sys_clk, sys_res_n) begin if (sys_res_n = '0') then state <= IDLE; rx_data_int <= (others => '0'); rx_new <= '0'; bitcnt <= 0; baudcnt <= 0; startbitdetection <= b"11"; elsif rising_edge(sys_clk) then startbitdetection <= startbitdetection(0) & rxd; rx_new <= '0'; baudcnt <= baudcnt + 1; case state is when IDLE => baudcnt <= 0; -- bei fallender flanke koennte starbit folgen if startbitdetection = b"10" then state <= STARTBIT; end if; when STARTBIT => rx_data_int <= (others => '0'); -- halbe BAUDTIME warten, um immer in der mitte abzutasten -- vgl. http://upload.wikimedia.org/wikipedia/de/d/de/RS-232_timing.png if baudcnt = BAUD/2 then baudcnt <= 0; if rxd = '0' then -- starbit (= '0')? dann kommen daten state <= DBITS; bitcnt <= 0; baudcnt <= 0; else -- sonst war das nix... state <= IDLE; end if; end if; when DBITS => if baudcnt = BAUD then baudcnt <= 0; -- bitorder beachten rx_data_int <= rxd & rx_data_int(7 downto 1); if bitcnt = 7 then state <= STOPBIT; else bitcnt <= bitcnt + 1; end if; end if; when STOPBIT => if baudcnt = BAUD then state <= IDLE; if rxd = '1' then rx_new <= '1'; end if; end if; end case; end if; end process; end architecture beh;