Search code examples
vhdlfreezestate-machine

VHDL simulation hangs even though it shows no error


I'm new to VHDL language and right now I'm trying to make a controlable stepper motor. It should be something like this (I actually got this picture from my code with Tina)

And this is my code:

LIBRARY ieee;                
USE ieee.std_logic_1164.ALL;            
USE ieee.std_logic_signed.ALL;         
ENTITY state_stepper_halfstep IS         
PORT(clk, plus, minus, start: IN    STD_LOGIC;
     q0,q1,q2,q3: OUT STD_LOGIC;
         a7,b7,c7,d7,e7,f7,g7,h7: OUT std_logic);
END state_stepper_halfstep;

ARCHITECTURE arc OF state_stepper_halfstep IS
    TYPE state_type IS (s0, s1, s2, s3, s4, s5, s6, s7);
    SIGNAL state: state_type;
        SIGNAL q: STD_LOGIC_VECTOR(3 downto 0);
        SIGNAL counter: integer range 0 to 21 :=11;
        SIGNAL digit: std_logic_vector (7 downto 0);
BEGIN

PROCESS (plus, minus, start, clk)
BEGIN 

IF rising_edge(plus) THEN  --  + Rotation value
    counter <= counter+1;
    IF counter > 20 THEN
        counter <= 20;
    END IF; 

ELSIF rising_edge(minus) THEN  --  - Rotation Value
    counter <= counter-1;
    IF counter < 2 THEN
        counter <= 2;
    END IF;
END IF;

    IF start = '1' THEN
        IF counter > 11 THEN  -- When value > 0
            WHILE counter > 11 LOOP  -- Clockwise looping
                EXIT WHEN counter = 11;
                IF rising_edge(clk) THEN        -- Clockwise Steps
                    CASE state IS
                        WHEN s0 => state <= s1;
                        WHEN s1 => state <= s2;
                        WHEN s2 => state <= s3;
                        WHEN s3 => state <= s4;
                        WHEN s4 => state <= s5;
                        WHEN s5 => state <= s6;
                        WHEN s6 => state <= s7;
                                   counter <= counter-1;
                        WHEN s7 => state <= s0;
                    END CASE;
                END IF;
            END LOOP;

        ELSIF counter < 11 THEN  -- When value < 0
            WHILE counter < 11 LOOP -- Counter-clockwise looping
                EXIT WHEN counter = 11;             
                IF rising_edge(clk) THEN        -- Counter-clockwise Steps
                    CASE state IS
                        WHEN s0 => state <= s7;
                        WHEN s7 => state <= s6;
                        WHEN s6 => state <= s5;
                        WHEN s5 => state <= s4;
                        WHEN s4 => state <= s3;
                        WHEN s3 => state <= s2;
                        WHEN s2 => state <= s1;
                                   counter <= counter+1;
                        WHEN s1 => state <= s0;
                    END CASE;
                END IF;
            END LOOP;

        ELSIF counter = 11 THEN -- When value = 0
            counter <= counter;

        END IF;

    ELSE state <= state;

    END IF;

END PROCESS;

WITH state SELECT
    q   <=  "0001"  WHEN    s0,
            "0011"  WHEN    s1,
            "0010"  WHEN    s2,
            "0110"  WHEN    s3,
            "0100"  WHEN    s4,
            "1100"  WHEN    s5,
            "1000"  WHEN    s6,
            "1001"  WHEN    s7;

q0 <= q(0);
q1 <= q(1);
q2 <= q(2);
q3 <= q(3);

    with counter select
digit<= "11000000" when 11,
    "11111001" when 12,
    "10100100" when 13,
    "10110000" when 14,
    "10011001" when 15,
    "10010010" when 16,
    "10000010" when 17,
    "11111000" when 18,
    "10000000" when 19,
    "10010000" when 20,
    "01111001" when 10,
    "00100100" when 9,
    "00110000" when 8,
    "00011001" when 7,
    "00010010" when 6,
    "00000010" when 5,
    "01111000" when 4,
    "00000000" when 3,
    "00010000" when 2;
    a7 <= digit(0);
