Forum Discussion

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

Weird State Machine issue

Thanks in advance for all suggestions...

I have wrote a program to test a FTDI 2232H chip with a Cyclone 3 (EP3C25F324C6).

The program is a simple STM, triggerd by a 60MHz clock of the FTDI chip (FT245 Asynchronous mode) with 3 steps : Idle /read from PC / write to PC.

The program works perfectly and I will post the source code below.

BUT there is a strange issue with the STM

Working version => idle -> read -> write -> read ->write -> .........

Not working version => idle -> read -> write -> idle -> read -> write -> idle ->......

The strange thing for me as unexperienced VHDL coder is dat when I use the idle step even only to jump to the read step the program doesn't work no more.

Can some one help me to clarify the problem and give me some good coding tips to prevent these strange isues ?

All suggestions are welcome

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FTDI_Interface is 
port(
	
	button_A		: in std_logic;		
	button_B		: in std_logic;	
	button_C		: in std_logic;	
	button_D		: in std_logic;	
	-- Connection to FTDI (FT245 COnfiguration)	
	FTDI_RXF_n			: in std_logic;		-- When low -> there is Data availible in the fifo
	FTDI_TXE_n			: in std_logic;		-- When low -> Data can be written into the fifo
	FTDI_RD_n			: out std_logic;		-- When low (and RXF_n low)-> Data is clocked to D0..D7 to receive 
	FTDI_WR_n			: out std_logic;		-- When low (and TXF_n low)-> Data is written to transmit FIFO
	FTDI_OE_n			: out std_logic;		-- Output enable -> Should be low one clock to drive data onto D0..D7	
	FTDI_Data		        : inout std_logic_vector(7 downto 0);	-- Data vector
	
	-- Other Connections:
	CLK_FTDI		: in std_logic;		-- 60 MHz clock driven by FDTI
	Reset_n		: in std_logic;		-- reset input	
	
	-- The Outputs for the leds
	D_Readed		: out std_logic_vector(7 downto 0);	
	);
end FTDI_Interface;
architecture RTL of FTDI_Interface is
-- Create state machine cases
type T_STM_MAIN 	is (Step_Idle,Step_Read,Step_Write);
type T_STM_RD 		is (rd_idle, do_OE, do_RD, read_data, rd_hold);
type T_STM_WR 		is (wr_idle, do_WR, burst_write, pause_wr, slow_wr);
type T_STM_bytes	is (byte0, byte1 , byte2, byte3);
signal STM_MAIN_CURR		: T_STM_MAIN;
signal STM_RD			: T_STM_RD;
signal STM_WR			: T_STM_WR;
signal data_to_PC : std_logic_vector (7 downto 0);
signal byte_cnt_write   : integer range 0 to 1000000;
begin
	
	--# EXECUTE EACH CLOCK PULS	
	process(CLK_FTDI)
	
	begin
			if(Reset_n = '0') then	
				STM_MAIN_CURR <= Step_Idle;			
			elsif (rising_edge(CLK_FTDI)) then 
			-- This is the state machine to controll everything flow-wise.			
			case STM_MAIN_CURR is	
				--#  do nothing and wait on command
				when Step_Idle =>
--**************************** NO CONTENT BUT JUST A JUMP TO NEXT STEP ****************************
					STM_MAIN_CURR<=	Step_Read;  
