| @ -0,0 +1,126 @@ | |||
| -- ====================================================================== | |||
| -- UART transmitter | |||
| -- Copyright (C) 2020 Torsten Meissner | |||
| ------------------------------------------------------------------------- | |||
| -- This program is free software; you can redistribute it and/or | |||
| -- modify it under the terms of the GNU Lesser General Public | |||
| -- License as published by the Free Software Foundation; either | |||
| -- version 3 of the License, or (at your option) any later version. | |||
| -- | |||
| -- This program is distributed in the hope that it will be useful, | |||
| -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| -- Lesser General Public License for more details. | |||
| -- | |||
| -- You should have received a copy of the GNU Lesser General Public License | |||
| -- along with this program; if not, write to the Free Software Foundation, | |||
| -- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | |||
| -- ====================================================================== | |||
| library ieee; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| entity UartTx is | |||
| generic ( | |||
| DATA_LENGTH : positive range 5 to 9 := 8; | |||
| PARITY : boolean := false; -- not implemented yet | |||
| CLK_DIV : natural := 10 | |||
| ); | |||
| port ( | |||
| reset_n_i : in std_logic; -- async reset | |||
| clk_i : in std_logic; -- clock | |||
| data_i : in std_logic_vector(DATA_LENGTH-1 downto 0); -- data input | |||
| valid_i : in std_logic; -- input data valid | |||
| accept_o : out std_logic; -- inpit data accepted | |||
| tx_o : out std_logic -- uart tx data output | |||
| ); | |||
| end entity UartTx; | |||
| architecture rtl of UartTx is | |||
| type t_uart_state is (IDLE, SEND); | |||
| signal s_uart_state : t_uart_state; | |||
| signal s_data : std_logic_vector(DATA_LENGTH+1 downto 0); | |||
| signal s_clk_en : boolean; | |||
| function odd_parity (data : in std_logic_vector(DATA_LENGTH-1 downto 0)) return std_logic is | |||
| variable v_data : std_logic := '0'; | |||
| begin | |||
| for i in data'range loop | |||
| v_data := v_data xor data(i); | |||
| end loop; | |||
| return not v_data; | |||
| end function odd_parity; | |||
| begin | |||
| ClkDivP : process (clk_i, reset_n_i) is | |||
| variable v_clk_cnt : natural range 0 to CLK_DIV-1; | |||
| begin | |||
| if (reset_n_i = '0') then | |||
| s_clk_en <= false; | |||
| v_clk_cnt := CLK_DIV-1; | |||
| elsif (rising_edge(clk_i)) then | |||
| if (s_uart_state = IDLE) then | |||
| v_clk_cnt := CLK_DIV-2; | |||
| s_clk_en <= false; | |||
| elsif (s_uart_state = SEND) then | |||
| if (v_clk_cnt = 0) then | |||
| v_clk_cnt := CLK_DIV-1; | |||
| s_clk_en <= true; | |||
| else | |||
| v_clk_cnt := v_clk_cnt - 1; | |||
| s_clk_en <= false; | |||
| end if; | |||
| end if; | |||
| end if; | |||
| end process ClkDivP; | |||
| TxP : process (clk_i, reset_n_i) is | |||
| variable v_bit_cnt : natural range 0 to s_data'length-1; | |||
| begin | |||
| if (reset_n_i = '0') then | |||
| s_uart_state <= IDLE; | |||
| s_data <= (0 => '1', others => '0'); | |||
| accept_o <= '0'; | |||
| v_bit_cnt := 0; | |||
| elsif (rising_edge(clk_i)) then | |||
| FsmL : case s_uart_state is | |||
| when IDLE => | |||
| accept_o <= '1'; | |||
| v_bit_cnt := s_data'length-1; | |||
| if (valid_i = '1' and accept_o = '1') then | |||
| accept_o <= '0'; | |||
| s_data <= '1' & data_i & '0'; | |||
| s_uart_state <= SEND; | |||
| end if; | |||
| when SEND => | |||
| if (s_clk_en) then | |||
| s_data <= '1' & s_data(s_data'length-1 downto 1); | |||
| if (v_bit_cnt = 0) then | |||
| accept_o <= '1'; | |||
| s_uart_state <= IDLE; | |||
| else | |||
| v_bit_cnt := v_bit_cnt - 1; | |||
| end if; | |||
| end if; | |||
| end case; | |||
| end if; | |||
| end process TxP; | |||
| tx_o <= s_data(0); | |||
| end architecture rtl; | |||