Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20679 Discussions

Transmit on UART from FSM

CLa_R
Novice
1,384 Views

This is a generic problem with VHDL and no for a specific FPGA device.

 

For now, I use a Cyclone IV FPGA.

 

I have created a FSM and I would that, for each state of FSM, to transmit a char (8 bit) from my UART. The UART transmitter is defined as:

 

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity UART_TX is generic ( g_CLKS_PER_BIT : integer := 139 -- Needs to be set correctly ); port ( i_Clk : in std_logic; i_TX_DV : in std_logic; i_TX_Byte : in std_logic_vector(7 downto 0); o_TX_Active : out std_logic; o_TX_Serial : out std_logic; o_TX_Done : out std_logic ); end UART_TX; architecture RTL of UART_TX is type t_SM_Main is (s_Idle, s_TX_Start_Bit, s_TX_Data_Bits, s_TX_Stop_Bit, s_Cleanup); signal r_SM_Main : t_SM_Main := s_Idle; signal r_Clk_Count : integer range 0 to g_CLKS_PER_BIT-1 := 0; signal r_Bit_Index : integer range 0 to 7 := 0; -- 8 Bits Total signal r_TX_Data : std_logic_vector(7 downto 0) := (others => '0'); signal r_TX_Done : std_logic := '0'; begin p_UART_TX : process (i_Clk) begin if rising_edge(i_Clk) then case r_SM_Main is when s_Idle => o_TX_Active <= '0'; o_TX_Serial <= '1'; -- Drive Line High for Idle r_TX_Done <= '0'; r_Clk_Count <= 0; r_Bit_Index <= 0; if i_TX_DV = '1' then r_TX_Data <= i_TX_Byte; r_SM_Main <= s_TX_Start_Bit; else r_SM_Main <= s_Idle; end if; -- Send out Start Bit. Start bit = 0 when s_TX_Start_Bit => o_TX_Active <= '1'; o_TX_Serial <= '0'; -- Wait g_CLKS_PER_BIT-1 clock cycles for start bit to finish if r_Clk_Count < g_CLKS_PER_BIT-1 then r_Clk_Count <= r_Clk_Count + 1; r_SM_Main <= s_TX_Start_Bit; else r_Clk_Count <= 0; r_SM_Main <= s_TX_Data_Bits; end if; -- Wait g_CLKS_PER_BIT-1 clock cycles for data bits to finish when s_TX_Data_Bits => o_TX_Serial <= r_TX_Data(r_Bit_Index); if r_Clk_Count < g_CLKS_PER_BIT-1 then r_Clk_Count <= r_Clk_Count + 1; r_SM_Main <= s_TX_Data_Bits; else r_Clk_Count <= 0; -- Check if we have sent out all bits if r_Bit_Index < 7 then r_Bit_Index <= r_Bit_Index + 1; r_SM_Main <= s_TX_Data_Bits; else r_Bit_Index <= 0; r_SM_Main <= s_TX_Stop_Bit; end if; end if; -- Send out Stop bit. Stop bit = 1 when s_TX_Stop_Bit => o_TX_Serial <= '1'; -- Wait g_CLKS_PER_BIT-1 clock cycles for Stop bit to finish if r_Clk_Count < g_CLKS_PER_BIT-1 then r_Clk_Count <= r_Clk_Count + 1; r_SM_Main <= s_TX_Stop_Bit; else r_TX_Done <= '1'; r_Clk_Count <= 0; r_SM_Main <= s_Cleanup; end if; -- Stay here 1 clock when s_Cleanup => o_TX_Active <= '0'; r_TX_Done <= '1'; r_SM_Main <= s_Idle; when others => r_SM_Main <= s_Idle; end case; end if; end process p_UART_TX; o_TX_Done <= r_TX_Done; end RTL;

I need to send various char (byte) trough my transmitter, One Char for one state of my FSM.

For this reason I use this code:

 