b7 <= digit(1);
c7 <= digit(2);
d7 <= digit(3);
e7 <= digit(4);
f7 <= digit(5);
g7 <= digit(6);
h7 <= digit(7);
END arc;


This how it actually should work:
1. I can choose how many times the stepper motor (indicated with LEDs) will rotate with the "plus" and "minus" switches (it can counts from -9 to 9)
2. The 7 segment's dot is a negative sign for the number shown in the display
3. Postive value will make the motor rotate in clockwise direction
4. Negative value (shown with dot in 7 segments) will make the motor rotate in counter-clockwise direction
5. Everytime the motor completes 1 rotation, the 7 segments number should be reduced by 1 number
6. Stepper motor will only start to rotate if I start it (with giving a high logic to "start" input)


Problem occurs whenever I'm trying to simulate the circuit and hit "start". Tina will just go hang and then "Not Responding". To be honest, I'm not sure about what mistake I've made in my code because Tina shows no error whenever I try to "Enter New Macro" with my VHDL code.


My best guess is I've made mistake in my looping command

    IF start = '1' THEN
        IF counter > 11 THEN  -- When value > 0
            WHILE counter > 11 LOOP  -- Clockwise looping
                EXIT WHEN counter = 11;
                IF rising_edge(clk) THEN        -- Clockwise Steps
                    CASE state IS
                        WHEN s0 => state <= s1;
                        WHEN s1 => state <= s2;
                        WHEN s2 => state <= s3;
                        WHEN s3 => state <= s4;
                        WHEN s4 => state <= s5;
                        WHEN s5 => state <= s6;
                        WHEN s6 => state <= s7;
                                   counter <= counter-1;
                        WHEN s7 => state <= s0;
                    END CASE;
                END IF;
            END LOOP;

        ELSIF counter < 11 THEN  -- When value < 0
            WHILE counter < 11 LOOP -- Counter-clockwise looping
                EXIT WHEN counter = 11;             
                IF rising_edge(clk) THEN        -- Counter-clockwise Steps
                    CASE state IS
                        WHEN s0 => state <= s7;
                        WHEN s7 => state <= s6;
                        WHEN s6 => state <= s5;
                        WHEN s5 => state <= s4;
                        WHEN s4 => state <= s3;
                        WHEN s3 => state <= s2;
                        WHEN s2 => state <= s1;
                                   counter <= counter+1;
                        WHEN s1 => state <= s0;
                    END CASE;
                END IF;
            END LOOP;


I would really glad if someone could point out the mistake. Thank you in advance and have a good day!


Solution

  • What you are trying to achieve is a direct port from a computer language to VHDL. HDLs don't work this way and you'll have to shift your paradigm if you want to achieve this design. Here are a few tips:

    1. The description of your entity and architecture seem ok
    2. The main process' sensitivity list shows that you expect it to run "step by step", like thread but that cannot be done this way in HDL for synthesis. The model for hardware design description is that a process is run once throughout for each time there is an event on the signals listed in the sensivity list. The process cannot block while waiting for further events. If your sensitivity list signals are tested for values, that means that your process is combinatorial (pure logic). It's not what you intend to get (you have a clk signal). So your process should only have one signal in its sensitivity list: clk. After that, your process body can start with a unique IF rising_edge(clk) THEN that clearly indicates a clocked process.
    3. Clocked processes don't manage data passed the present clock cycle, so you have to think of the states you want to save from one cycle to the next and drive them as signals.
    4. Signals are exotic beasts compared to variables and you need to understand how they work with respect to events and time. For instance counter <= counter; is useless.
    5. The textual specification of behaviour of your system looks like the description of state machine. Why not refine it formally and flesh it out as a state of your system? See a simple example here
    6. Generally, for synthesis, you need a kind of reset signal to be sure all your states are initialized by hardware.