Forum Discussion

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

Trying to get State Machine to Stop Glitching

Currently I am developing a sequencer that every 16 clock ticks one of the tx enables are high while the rx enables are kept high all the time. My state machine is working occasionally although I have sudden glitches in it which causes for my code to go off course. I have attached the signal scope of this to the forum post. Does anyone have an idea of what could have caused this?

http://www.alteraforum.com/forum/attachment.php?attachmentid=11082&stc=1

code

LIBRARY IEEE;

USE IEEE.std_logic_1164.ALL;

USE IEEE.std_logic_textio.ALL;

USE IEEE.numeric_bit.ALL;

USE IEEE.numeric_std.ALL;

LIBRARY STD;

USE STD.textio;

ENTITY TOP IS

GENERIC (txNum : INTEGER := 5);

PORT (

clkrx : IN std_logic;

txen_1 : OUT std_logic;

txen_2 : OUT std_logic;

txen_3 : OUT std_logic;

txen_4 : OUT std_logic;

txen_5 : OUT std_logic;

rxen_1 : OUT std_logic;

rxen_2 : OUT std_logic;

rxen_3 : OUT std_logic;

rxen_4 : OUT std_logic;

rxen_5 : OUT std_logic;

clkout : OUT std_logic

);

END TOP;

ARCHITECTURE behavioral OF TOP IS

CONSTANT s0 : STD_LOGIC_vector(2 DOWNTO 0) := "000";

CONSTANT s1 : STD_LOGIC_vector(2 DOWNTO 0) := "001";

CONSTANT s2 : STD_LOGIC_vector(2 DOWNTO 0) := "010";

CONSTANT s3 : STD_LOGIC_vector(2 DOWNTO 0) := "011";

CONSTANT s4 : STD_LOGIC_vector(2 DOWNTO 0) := "100";

CONSTANT s5 : STD_LOGIC_vector(2 DOWNTO 0) := "101";

SIGNAL current_s : STD_LOGIC_vector(2 DOWNTO 0) := s5;

--current and next state declaration.

SIGNAL next_s : STD_LOGIC_vector(2 DOWNTO 0) := s0;

SIGNAL cnt : INTEGER RANGE 0 TO 16 := 0;

SIGNAL p : BOOLEAN := false;

BEGIN

PROCESS (clkrx)

BEGIN

IF (rising_edge(clkrx)) THEN

IF (cnt = 0) THEN

current_s <= next_s;

cnt <= cnt + 1;

p <= true;

ELSIF (cnt = 16) THEN

current_s <= next_s;

cnt <= cnt + 2;

ELSE

cnt <= cnt + 1;

END IF;

END IF;

END PROCESS;

PROCESS (clkrx, current_s, p)

BEGIN

IF (p) THEN

clkout <= clkrx;

END IF;

END PROCESS;

--state machine process.

PROCESS (current_s)

BEGIN

CASE current_s IS

WHEN s0 => --when current state is "s0"

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

rxen_4 <= '1';

rxen_5 <= '1';

txen_1 <= '1';

txen_2 <= '0';

txen_3 <= '0';

txen_4 <= '0';

txen_5 <= '0';

IF (txNum = 1) THEN

next_s <= s0;

ELSE

next_s <= s1;

END IF;

WHEN s1 => --when current state is "s1"

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

txen_1 <= '0';

txen_2 <= '1';

txen_3 <= '0';

txen_4 <= '0';

txen_5 <= '0';

IF (txNum = 2) THEN

next_s <= s0;

ELSE

next_s <= s2;

END IF;

WHEN s2 => --when current state is "s2"

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

rxen_4 <= '1';

rxen_5 <= '1';

txen_1 <= '0';

txen_2 <= '0';

txen_3 <= '1';

txen_4 <= '0';

txen_5 <= '0';

IF (txNum = 3) THEN

next_s <= s0;

ELSE

next_s <= s3;

END IF;

WHEN s3 => --when current state is "s3"

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

rxen_4 <= '1';

rxen_5 <= '1';

txen_1 <= '0';

txen_2 <= '0';

txen_3 <= '0';

txen_4 <= '1';

txen_5 <= '0';

IF (txNum = 4) THEN

next_s <= s0;

ELSE

next_s <= s4;

END IF;

WHEN s4 =>

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

rxen_4 <= '1';

rxen_5 <= '1';

txen_1 <= '0';

txen_2 <= '0';

txen_3 <= '0';

txen_4 <= '0';

txen_5 <= '1';

next_s <= s0;

WHEN OTHERS =>

rxen_1 <= '1';

rxen_2 <= '1';

rxen_3 <= '1';

rxen_4 <= '1';

rxen_5 <= '1';

txen_1 <= '1';

txen_2 <= '0';

txen_3 <= '0';

txen_4 <= '0';

txen_5 <= '0';

next_s <= s0;

END CASE;

END PROCESS;

END behavioral;

