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 : 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 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
-
- tx_new <= tx_new_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";
-
- txd_next <= '0'; --fixme: syncronizers!
- sync2 <= '0';
- sync1 <= '0';
- timer <= 0;
- counter <= 0;
+ 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;
- 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;
- end if;
- end process;
-
- process(state, txd, counter)
- begin
- state_next <= state;
-
- shift <= '0';
- shift_reset <='0';
- shift_value <= '0';
- timer_next <= 0;
- counter_next <= 0;
-
- case state 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;
- end if;
+ 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');
- if (timer = timer_max) then
- timer_next <= 0;
- counter_next <= counter + 1;
- if (sample_counter < samples/2) then
- shift_value <= '1';
- else
- shift_value <= '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;
- shift <= '1';
- else
- timer_next <= timer + 1;
- end if;
+ when DBITS =>
+ if baudcnt = BAUD then
+ baudcnt <= 0;
+ -- bitorder beachten
+ rx_data_int <= rxd & rx_data_int(7 downto 1);
- if timer = timer_max/samples and txd_next = '1' then
- sample_counter_next <= sample_counter + 1;
- end if;
- when DONE =>
- state_next <= IDLE;
- end case;
+ 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;