Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

RS232 command interpreter vhdl

Hello everyone, I came here in order to find any suggestion for the following issue.

I have a fpga custom board wich needs to make a task depending on the command received by a mcu or pc. For instance, the command <SW> followed by n bytes of data will change the frequency of a DDS system, and so on with other 4 bytes commands (4 ASCII chars). I already have my UART component workin and tested with the windows hyperterminal wich echos back every key pressed.

I tried with a 8bit shift left register and a counter in order to "concatenate" the command and later compare it in order to perform the correspondig action, but I just can't make it work. Does anyone already did something like that before?

the pseudo code is the following


...
architecture arch of myEntity is
signal RxReady : std_logic;
signal enableTx : std_logic;
signal cmd : std_logic_vector(31 downto 0) := (others => '0');
signal cmd_tmp : std_logic_vector(31 downto 0) := (others => '0');
signal tmp_data : std_logic_vector(7 downto 0) := (others => '0');
signal cont : integer range 0 to 4 := 0;
begin
u1 : UART port map (sysclk, sysrst, enableTx, TxD, TxData, RxD, tmp_data, RxReady);
process(sysrst, tmp_data, RxReady)
begin
if sysrst = '1' then
enableTx <= '0';
cmd <= (others => '0');
cmd_tmp <= (others => '0');
else
if RxReady = '1' then
if cont < 4 then
cont := cont + 1;
cmd_tmp <= cmd_tmp(23 downto 0) & tmd_data;
cmd <= cmd_tmp;
else
cont := 0;
end if;
else
end if;
end if;
end process;
process(cmd)
begin
-- just a Test, but not working, it only has the last char coming from the PC, i.e, a sequence 1234, should be 1234, but it is just 4444
if cmd = one&two&three&four then
outLEDS <= (others => '1');
else 
outLEDS <= (others => '0');
end if;
end process;
end architecture;
...

If anyone have a suggestion it will be really appreciated. Thanks in advance.

2 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    just my two cents...

    You have a mix-up of variable assignment (cont := cont+1) which takes place immediately and signal assignments " <= " which take place "once" the condition is met. Additionally you should synchronize the process for concatenating the command to sysclk rather using the outputflag of the UART process for stringent clock synchronous design...

    Additionally the cont variable increases to 4 (being pure combinatorical, not registered) with the RxReady being '1', not with the rising edge of RxReady indicating a new command being received.

    It may already solve the issue, if you define cont as a signal as well and rewrite the condition from "If RxReady = '1' " to "If Rising_Edge(RxReady)" to envoke these code lines only once for each time you get a new byte by the UART...

    Regards,

    Carlhermann
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello Carlhermann,

    First of all I want to thank you for your comments and suggestions :o. I was able to solve this issue, part of it was make changes like you suggested before.

    --- Quote Start ---

    ...Additionally you should synchronize the process for concatenating the command to sysclk rather using the outputflag of the UART process for stringent clock synchronous design...

    --- Quote End ---

    Also I built a FSM for handling the "commands", the code I sure could be improved a lot in order to be more "compact" or efficient; but at least it is working now.

    Here's the code

    
    ...
    -- Commands FSM
    process(sysrst, sysclk, txEnable, rxData)
    begin
    if sysrst = '0' then
    	txEnable	<=	'0';
    	txData	<=	(others => '0');
    	cmd_ctr	<=	0;
    	cmd_state	<=	IDLE;
    	commands	<=	(others => '0');
    elsif sysclk'event and sysclk = '1' then
    case cmd_state is
    	when	IDLE	=>	
    						txEnable	<=	'0';
    						txData	<=	(others	=> '0');
    						if rxReady = '1' then
    							cmd_state	<=	START_CMD;
    						else
    							cmd_state	<=	IDLE;
    							cmd_rdy	<=	'0';
    							cmd_ctr	<=	0;
    							commands	<=	(others => '0');
    						end if;
    	when START_CMD	=>
    		case cmd_ctr is
    			when 0	=>
    						commands	<=	commands(23 downto 0) & rxData;
    						cmd_ctr	<=	1;
    						cmd_state	<=	START_CMD;
    			when 1	=>
    						if rxReady = '1' then
    							commands	<=	commands(23 downto 0) & rxData;
    							cmd_ctr	<=	2;
    							cmd_state	<=	START_CMD;
    						end if;
    			when 2	=>	
    						if rxReady = '1' then
    							commands	<=	commands(23 downto 0) & rxData;
    							cmd_ctr	<=	3;
    							cmd_state	<=	START_CMD;
    						end if;
    			when 3	=>
    						if rxReady = '1' then
    							commands	<=	commands(23 downto 0) & rxData;
    							cmd_ctr	<=	0;
    							cmd_state	<=	WHICH_CMD;
    						end if;
    		end case;															
    	when WHICH_CMD	=>
    ...
    

    Thanks again for your support.

    Regards,

    Efel