Altera_Forum
Honored Contributor
12 years agoFinite 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;