Altera_Forum
Honored Contributor
12 years agoWeird 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 welcomelibrary 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