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 counter_max : integer := 9;
- constant samples : integer := 8;
+ 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_int, state_next : STATE_UART_RX;
- signal timer, timer_next : integer range 0 to 65535;
- signal counter, counter_next : integer range 0 to 15;
- signal sample_counter, sample_counter_next : integer range 0 to counter_max-1;
- signal state, state_next : STATE_UART_RX;
- signal sync1, sync2, txd_next: std_logic; --synchronizers FIXME!
-
- -- these are internal signals that are actually used as in and output
- signal tx_data_prev : std_logic_vector(7 downto 0);
- signal tx_new_i : std_logic;
- signal shift, shift_value, shift_reset : std_logic;
+ 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;
- tx_new <= tx_new_i;
-
- process(sys_clk, sys_res)
+ process(sys_clk, sys_res_n)
begin
- if (sys_res = '0') then
- -- Set reset state
- state <= IDLE;
- tx_data_prev <= X"00";
-
- txd_next <= '0'; --fixme: syncronizers!
- sync2 <= '0';
- sync1 <= '0';
- timer <= 0;
- counter <= 0;
+ 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
- -- Store next state
- state <= state_next;
- if (shift = '1') then
- tx_data(7 downto 1) <= tx_data_prev(6 downto 1);
- tx_data(0) <= shift_value;
- elsif ( shift_reset = '1') then
- tx_data <= X"00";
- end if;
-
- txd_next <= sync2; --fixme: syncronizers!
- sync2 <= sync1;
- sync1 <= txd;
- counter <= counter_next;
- sample_counter <= sample_counter_next;
- timer <= timer_next;
+ 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, txd, counter)
+ process(state_int, rx_data_int, rxd, bitcnt_int, baudcnt_int,
+ startbitdetection)
begin
- state_next <= state;
+ state_next <= state_int;
+ rx_data_next <= rx_data_int;
+ rx_new_next <= '0';
+ bitcnt_next <= bitcnt_int;
+ baudcnt_next <= baudcnt_int;
- shift <= '0';
- shift_reset <='0';
- shift_value <= '0';
- timer_next <= 0;
- counter_next <= 0;
-
- case state is
+ case state_int is
when IDLE =>
- if (txd = '0') then
- state_next <= BUSY;
- shift_reset <= '1';
- end if;
- when BUSY =>
- if (counter = counter_max) then --FIXME: is this true?
- state_next <= DONE;
+ -- 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');
- if (timer = timer_max) then
- timer_next <= 0;
- counter_next <= counter + 1;
- if (sample_counter < samples/2) then
- shift_value <= '1';
+ -- 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
- shift_value <= '0';
+ -- sonst war das nix...
+ state_next <= IDLE;
end if;
- shift <= '1';
- else
- timer_next <= timer + 1;
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 timer = timer_max/samples and txd_next = '1' then
- sample_counter_next <= sample_counter + 1;
+ 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;
- when DONE =>
- state_next <= IDLE;
end case;
end process;
-
end architecture beh;