4 Replies

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

    I'm not sure what's causing the problem, but you have a bug in your counter code:

    SIGNAL cnt : INTEGER RANGE 0 TO 16 := 0;
    PROCESS (clkrx)
    BEGIN
      IF (rising_edge(clkrx)) THEN
        IF (cnt = 0) THEN
          current_s <= next_s;
          cnt <= cnt + 1;
          p <= true;
        ELSIF (cnt = 16) THEN
          current_s <= next_s;
          cnt <= cnt + 2;
        ELSE
          cnt <= cnt + 1;
        END IF;
      END IF;
    END PROCESS;
    
    You are defining a range from 0 to 16, but when you reach 16 you still increase the counter, getting out of range. This kind of behaviour is undefined in VHDL (and will cause an error in a simulator). I'm not sure what Quartus synthesizes in this case, but it's quite possible that it's an +1 adder that works fine with numbers from 0 to 16 and gives strange results for other values.

    Try this instead:

    SIGNAL cnt : INTEGER RANGE 0 TO 15 := 0;
    PROCESS (clkrx)
    BEGIN
      IF (rising_edge(clkrx)) THEN
        IF (cnt = 0) THEN
          current_s <= next_s;
          cnt <= cnt + 1;
          p <= true;
        ELSIF (cnt = 15) THEN
          cnt <= 0;
        ELSE
          cnt <= cnt + 1;
        END IF;
      END IF;
    END PROCESS;
    It will synthesize as a regular adder, and uses one bit less.

    Which clock frequency are you using for this design? Did you constrain your project for Timequest?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    There are some issues with this code:

    The rxen_x and txen_x signals are not all assigned in every state - this is going to form latches that could cause odd timing problems,. With an asynchronous process ALL signals must be assigned in ALL starts to prevent the formation of latches.The easy way around this is to assign each signal a default (including next_s) before the case statement. This gives each signal a value should it not be assigned somewhere else (it also must be an explicit value, not itself - that is a latch).

    Where does clkrx come from?

    Why is clkout assigned from clkrx based on p? p is true after the first clock. Routing clocks like this is a really bad idea. Apart from latching the clock (which is a bad idea), when you simulate the design, clkout is going to be 1 delta behind clkrx, which is going to do some odd things in your simulation and you probably wont have a clue whats going on. Moral of the story - use the same clock everywhere, dont use assigned versions.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I began to rewrite the code to get rid of some of the unnecessary factors mentioned above and developed this code bellow. Even after doing all that my code still glitches.

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

    library IEEE;

    use IEEE.std_logic_1164.all;

    use IEEE.std_logic_textio.all;

    use IEEE.std_logic_unsigned.all;

    library STD;

    use STD.textio;

    ENTITY state_machine IS

    generic(txNum:integer:=5);

    PORT(

    clk : IN STD_LOGIC;

    reset : IN STD_LOGIC;

    txen_1 : out std_logic;

    txen_2 : out std_logic;

    txen_3 : out std_logic;

    txen_4 : out std_logic;

    txen_5 : out std_logic;

    rxen_1 : out std_logic;

    rxen_2 : out std_logic;

    rxen_3 : out std_logic;

    rxen_4 : out std_logic;

    rxen_5 : out std_logic);

    END state_machine;

    ARCHITECTURE a OF state_machine IS

    constant s0:STD_LOGIC_vector(2 downto 0):="000";

    constant s1:STD_LOGIC_vector(2 downto 0):="001";

    constant s2:STD_LOGIC_vector(2 downto 0):="010";

    constant s3:STD_LOGIC_vector(2 downto 0):="011";

    constant s4:STD_LOGIC_vector(2 downto 0):="100";

    constant s5:STD_LOGIC_vector(2 downto 0):="101";

    signal state: STD_LOGIC_vector(2 downto 0):=s0;

    signal cnt:STD_LOGIC_VECTOR(3 DOWNTO 0):="0000";

    BEGIN

    process(clk)

    begin

    if(rising_edge(clk))then

    cnt<=cnt+1;

    end if;

    end process;

    PROCESS (clk,reset)

    BEGIN

    IF reset = '1' THEN

    state <= s0;

    ELSIF (rising_edge(clk)) THEN

    CASE state IS

    WHEN s0=>

    state <= s1;

    WHEN s1=>

    if(cnt="1111")then

    if(txNum=1)then

    state <= s1;

    else

    state <= s2;

    end if;

    else

    state <= s1;

    end if;

    WHEN s2=>

    if(cnt="1111")then

    if(txNum=2)then

    state <= s1;

    else

    state <= s3;

    end if;

    else

    state <= s2;

    end if;

    WHEN s3=>

    if(cnt="1111")then

    if(txNum=3)then

    state <= s1;

    else

    state <= s4;

    end if;

    else

    state <= s3;

    end if;

    WHEN s4=>

    if(cnt="1111")then

    if(txNum=4)then

    state <= s1;

    else

    state <= s5;

    end if;

    else

    state <= s4;

    end if;

    WHEN s5=>

    if(cnt="1111")then

    state <= s1;

    end if;

    when others=>

    state<=s1;

    END CASE;

    END IF;

    END PROCESS;

    PROCESS (state)

    BEGIN

    rxen_1<='1';

    rxen_2<='1';

    rxen_3<='1';

    rxen_4<='1';

    rxen_5<='1';

    CASE state IS

    WHEN s0 =>

    txen_1<='0';

    txen_2<='0';

    txen_3<='0';

    txen_4<='0';

    txen_5<='0';

    WHEN s1 =>

    txen_1<='1';

    txen_2<='0';

    txen_3<='0';

    txen_4<='0';

    txen_5<='0';

    WHEN s2 =>

    txen_1<='0';

    txen_2<='1';

    txen_3<='0';

    txen_4<='0';

    txen_5<='0';

    when s3=>

    txen_1<='0';

    txen_2<='0';

    txen_3<='1';

    txen_4<='0';

    txen_5<='0';

    when s4=>

    txen_1<='0';

    txen_2<='0';

    txen_3<='0';

    txen_4<='1';

    txen_5<='0';

    when s5=>

    txen_1<='0';

    txen_2<='0';

    txen_3<='0';

    txen_4<='0';

    txen_5<='1';

    when others=>

    txen_1<='1';

    txen_2<='0';

    txen_3<='0';

    txen_4<='0';

    txen_5<='0';

    END CASE;

    END PROCESS;

    END a;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    These are not glitches, these are functions of your code. Glitches are when you get small changes in signal usually less than 1 clock period due to analogue signal operations.

    Here, you have problems because of bugs in your code. You need to write a testbench to debug the design without going on to hardware.