-- UART TRANSMITTER library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- DBIT is the number of data bits. STOP_BITS_TICKS is the number of stop bit * 16 -- Oversampling is set to 16 times the baud rate. tx_start is command to start transmitting, baud_in -- is baud clock input, din is 8-bit input to be transmitted, tx_done_tick indicates completion of -- transmission, tx is output wire of UART. entity UART_TX is generic( DBIT: integer := 8; STOP_BITS_TICKS: integer := 16 ); port( clk, reset: in std_logic; tx_start: in std_logic; baud_in: in std_logic; din: in std_logic_vector(7 downto 0); tx_done_tick: out std_logic; tx: out std_logic ); end UART_TX; architecture beh of UART_TX is type state_type is (idle, start, data, stop); signal state_reg, state_next: state_type; -- Oversampling is 16 baud ticks so 4 bits will do, number of bits is 8 so 3 bits will do signal baud_cnt_reg, baud_cnt_next: unsigned(3 downto 0); signal bits_cnt_reg, bits_cnt_next: unsigned(2 downto 0); signal byte_reg, byte_next: std_logic_vector(7 downto 0); signal tx_reg, tx_next: std_logic; begin -- FFs -- baud_cnt_reg tracks baud ticks for oversampling, bits_cnt_reg tracks number of bits transmitted, -- byte_reg holds the bits of the outgoing byte process(clk, reset) begin if (reset = '1') then state_reg <= idle; baud_cnt_reg <= (others => '0'); bits_cnt_reg <= (others => '0'); byte_reg <= (others => '0'); tx_reg <= '1'; elsif (clk'event and clk='1') then state_reg <= state_next; baud_cnt_reg <= baud_cnt_next; bits_cnt_reg <= bits_cnt_next; byte_reg <= byte_next; tx_reg <= tx_next; end if; end process; -- next state logic process (state_reg, baud_cnt_reg, bits_cnt_reg, byte_reg, baud_in, tx_reg, tx_start, din) begin -- default assignments for FFs is to save the current values, for state machine, it's the current -- state, tx_done_tick is '0' until an entire byte is transmitted state_next <= state_reg; baud_cnt_next <= baud_cnt_reg; bits_cnt_next <= bits_cnt_reg; byte_next <= byte_reg; tx_next <= tx_reg; tx_done_tick <= '0'; case state_reg is when idle => -- hold tx wire high when 'not' in transmission mode tx_next <= '1'; -- if external signal indicates 'start transmitting', then initialize counter -- baud_cnt_reg and latch 8-bit input into byte_reg -- change state to 'start' if (tx_start = '1') then state_next <= start; baud_cnt_next <= (others => '0'); byte_next <= din; end if; when start => -- put out 0 on tx for start bit tx_next <= '0'; -- wait for baud tick if (baud_in = '1') then -- if the 15th band rate tick is received, end start bit, begin data bits, -- re-initialize baud counter (baud_cnt_reg), and bit counter (bits_cnt_reg) if (baud_cnt_reg = 15) then state_next <= data; baud_cnt_next <= (others => '0'); bits_cnt_next <= (others => '0'); -- keep counting baud ticks else baud_cnt_next <= baud_cnt_reg + 1; end if; end if; when data => -- put low order bit of data on tx tx_next <= byte_reg(0); -- wait for baud tick if (baud_in = '1') then -- if 15, then move to next bit, re-initialize counter and shift right eliminating -- low order bit just transmitted. Bits sent LSB to MSB if (baud_cnt_reg = 15) then baud_cnt_next <= (others => '0'); byte_next <= '0' & byte_reg(7 downto 1); -- check if there are any more bits -- if so, we're done, goto 'stop' state if (bits_cnt_reg = (DBIT - 1)) then state_next <= stop; -- else increment bit counter else bits_cnt_next <= bits_cnt_reg + 1; end if; -- keep counting baud ticks else baud_cnt_next <= baud_cnt_reg + 1; end if; end if; when stop => -- put out stop bit ('1' on tx_reg) tx_next <= '1'; -- wait for baud tick if (baud_in = '1') then -- if we've counted enough baud ticks for the stop bits indicated above, then -- pulse 'tx_done_tick' and return to idle if (baud_cnt_reg = (STOP_BITS_TICKS-1)) then state_next <= idle; tx_done_tick <= '1'; -- else keep counting baud ticks else baud_cnt_next <= baud_cnt_reg + 1; end if; end if; end case; end process; -- output of FF tx_reg drives tx wire of UART port tx <= tx_reg; end beh;