Forum Discussion

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

Finite state machine - doesnt change state second time & glitch

I have a fairly simple state machine that when in idle state, if txval is high should take the data from input port, put txbus flag to 1, then write it to FT245 chip and when writing is finished and back in idle put txbus back to 0. Until txval is high. If txval was high when entering, it should take the data from input port and so on; or wait until input port data is high.

I am using this state machine from another one, and they share the same clocks. FT245 chip stuff is registered since it is async.

I have noticed 2 things:

In case txval goes high while still in write_end state, txbus drops to 0 and goes high again. I set txbus to 0 only and only in idle state. In all others is it 1.

In case one cycle of state changes is done, it does not go into another cycle of state changes if all conditions for it are satisfied, however it does take the data from input port.

In hardware - in serial terminal I can see this 1 byte being succesfully sent, but nothing else.

I am trying to debug this for quite some time now...but....

https://www.alteraforum.com/forum/attachment.php?attachmentid=8289 https://www.alteraforum.com/forum/attachment.php?attachmentid=8290

Code is:


LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY FT245 IS
  PORT(
      clk : IN std_logic;
        rstn : IN std_logic;
      txrdy : OUT std_logic;
        txval : IN std_logic;
        txdat : IN std_logic_vector(7 downto 0);
        txbus : OUT std_logic;
      -- FT2232 Bus Signals
        usb_data : inout std_logic_vector(7 downto 0);
        usb_rd_n : out std_logic;
        usb_wr   : out std_logic;        
        usb_rxf_n : in std_logic;
        usb_txe_n : in std_logic;
        d_state : out std_logic_vector(2 downto 0)
  );
END FT245;
ARCHITECTURE behv OF FT245 IS
constant CMDDELAY : integer := 10; -- 10*20ns for 50Mhz clock = 200ns    
    signal usb_input :  STD_LOGIC_VECTOR (7 DOWNTO 0);        
    signal usb_output_next: STD_LOGIC_VECTOR (7 DOWNTO 0);
    signal usb_output_reg :  STD_LOGIC_VECTOR (7 DOWNTO 0);        
    signal recv_data_reg  :  STD_LOGIC_VECTOR(7 DOWNTO 0);
    signal recv_data_next  :  STD_LOGIC_VECTOR(7 DOWNTO 0);
   signal rd_n_reg : STD_LOGIC;    -- Registered RD_N (to be written)
   signal rd_n_next : STD_LOGIC;   -- Next RD_N (to be registered)
   signal wr_reg : STD_LOGIC;      -- Registered WR (to be written)
   signal wr_next : STD_LOGIC;     -- Next WR (to be registered)
   signal rxf_reg : STD_LOGIC;     -- Status of RX_F flag
   signal txe_n_reg : STD_LOGIC;      -- Status of TXE_N flag
   signal oe_reg : STD_LOGIC;  -- For Bi-Di bus (to be written)
    signal oe_next : STD_LOGIC; -- For Bi-Di bus (next output enable state - to be registered)
    signal delay_reg : integer range 0 to CMDDELAY;        -- Delay counter (for start next state)
   signal delay_next: integer range 0 to CMDDELAY;        -- Delay counter (for start next state)
    
    -- Build an enumerated type for the state machine
    type state_type is (init, idle, write_prepare, write_strobe, write_end);
    
    -- Register to hold the current state
    signal state_now : state_type;
    signal state_next : state_type;
    