--[cut]   type t_SM_serial is (s_Start, s_COMMAND, s_BA, s_BB, s_BC);   signal next_state : t_SM_Serial; signal r_SM_serial : t_SM_serial := s_Start;   -- Low-level byte-write-------------------------------------------------------------------- procedure UART_WRITE_BYTE ( i_data_in : in std_logic_vector(7 downto 0) ) is begin r_TX_BYTE <= i_data_in; r_TX_DV <= '1'; end UART_WRITE_BYTE; --------------------------------------------------------------------------------------   begin --------------architecture begin -- Instantiate UART transmitter UART_TX_INST : uart_tx generic map ( g_CLKS_PER_BIT => 139 --c_CLKS_PER_BIT: 16MHz/115200Baud ) port map ( i_clk => Clk, i_tx_dv => r_TX_DV, i_tx_byte => r_TX_BYTE, o_tx_active => open, o_tx_serial => out_serial_memory, o_tx_done => w_TX_DONE ); st: process (r_SM_serial,w_TX_DONE) begin case r_SM_Serial is when s_COMMAND => if (w_TX_Done = '1' ) then next_state <= S_BA; end if; when s_BA => if (w_TX_Done = '1' ) then next_state <= S_BB; end if; when s_BB => if (w_TX_Done = '1' ) then next_state <= S_start; end if; when others => next_state <= s_Start; end case; end process; ---------------------------------------- -- Output Logic ---------------------------------------- OUT_LOGIC: process (r_SM_Serial) begin case r_SM_Serial is when s_Command => UART_WRITE_BYTE(X"41"); when s_BA => UART_WRITE_BYTE(X"42"); when s_BB => UART_WRITE_BYTE(X"43"); when s_Start => r_TX_DV <= '0'; when others => r_TX_DV <= '0'; end case; end process;-- OUT_LOGIC; process (Clk,MSync) begin if msync = '1' then r_SM_serial <= s_command;   elsif rising_edge(CLK) and r_SM_serial /= s_start then r_SM_Serial <= NEXT_STATE; end if;

This does not work. This code transmits many characters together for each state and never stop .

Annotazione 2019-03-29 223952.jpg

 

Where am I wrong?

0 Kudos
3 Replies
Abe
Valued Contributor II
967 Views

Try out this code and see. Its a simple UART implementation..

