use work.gen_pkg.all;
entity uart_rx is
-port(
- sys_clk : in std_logic;
- sys_res : in std_logic;
- txd : in std_logic; -- warning: this is asynchronous input!
- tx_data : out std_logic_vector(7 downto 0); -- map this to a larger register with containing input
- tx_new : out std_logic
-);
+ 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 timer_max : integer := 35;
+ constant BAUD : integer := CLK_FREQ/BAUDRATE;
- type STATE_UART_RX is (IDLE, BUSY, DONE);
+ type STATE_UART_RX is (IDLE, STARTBIT, DBITS, STOPBIT);
+ signal state : STATE_UART_RX;
- signal timer, timer_next : integer range 0 to 65535;
- signal counter, counter_next : integer range 0 to 15;
- signal state, state_next : STATE_UART_RX;
- signal tx_data_prev : std_logic_vector(7 downto 0); -- FIXME: this isnt named next so that the interface isn't called tx_data_next ...
-
- -- these are internal signals that are actually used as in and output
- signal tx_data_i : std_logic_vector(7 downto 0);
- signal tx_new_i : std_logic;
+ 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
---FIXME:
-
- tx_new <= tx_new_i;
- tx_data <= tx_data_i;
-
- process(sys_clk, sys_res)
+ rx_data <= rx_data_int;
+ process(sys_clk, sys_res_n)
begin
- if (sys_res = '0') then
- -- Set reset state
+ if (sys_res_n = '0') then
state <= IDLE;
- tx_data_prev <= X"00";
+ rx_data_int <= (others => '0');
+ rx_new <= '0';
+ bitcnt <= 0;
+ baudcnt <= 0;
+ startbitdetection <= b"11";
elsif rising_edge(sys_clk) then
- -- Store next state
- state <= state_next;
- tx_data_prev <= tx_data_i;
- end if;
- end process;
+ 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');
- process(state, txd, counter)
- begin
- state_next <= state;
- case state is
- when IDLE =>
- if (txd = '0') then
- state_next <= BUSY;
- else
- state_next <= IDLE;
- end if;
- when BUSY =>
- if (counter = 9) then --FIXME: is this true?
- state_next <= DONE;
- else
- state_next <= BUSY;
- end if;
- when DONE =>
- state_next <= IDLE;
- end case;
- end process;
+ -- 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);
- process(state)
- begin
- -- Set default values
- -- for the outputs
- tx_new_i <= '0';
-
- -- Calculate the outputs
- -- based on the current
- -- state
- case state is
- when IDLE =>
- tx_new_i <= '0';
- when BUSY =>
- tx_new_i <= '0';
- when DONE =>
- tx_new_i <= '1';
- end case;
- end process;
--- END FIXME: do fill this out CORRECTLY
-
- process (sys_clk, sys_res)
- begin
- if sys_res = '0' then
- counter <= 0;
- timer <= 0;
- elsif rising_edge(sys_clk) then
- counter <= counter_next;
- timer <= timer_next;
+ 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;
-
- process (timer)
- begin
- if (timer = timer_max) then
- timer_next <= 0;
- else
- timer_next <= timer + 1;
- end if;
- end process;
-
- process (timer, counter, tx_new_i)
- begin
- if (tx_new_i = '1') then
- if (timer = timer_max) then
- if (counter > 10) then
- counter_next <= 0;
- else
- counter_next <= counter + 1;
- end if;
- else
- counter_next <= counter;
- end if;
- else
- counter_next <= 0;
- end if;
- end process;
-
- process (counter, txd)
- begin
- tx_data_i <= tx_data_prev;
- -- TODO: we probably want oversampling and averaging + failure!
- -- FIXME: this is per se not synthesisable
- case (counter) is
- when 0 => --start bit
- assert (txd = '0');
- when 1 =>
- tx_data_i(0) <= txd;
- when 2 =>
- tx_data_i(1) <= txd;
- when 3 =>
- tx_data_i(2) <= txd;
- when 4 =>
- tx_data_i(3) <= txd;
- when 5 =>
- tx_data_i(4) <= txd;
- when 6 =>
- tx_data_i(5) <= txd;
- when 7 =>
- tx_data_i(6) <= txd;
- when 8 =>
- tx_data_i(7) <= txd;
- when 9 => -- stop bit
- assert (txd = '1');
- when others => -- idle
- assert (txd = '1');
- end case;
- end process;
-
end architecture beh;