Altera_Forum
Honored Contributor
14 years agoVHDL 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;