-- Very simple, non-buffered implementation of 8 data bits, 0 parity, 1 stop bit -- serial communications channel. Should be able to work at any baud (with a -- degree of error) by setting I_clk_baud_count respectively: -- -- For a 50MHz I_clk: -- I_clk_baud_count := X"1458" -- 9600bps -- I_clk_baud_count := X"01B2" -- 115200bps -- -- To generate other timings, perform calculation: -- <I_clk in Hz> / <expected baud> = I_clk_baud_count -- 50000000 / 9600 = 5208 (0x1458) -- -- Inputs/Outputs: -- -- SYS: -- I_clk - system clock - at least 16x baud rate for recieve -- but can be less if only using TX. -- I_clk_baud_count - the number of cycles of I_clk between baud ticks -- used to set a known transmit/recieve baud rate. -- I_reset - reset line. ideally, reset whilst changing baud. -- -- TX: -- I_txData - data to transmit. -- I_txSig - signal to transmit (deassert when txReady low) or -- change I_txData to stream out. -- O_txRdy - '1' when idle, '0' when transmitting. -- O_tx - actual serial output. -- -- RX: -- I_rx - actual serial input. -- I_rxCont - receive enable/continue. -- O_rxData - data received. -- O_rxSig - data available signal - does not deassert until new -- frame starts being received. -- O_rxFrameError - Stop bit invalid/frame error. Deasserts on next receive, -- but the data received may still be invalid. --   library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL;   entity uart is Port ( I_clk : in STD_LOGIC; I_clk_baud_count : in STD_LOGIC_VECTOR (15 downto 0);   I_reset: in STD_LOGIC;   I_txData : in STD_LOGIC_VECTOR (7 downto 0); I_txSig : in STD_LOGIC; O_txRdy : out STD_LOGIC; O_tx : out STD_LOGIC;   I_rx : in STD_LOGIC; I_rxCont: in STD_LOGIC; O_rxData : out STD_LOGIC_VECTOR (7 downto 0); O_rxSig : out STD_LOGIC; O_rxFrameError : out STD_LOGIC   ); end uart;   architecture Behavioral of uart is signal tx_data : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); signal tx_state: integer := 0; signal tx_rdy : STD_LOGIC := '1'; signal tx: STD_LOGIC := '1'; signal rx_sample_count : integer := 0; signal rx_sample_offset : integer := 3; signal rx_state: integer := 0; signal rx_data : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); signal rx_sig : STD_LOGIC := '0'; signal rx_frameError : STD_LOGIC := '0'; signal rx_clk_counter : integer := 0; signal rx_clk_reset : STD_LOGIC := '0'; signal rx_clk_baud_tick: STD_LOGIC := '0'; signal tx_clk_counter : integer := 0; signal tx_clk : STD_LOGIC := '0'; constant OFFSET_START_BIT: integer := 7; constant OFFSET_DATA_BITS: integer := 15; constant OFFSET_STOP_BIT: integer := 7; begin   clk_gen: process (I_clk) begin if rising_edge(I_clk) then -- RX baud 'ticks' generated for sampling, with reset if rx_clk_counter = 0 then -- x16 sampled - so chop off 4 LSB rx_clk_counter <= to_integer(unsigned(I_clk_baud_count(15 downto 4))); rx_clk_baud_tick <= '1'; else if rx_clk_reset = '1' then rx_clk_counter <= to_integer(unsigned(I_clk_baud_count(15 downto 4))); else rx_clk_counter <= rx_clk_counter - 1; end if; rx_clk_baud_tick <= '0'; end if; -- TX standard baud clock, no reset if tx_clk_counter = 0 then -- chop off LSB to get a clock tx_clk_counter <= to_integer(unsigned(I_clk_baud_count(15 downto 1))); tx_clk <= not tx_clk; else tx_clk_counter <= tx_clk_counter - 1; end if; end if; end process; O_rxFrameError <= rx_frameError; O_rxSig <= rx_sig; rx_proc: process (I_clk, I_reset, I_rx, I_rxCont) begin -- RX runs off the system clock, and operates on baud 'ticks' if rising_edge(I_clk) then if rx_clk_reset = '1' then rx_clk_reset <= '0'; end if; if I_reset = '1' then rx_state <= 0; rx_sig <= '0'; rx_sample_count <= 0; rx_sample_offset <= OFFSET_START_BIT; rx_data <= X"00"; O_rxData <= X"00"; elsif I_rx = '0' and rx_state = 0 and I_rxCont = '1' then -- first encounter of falling edge start rx_state <= 1; -- start bit sample stage rx_sample_offset <= OFFSET_START_BIT; rx_sample_count <= 0; -- need to reset the baud tick clock to line up with the start -- bit leading edge. rx_clk_reset <= '1'; elsif rx_clk_baud_tick = '1' and I_rx = '0' and rx_state = 1 then -- inc sample count rx_sample_count <= rx_sample_count + 1; if rx_sample_count = rx_sample_offset then -- start bit sampled, time to enable data rx_sig <= '0'; rx_state <= 2; rx_data <= X"00"; rx_sample_offset <= OFFSET_DATA_BITS; rx_sample_count <= 0; end if; elsif rx_clk_baud_tick = '1' and rx_state >= 2 and rx_state < 10 then -- sampling data if rx_sample_count = rx_sample_offset then rx_data(6 downto 0) <= rx_data(7 downto 1); rx_data(7) <= I_rx; rx_sample_count <= 0; rx_state <= rx_state + 1; else rx_sample_count <= rx_sample_count + 1; end if; elsif rx_clk_baud_tick = '1' and rx_state = 10 then if rx_sample_count = OFFSET_STOP_BIT then rx_state <= 0; rx_sig <= '1'; O_rxData <= rx_data; -- latch data out if I_rx = '1' then -- stop bit correct rx_frameError <= '0'; else -- stop bit is always high, if we don't see it, there -- has been an issue. Signal an error. rx_frameError <= '1'; end if; else rx_sample_count <= rx_sample_count + 1; end if; end if; end if; end process;     O_tx <= tx; O_txRdy <= tx_rdy; tx_proc: process (tx_clk, I_reset, I_txSig, tx_state) begin -- TX runs off the TX baud clock if rising_edge(tx_clk) then if I_reset = '1' then tx_state <= 0; tx_data <= X"00"; tx_rdy <= '1'; tx <= '1'; else if tx_state = 0 and I_txSig = '1' then tx_state <= 1; tx_data <= I_txData; tx_rdy <= '0'; tx <= '0'; -- start bit elsif tx_state < 9 and tx_rdy = '0' then tx <= tx_data(0); tx_data <= '0' & tx_data (7 downto 1); tx_state <= tx_state + 1; elsif tx_state = 9 and tx_rdy = '0' then tx <= '1'; -- stop bit tx_rdy <= '1'; tx_state <= 0; end if; end if; end if; end process;   end Behavioral;

 

0 Kudos
CLa_R
Novice
967 Views

Thanks. Have you an example for use this UART?

0 Kudos
Ahmed_H_Intel1
Employee
967 Views
Hi Claudio, Please check the examples below: https://github.com/AntonZero/UART and watch this video for explanation: https://www.youtube.com/watch?v=fMmcSpgOtJ4 Regards,
0 Kudos
Reply