Forum Discussion

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

VHDL State Machine: Bad State Transitions

Hi, I'm really hoping someone can help me as I'm at my wits end. I am running into a scenario where my state machine is transitioning into an invalid state. As far as I can tell, all of my paths between states are covered, but I must be doing something wrong. The states are setup to use one-hot encoding, btw.

Here's the some VHDL that reproduces the problem. It basically reads data from a FIFO and tries to write it to USB. After running for some period of time (which varies), the "packet_state" value becomes 0x00 (an invalid state value).

I've also attached a SignalTap screenshot showing the transition. I just can't understand why it happens.

Any ideas or suggestions?

Thanks!

 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity USB_IO is
 port
 (
  -- General --
  main_clk:    in  std_logic;        -- Primary clock: 50 Mhz
 
  -- Reset --
  reset_n:     in  std_logic := '0';
 
  -- USB TX FIFO --
  fifo_usb_tx_bus:  in  std_logic_vector(23 downto 0);
  fifo_usb_tx_empty: in  std_logic := '0';
  fifo_usb_tx_rd:  out std_logic := '0';  
  fifo_usb_tx_clr:  out std_logic := '0';
 
  -- FTDI FT2232 USB I/O --
  ftdi_usb_txe_n:  in  std_logic := '0';      
  ftdi_usb_rxf_n:  in  std_logic := '1';      
  ftdi_usb_bus:   inout std_logic_vector(7 downto 0);  
  ftdi_usb_wr_n:   buffer std_logic := '1';     
  ftdi_usb_rd_n:   buffer std_logic := '1'      
 );
end USB_IO;
 
architecture rtl of USB_IO is
 
-- Create separate in and out signals for  the bidir port 'ftdi_usb_bus'.
signal ftdi_usb_bus_in  : std_logic_vector(7 downto 0) := "00000000";
signal ftdi_usb_bus_out : std_logic_vector(7 downto 0) := "00000000";
 
attribute syn_encoding : string;
 
type usb_io_state_type is (usb_io_idle, usb_io_tx, usb_io_rx);
attribute syn_encoding of usb_io_state_type : type is "onehot";
 
signal usb_io_state : usb_io_state_type := usb_io_idle;
 
type packet_state_type is (
 S1, 
 S2, 
 S3, 
 S4, 
 S5, 
 S6, 
 S7, 
 S8
);
 
attribute syn_encoding of packet_state_type : type is "onehot";
signal packet_state : packet_state_type := S1;
 
begin
 
-- Infer tri-state buffers for our bidirectional pins.
ftdi_usb_bus <= ftdi_usb_bus_out when ftdi_usb_rd_n = '1' else "ZZZZZZZZ";
ftdi_usb_bus_in <= ftdi_usb_bus;
 
 process(main_clk) 
 begin
 
  if(rising_edge(main_clk)) then
 
   -- Default our outputs.
   fifo_usb_tx_clr <= '0';
   fifo_usb_tx_rd <= '0';
   ftdi_usb_wr_n <= '1';
   ftdi_usb_rd_n <= '1';
 
   if(reset_n = '0') then
    usb_io_state <= usb_io_idle;
    packet_state <= S1;
    fifo_usb_tx_clr <= '1';
   else
 
    case usb_io_state is
     when usb_io_idle =>
 
      packet_state <= S1;
 
      -- Look for incoming data first; then outgoing.
      if(ftdi_usb_rxf_n = '0') then
       usb_io_state <= usb_io_rx;
      elsif(fifo_usb_tx_empty = '0') then
       fifo_usb_tx_rd <= '1';
       usb_io_state <= usb_io_tx;
      else
       usb_io_state <= usb_io_idle;
      end if;
 
     when usb_io_tx =>
 
      if(ftdi_usb_txe_n = '0') then
 
       case packet_state is
        when S1 => 
         ftdi_usb_bus_out <= X"AA";
         packet_state <= S2;
        when S2 =>
         ftdi_usb_bus_out <= X"AA";
         ftdi_usb_wr_n <= '0';
         packet_state <= S3;
        when S3 => 
         ftdi_usb_bus_out <= fifo_usb_tx_bus(23 downto 16);
         packet_state <= S4;
        when S4 =>
         ftdi_usb_bus_out <= fifo_usb_tx_bus(23 downto 16);
         ftdi_usb_wr_n <= '0';
         packet_state <= S5;
        when S5 =>
         ftdi_usb_bus_out <= fifo_usb_tx_bus(15 downto 8);
         packet_state <= S6;
        when S6 =>
         ftdi_usb_bus_out <= fifo_usb_tx_bus(15 downto 8);
         ftdi_usb_wr_n <= '0';
         packet_state <= S7;
        when S7 =>
         ftdi_usb_bus_out <= fifo_usb_tx_bus(7 downto 0);
         packet_state <= S8;        
        when S8 =>
         ftdi_usb_bus_out <= fifo_usb_tx_bus(7 downto 0);
         ftdi_usb_wr_n <= '0';
         packet_state <= S1;
         usb_io_state <= usb_io_idle;
        when others =>
         ftdi_usb_wr_n <= '1';
         packet_state <= S1;
         usb_io_state <= usb_io_idle;
       end case;
 
      end if;
 
     when usb_io_rx =>
 
      -- Not yet implemented --
      usb_io_state <= usb_io_idle;
      packet_state <= S1;
    end case;
 
   end if; -- reset
 
  end if; -- rising_edge
 
 end process USB_IO_Handler;
 
end architecture rtl;