begin    
 --{------------------------------------------------------------------------------}
  --{ Params  : <CLK>  Clock
  --{           <RST>  Reset
  --{ Descript: State machine: State register
  --{           The state register is updated
  --{           Using synchronuous reset
  --{------------------------------------------------------------------------------}
  process (clk, rstn)
  begin
    if (rising_edge(clk)) then
      if (rstn = '0') then
        delay_reg <= 0;          
      else          
        if (delay_reg = 0) then
          state_now <= state_next;
          delay_reg <= delay_next;
        else
          delay_reg <= delay_reg - 1;
        end if;      
      end if;  
        
        IF(state_now = init) THEN 
           d_state <= "000";
        ELSIF(state_now = idle) THEN 
           d_state <= "001";
        ELSIF(state_now = write_prepare) THEN 
           d_state <= "010"; 
        ELSIF(state_now = write_strobe) THEN
           d_state <= "011";
        ELSIF(state_now = write_end) THEN 
           d_state <= "100";
        ELSE 
           d_state <= "111";
        END IF;
        
    end if;
  end process;
  --{------------------------------------------------------------------------------}
  --{ Params  : <CLK>  Clock
  --{ Descript: State machine: Output buffer
  --{           The output registers are updated
  --{------------------------------------------------------------------------------}
  process (clk)
  begin
    if (rising_edge(clk)) then
       rd_n_reg <= rd_n_next;  -- Register RD_N output
        wr_reg <= wr_next;      -- Register WR output
        rxf_reg <= usb_rxf_n;   -- Register RXF input
        txe_n_reg <= usb_txe_n; -- Register TXE_N input
        oe_reg <= oe_next;      -- Register Bi-Di OE flag              
        recv_data_reg <= recv_data_next;        
       usb_output_reg <= usb_output_next;    
              
    end if;
  end process;
  
  
 txrdy <= not txe_n_reg; -- assert txrdy when FIFO has space.  
  --{------------------------------------------------------------------------------}
  --{ Params  : <START>       Start flag
  --{           <RST>         Reset
  --{           <state_now>   Current state
  --{ Descript: State machine: Next state logic
  --{ Notes   : <delay_next> is the delay after the -next- state has been executed
  --{           and must be reset
  --{------------------------------------------------------------------------------}
  process (clk, rstn, state_now, txval, txdat, rd_n_reg, wr_reg, oe_reg, delay_reg, usb_output_reg, recv_data_reg, txe_n_reg)               
  begin
    if (rstn = '0') then
       rd_n_next <= '1';
        wr_next <= '0';
        oe_next <= '1'; -- default in output bus
        usb_output_next <= (others=>'0');
        recv_data_next <= (others=>'0');
      delay_next <= 0;
        state_next <= init;    
      txbus <= '1';        
    else     
       rd_n_next <= rd_n_reg;
        wr_next <= wr_reg;
        oe_next <= oe_reg;
        delay_next <= delay_reg;
        state_next <= state_now;
                
        usb_output_next <= usb_output_reg;
        recv_data_next <= recv_data_reg;        
        txbus <= '1';
        
      case state_now is
        when init   =>  
                                rd_n_next <= '1';
                                wr_next <= '0';
                                oe_next <= '1'; -- default in output bus
                                usb_output_next <= (others=>'0');
                                delay_next <= 0;                                                   
                        state_next <= idle;                
                               txbus <= '0';    
                                         
          when idle =>
                       delay_next <= 0;        
                     IF(txval = '0') THEN                                  
                                txbus <= '0';
                            ELSIF(txval = '1') THEN
                                state_next <= write_prepare;                               
                                usb_output_next <= txdat;
                                txbus <= '1';
                            END IF;
                            
          when write_prepare =>     
                          txbus <= '1';          
                      if(txe_n_reg = '0') then -- wait until TX fifo has space
                            oe_next <= '1';
                            delay_next <= 0;
                            state_next <= write_strobe;
                          end if;
        when write_strobe => 
                          txbus <= '1';
                    wr_next <= '1';
                        delay_next <= CMDDELAY;                          
                        state_next <= write_end;
          when write_end =>                       
                      txbus <= '1';
                    wr_next <= '0';
                          delay_next <= CMDDELAY;                          
                          state_next <= idle;        
          when others => 
                      rd_n_next <= rd_n_reg;
                          wr_next <= wr_reg;
                          oe_next <= oe_reg;
                          state_next <= init;  
                          delay_next <= 0;
                          txbus <= '0';
      end case;
    end if;
end process;
    
    
 --{------------------------------------------------------------------------------}
  --{ Descript: Output
  --{           The actual outputs are set
  --{------------------------------------------------------------------------------}
  usb_rd_n <= rd_n_reg;
  usb_wr   <= wr_reg;      
  usb_data <= usb_output_reg when oe_reg = '1' else (others => 'Z');
  usb_input <= usb_data when oe_reg = '0';     
 
  
END behv;

13 Replies