--------------------------------------------------------------------------------- -- Company: Pouet Pouet -- Engineer: BenH -- -- Create Date: 19:10:00 03/01/2008 -- Design Name: -- Module Name: uart - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- Synthetisable mini UART. Input clock is bauds * 16 -- -- Dependencies: none -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity uart is port ( clk : in std_logic; -- base clock (bauds * 16) rst : in std_logic; -- reset active high rx : in std_logic; -- rx line tx : out std_logic; -- tx line rxbyte : out std_logic_vector(7 downto 0); -- rx byte port rxkick : out std_logic; -- rising edge when new rx char txbyte : in std_logic_vector(7 downto 0); -- tx byte port txkick : in std_logic; -- set to 1 to kick tx char when idle txbusy : out std_logic -- set to 1 when tx is sending ); end uart; architecture behaviour of uart is signal tclkcnt : unsigned(3 downto 0); signal rclkcnt : unsigned(3 downto 0); signal txstrobe : std_logic; -- tx bit clock signal rxstrobe : std_logic; -- rx bit clock signal rxhalf : std_logic; -- rx half bit clock signal rxsync : std_logic; -- rx synced (clock on) type tx_state_type is ( TX_IDLE, TX_SHIFT); signal tx_state : tx_state_type; signal txbitcnt : integer range 0 to 8; signal txshift : std_logic_vector(7 downto 0); type rx_state_type is ( RX_IDLE, RX_START, RX_SHIFT); signal rx_state : rx_state_type; signal rxbitcnt : integer range 0 to 8; signal rxshift : std_logic_vector(7 downto 0); signal rxbuf : std_logic; signal rxcur,rxlast : std_logic; begin -- Make tx clock by dividing clk by 16 make_tx_clock: process(clk, rst) begin if rst = '1' then tclkcnt <= (others => '0'); elsif rising_edge(clk) then tclkcnt <= tclkcnt + 1; end if; end process; txstrobe <= '1' when tclkcnt = conv_unsigned(15,4) else '0'; -- Make rx clock and half bit clock by dividing clk by 16 when synced make_rx_clock: process(clk, rxsync, rst) begin if rst = '1' then rclkcnt <= (others => '0'); elsif rising_edge(clk) then rclkcnt <= (others => '0'); if rxsync = '1' then rclkcnt <= rclkcnt + 1; end if; end if; end process; -- Note that we strobe at 14 and not 15 to compensate for the squew -- introduced by the counter reset when switching from RX_START to -- RX_SHIFT states rxstrobe <= '1' when rclkcnt = conv_unsigned(14,4) else '0'; rxhalf <= '1' when rclkcnt = conv_unsigned(7,4) else '0'; -- Tx state machine tx_machine: process(clk, rst) begin if rst = '1' then tx_state <= TX_IDLE; txbusy <= '0'; tx <= '1'; elsif rising_edge(clk) and txstrobe = '1' then case tx_state is when TX_IDLE => -- Latch Tx and begin start bit tx <= '1'; if txkick = '1' then tx_state <= TX_SHIFT; tx <= '0'; txbitcnt <= 8; txshift <= txbyte; txbusy <= '1'; end if; when TX_SHIFT => -- Shift bits out, test for stop if txbitcnt = 0 then tx <= '1'; tx_state <= TX_IDLE; txbusy <= '0'; else tx <= txshift(7); txshift(7 downto 0) <= txshift(6 downto 0) & '1'; txbitcnt <= txbitcnt - 1; end if; end case; end if; end process; -- Rx buffer rx_buffer: process(clk, rst) begin if rst = '1' then rxbuf <= '1'; rxcur <= '1'; rxlast <= '1'; elsif rising_edge(clk) then rxlast <= rxcur; rxcur <= rxbuf; rxbuf <= rx; end if; end process; -- Rx state machine rx_machine: process(clk, rst) begin if rst = '1' then rx_state <= RX_IDLE; rxsync <= '0'; rxkick <= '0'; rxbitcnt <= 0; rxshift <= (others => '0'); elsif rising_edge(clk) then case rx_state is when RX_IDLE => rxkick <= '0'; rxsync <= '0'; if rxcur = '0' and rxlast = '1' then rx_state <= RX_START; rxsync <= '1'; rxshift <= (others => '0'); end if; when RX_START => if rxcur = '1' then -- Error, start bit not long enough rx_state <= RX_IDLE; rxsync <= '0'; elsif rxhalf = '1' then rxsync <= '0'; rx_state <= RX_SHIFT; rxbitcnt <= 8; end if; when RX_SHIFT => rxsync <= '1'; if rxstrobe = '1' then if rxbitcnt = 0 then -- Could check stop bit value rx_state <= RX_IDLE; rxbyte <= rxshift; rxkick <= '1'; else rxshift(7 downto 1) <= rxshift(6 downto 0); rxshift(0) <= rxcur; rxbitcnt <= rxbitcnt - 1; end if; end if; end case; end if; end process; end behaviour;