--************************************** ****************************************************** 
				
				--#  Start sequence of setting flags to read from the FTDI		
				when Step_Read =>					
					-- Here we wait for a command to come through the FTDI
					FTDI_WR_n <= '1';
					-- Init the write STM to idle state
					STM_WR <= wr_idle;
					-- Evaluate the read STM.
					case STM_RD is
						--# # READ IDLE : initialize variables
						when rd_idle =>
							FTDI_OE_n <=  '1';
							FTDI_RD_n <=  '1';		
							FTDI_Data <= (others => 'Z');
							D_Readed <= (others => '0');
							-- If FTDI pulls RXF low then data is available. We need to do OE next.
							if(FTDI_RXF_n = '0') then
								STM_RD <= do_OE;
							end if;
						--## OUTPUT ENABLE : enable to start reading 	
						when do_OE =>
							-- Set output enable one clock pulse before reading command 
							FTDI_OE_n <= '0';
							STM_RD <= do_RD;
						
						--## READ FLAG : Pull RD_n low and go to read state 
						when do_RD =>   
							FTDI_RD_n <= '0';
							STM_RD <= read_data;
						
						--## READING : read until FTDI stops
						when read_data =>
							-- Finish read operation ?
							if(FTDI_RXF_n = '1') then														
								-- reset FT245 signals
								FTDI_OE_n <=  '0';
								FTDI_RD_n <=  '1';													
								STM_RD <= rd_idle;	
							-- ***** TESTING directly to write -----	
								STM_MAIN_CURR <= Step_Write;		
							else
								-- *** Here data is comming @ 60MHz ***
								D_Readed <= FTDI_Data;
							end if;
						when others =>
					end case;				
			
				
		
				--#  Start sequence of setting flags to write to the FTDI			
				when Step_Write =>	
					DAV<='0';
					--State_DONE<='0';
					case STM_WR is
					
						--## WRITE IDLE : prepare flags of FTDI and RAM
						when wr_idle =>
							FTDI_OE_n<='1';
							--If FTDI_TXE_n is 0, then FTDI will allow data to be transmitted 
							if(FTDI_TXE_n =not '0') then
								STM_WR <= do_WR;
							end if;
							byte_cnt_write <= 0;
							--ram_addr_int <=Ram_addr_start;
							--Ram_Addr <=(others => '0');
							--Ram_nCE <= not '1';	
							FTDI_WR_n <= '1';		
						
						--## WRITE START: start write command to FTDI
						when do_WR =>
							-- Go to the burst_write state, reset RAM adress, and enable RAM data output
							--Ram_nOE <='0';
							--Ram_Addr <=(others => '0');
							--Ram_Data <=(others => '0');
							FTDI_WR_n <= '0';		-- Enables the data byte on the D0...D7 pins to be written into the transmit FIFO buffer
							STM_WR <= burst_write;
							
						when burst_write =>
							-- If FTDI_TXE_n is asserted, FTDI does not want data anymore, so we pause XMIT:
							if(FTDI_TXE_n = not '1') then 
								STM_WR <= pause_wr;
								FTDI_WR_n <= '1';	-- Disable write enable
								test<='0';
								
							-- We want to write "n_sps_meas_int samples/channel * 32 channels * 2 bytes/sample" bytes	
							elsif(byte_cnt_write <4) then
								test<='1';
								data_to_PC <= (others => '0');
								data_to_PC(0)<=not button_A;		
								data_to_PC(1)<=not button_B;			
								data_to_PC(2)<=not button_C;	
								data_to_PC(3)<=not button_D;						
								FTDI_Data <= data_to_PC;		
																	
								byte_cnt_write <= byte_cnt_write + 1;
								
								-- Slow down the write operation to FTDI, the RAM is to slow...
								STM_WR <= slow_wr;
								FTDI_WR_n <= '1';	-- disable writing
								
							else
								-- We have written enough bytes, clean up the FSMs and ram signals
								STM_WR <= wr_idle;
								FTDI_WR_n <= '1';	-- disable writing
--*********************************************WORKING VERSION ******************************************
								STM_MAIN_CURR <= Step_Read;		
--*****************************************************************************************************
--*********************************************FAILING VERSION ******************************************
--								STM_MAIN_CURR <= Step_Idle;		
--*****************************************************************************************************					
							end if;
							
						--## DELAY with 1 cycle: ram is slower than FTDI
						when slow_wr =>
							STM_WR <= burst_write;
							FTDI_WR_n <= '0';		-- enable writing again
							
						--# # PAUSE : FTDI chip needs a break...	
						when pause_wr =>
							if(FTDI_TXE_n = '0') then
								STM_WR <= burst_write;
								FTDI_WR_n <= '0';	-- enable writing again
							end if;
						when others =>
					end case;	
				
				when others =>	
			end case;
	end if;
	end process;	
end RTL;
		

FYI: the code in C to talk to the FTDI chip is attached

5 Replies

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

    Have you written a testbench for this?

    I also notice you missed the reset from the main process (will be important when testing).

    I assume the failure is due to the extra pipeline delay when the extra idle state occurs. Is this acceptable in the design?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I've not looked over either your VHDL or C code but would only point out that the FT2232H may not be behaving exactly as advertised. In particular the Linux driver had some problems when I used the chip some years ago and the FIFO signals had some unexpected glitches on them. The Windows driver seemed to work fine.

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

    --- Quote Start ---

    Have you written a testbench for this?

    I also notice you missed the reset from the main process (will be important when testing).

    I assume the failure is due to the extra pipeline delay when the extra idle state occurs. Is this acceptable in the design?

    --- Quote End ---

    I didn't write a testbench for this application. But what do you mean with a reset from the main process? I implemented a startup condition:

    if(Reset_n = '0') then	
    	STM_MAIN_CURR <= Step_Idle;

    An extra delay is acceptable. In the future I want to add some logic in the extra IDLE step. This IDLE step will decide to jump to the READ or WRITE step based on external input. When read or write operation is finished the STM has to jump back to IDLE and later when an external read/write signal is set the logic in the IDLE step should start a new read or write process.

    Thanks for the replies
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    As it's an async reset, then it needs to be in the sensitivity list to behave correctly in a simulation.

    I highly suggest you write a testbench. It will save you the hours and hours you can waste dubugging on hardware.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    As it's an async reset, then it needs to be in the sensitivity list to behave correctly in a simulation.

    I highly suggest you write a testbench. It will save you the hours and hours you can waste dubugging on hardware.

    --- Quote End ---

    I struggled with making a proper test-bench but now it is up and running and indeed it is super handy.

    I noticed that there occurs a problem with the state machine when some parameters are not proper initialized.

    I will search further to solve my problem and will post my result.

    For other starters, I found that there is more than one solutions to setup a Simulation.

    This tutorial helped me a lot and gave the fastest and most flexible Simulation.

    http://edg.uchicago.edu/software/altera/quartus_tutorial/