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_int, state_next : STATE_UART_RX; signal rx_data_next, rx_data_int : std_logic_vector(7 downto 0); signal rx_new_next, rx_new_int : std_logic; signal startbitdetection : std_logic_vector(1 downto 0); signal bitcnt_int, bitcnt_next : integer range 0 to 7; signal baudcnt_int, baudcnt_next : integer range 0 to BAUD; begin rx_new <= rx_new_int; rx_data <= rx_data_int; process(sys_clk, sys_res_n) begin if (sys_res_n = '0') then state_int <= IDLE; rx_data_int <= (others => '0'); rx_new_int <= '0'; bitcnt_int <= 0; baudcnt_int <= 0; startbitdetection <= b"11"; elsif rising_edge(sys_clk) then state_int <= state_next; rx_data_int <= rx_data_next; rx_new_int <= rx_new_next; bitcnt_int <= bitcnt_next; baudcnt_int <= baudcnt_next; startbitdetection(0) <= rxd; startbitdetection(1) <= startbitdetection(0); end if; end process; process(state_int, rx_data_int, rxd, bitcnt_int, baudcnt_int, startbitdetection) begin state_next <= state_int; rx_data_next <= rx_data_int; rx_new_next <= '0'; bitcnt_next <= bitcnt_int; baudcnt_next <= baudcnt_int; case state_int is when IDLE => -- bei fallender flanke koennte starbit folgen if startbitdetection = b"10" then state_next <= STARTBIT; baudcnt_next <= 0; end if; when STARTBIT => rx_data_next <= (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_int < BAUD/2 then baudcnt_next <= baudcnt_int + 1; else baudcnt_next <= 0; if rxd = '0' then -- starbit (= '0')? dann kommen daten state_next <= DBITS; bitcnt_next <= 0; else -- sonst war das nix... state_next <= IDLE; end if; end if; when DBITS => if baudcnt_int < BAUD then baudcnt_next <= baudcnt_int + 1; else baudcnt_next <= 0; rx_data_next <= rx_data_int(6 downto 0) & rxd; if bitcnt_int = 7 then state_next <= STOPBIT; else bitcnt_next <= bitcnt_int + 1; end if; end if; when STOPBIT => if baudcnt_int < BAUD then baudcnt_next <= baudcnt_int + 1; else state_next <= IDLE; if rxd = '1' then rx_new_next <= '1'; end if; end if; end case; end process; end architecture beh;