- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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 .
Where am I wrong?
Link Copied
3 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. Have you an example for use this UART?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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,
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page