5 Replies

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

    Sorry to reply to my own post, but I just saw a similar thread which suggests that the bad state could be related to timing (perhaps with the ftdi_usb_txe_n input?).

    I'm trying to use the FTDI FT2232 USB chip in asynchronous mode. That may be the source of all of my problems....
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    If the incoming signals are asynchrnous, I suggest you synchronise them to the "main_clk" before trying to use them. Without doing that, you will be violating setup and hold times, and any signals that read them may become meta-stable.

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

    Metastability isn't required to get illegal states. Routing delay skew is sufficient, causing 99.9% (or so) of unexpected logic behaviour with timing violations. Synchronizing is the solution anyway.

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

    change your clk to 24Mhz and use this (LMK if it helps):

    -- ft2232d_fifo generation

    library ieee;

    use ieee.std_logic_1164.all;

    use ieee.numeric_std.all;

    use ieee.std_logic_unsigned.all;

    entity ft2232d_fifo is

    port (

    clkin : in std_logic; -- 24 MHZ clock from oscillator

    resetn : in std_logic; -- global reset to reset everything

    usbtxen : in std_logic; -- TX FIFO empty (low means data can go into FIFO)

    usbrxfn : in std_logic; -- RX FIFO full (low means data can be read from FIFO)

    readfifodata : in std_logic; -- Read Enable

    writefifo : in std_logic; -- Write Enable

    usbrdn : out std_logic; -- strobe low-then-high to get data from FIFO

    usbwr : out std_logic; -- strobe high-then-low to write data into FIFO

    usbd : inout std_logic_vector(7 downto 0); -- bi-directional data bus to FIFO chip

    data_read : out std_logic_vector(7 downto 0); -- bi-directional data bus to FIFO chip

    data_write : in std_logic_vector(7 downto 0) -- bi-directional data bus to FIFO chip

    );

    end ft2232d_fifo;

    -------------------------------------------------------------

    architecture rtl of ft2232d_fifo is

    type USB_STATE_TYPE is (USBIDLE,USBGETBYTE,USBSAVEBYTE,

    USBRDDN,USBPUTBYTE,USBWOUT,

    USBWHLD);

    --signal USBState : std_logic_vector(4 downto 0);

    --signal USBIDLE : std_logic_vector(4 downto 0) := "00000";

    --signal USBGETBYTE : std_logic_vector(4 downto 0) := "00001";

    --signal USBSAVEBYTE : std_logic_vector(4 downto 0) := "10001";

    --signal USBRDDN : std_logic_vector(4 downto 0) := "01000";

    --signal USBPUTBYTE : std_logic_vector(4 downto 0) := "00010";

    --signal USBWOUT : std_logic_vector(4 downto 0) := "00110";

    --signal USBWHLD : std_logic_vector(4 downto 0) := "01100";

    signal USBState : USB_STATE_TYPE;

    signal iswrite : std_logic;

    signal usbdone : std_logic;

    begin

    --usbrdn <= NOT USBState(0);

    --usbwr <= USBState(1);

    --iswrite <= USBState(2);

    --usbdone <= USBState(3);

    usb_rx_tx: process (resetn,clkin)

    begin

    if (resetn = '0') then

    USBState <= USBIDLE;

    usbrdn <= '1';

    usbwr <= '0';

    iswrite <= '0';

    usbdone <= '0';

    data_read <= (others => '0');

    elsif (rising_edge(clkin)) then

    case USBState is

    when USBIDLE =>

    usbrdn <= '1';

    usbwr <= '0';

    iswrite <= '0';

    usbdone <= '0';

    if(readfifodata = '1' AND usbrxfn = '0') then

    USBState <= USBGETBYTE;

    elsif(writefifo = '1' AND usbtxen = '0') then

    USBState <= USBPUTBYTE;

    else

    USBState <= USBIDLE;

    end if;

    when USBGETBYTE =>

    usbwr <= '0';

    iswrite <= '0';

    usbdone <= '0';

    usbrdn <= '0';

    USBState <= USBSAVEBYTE;

    when USBSAVEBYTE =>

    usbwr <= '0';

    iswrite <= '0';

    usbdone <= '0';

    usbrdn <= '0';

    if(readfifodata = '1')then

    data_read <= usbd;

    end if;

    USBState <= USBRDDN;

    when USBRDDN =>

    usbrdn <= '1';

    usbwr <= '0';

    iswrite <= '0';

    usbdone <= '1';

    if(readfifodata = '0' AND writefifo = '0')then

    USBState <= USBIDLE;

    end if;

    when USBPUTBYTE =>

    usbrdn <= '1';

    usbwr <= '1';

    iswrite <= '0';

    usbdone <= '0';

    USBState <= USBWOUT;

    when USBWOUT =>

    usbrdn <= '1';

    usbwr <= '1';

    iswrite <= '1';

    usbdone <= '0';

    USBState <= USBWHLD;

    when USBWHLD =>

    usbrdn <= '1';

    usbwr <= '0';

    iswrite <= '1';

    usbdone <= '1';

    if(readfifodata = '0' AND writefifo = '0')then

    USBState <= USBIDLE;

    end if;

    end case;

    end if;

    end process usb_rx_tx;

    usbd <= data_write when (iswrite) = '1' else "ZZZZZZZZ";

    end rtl;

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

    Using FT2232 in asynchronous mode with 24 MHz clock frequency does not solve the problem addressed in post# 2 to# 4. Synchroniszation is still required as long as FTDI internal and FPGA clock ar unrelated.