Forum Discussion

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

Button press to change state machine - "Can't resolve multiple constant drivers..."

I'm trying to set up a small demo to make a stepper motor move in various ways in which I'll need a series of buttons to control the action of the motors.

To do this I'm using a state machine to perform the required actions depending on the button press, however some of the states aren't continuous and need to drop to another state after completion of the action. The trouble is I'm getting errors. I kinda understand why the compiler doesn't like it, but I don't know how to circumvent the issue, so suggestions welcome.

Also, it would appear that I'm not getting the desired clock signal on my step_clk output, which also confuses me greatly.


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity motor_demo is
    port(    clk: in std_logic;
        
            RST, EN, CTRL, HALF, CW, Step_clk: out std_logic;
            sw: in std_logic_vector(0 to 4)
            );
end motor_demo;
architecture stm of motor_demo is
    type motor_action is (STOP, CWISE, CCWISE, CW_45, CCW_180);
    signal motor_state: motor_action := CWISE;
    
    signal stepcount: integer := 0;
    signal clk_div: std_logic;
begin
    -- Clock divider for stepper action
    clk_divider: entity work.clk_divide port map(clk, clk_div);
    
    
    process(sw) is
    begin
    
        case sw is
            when "01111" =>
                motor_state <= CWISE;
            when "10111" =>
                motor_state <= CCWISE;
            when "11011" =>
                motor_state <= STOP;
            when "11101" =>
                motor_state <= CW_45;
            when "00001" =>
                motor_state <= CCW_180;
            when others =>
                motor_state <= STOP;
        end case;
    
    end process;
    
    process(clk_div, motor_state) is
    begin
    
        if rising_edge(clk_div) then
        
            case motor_state is 
                when STOP =>
                    step_clk <= '0';
                    stepcount <= 0;
                    
                when CWISE =>
                    step_clk <= clk_div;
                    CW <= '1';
                    
                when CCWISE =>
                    Step_clk <= clk_div;
                    CW <= '0';
                    
                when CW_45 =>
                    CW <= '1';
                    if(stepcount < 49) then
                        step_clk <= clk_div;
                    else
                        motor_state <= STOP;
                    end if;                    
                    stepcount <= stepcount + 1;
                
                when CCW_180 =>
                    CW <= '0';
                    if(stepcount < 199) then
                        step_clk <= clk_div;
                    else
                        motor_state <= STOP;
                    end if;                    
                    stepcount <= stepcount + 1;                    
        
            end case;
        
        end if;
    
    end process;
    
end stm;

Error (10028): Can't resolve multiple constant drivers for net "motor_state.STOP" at motor_demo.vhd(52)
Error (10029): Constant driver at motor_demo.vhd(31)
Error (10028): Can't resolve multiple constant drivers for net "motor_state.CWISE" at motor_demo.vhd(52)
Error (10028): Can't resolve multiple constant drivers for net "motor_state.CCWISE" at motor_demo.vhd(52)
Error (10028): Can't resolve multiple constant drivers for net "motor_state.CW_45" at motor_demo.vhd(52)
Error (10028): Can't resolve multiple constant drivers for net "motor_state.CCW_180" at motor_demo.vhd(52)
Error (12153): Can't elaborate top-level user hierarchy
Error: Quartus II 32-bit Analysis & Synthesis was unsuccessful. 7 errors, 5 warnings

Edit: So apparently if I put the 'sw' case statement within 'if rising_edge(clk_div)' statement I don't have a problem, but the only downside is that's not ideal if the clock were to be going a few Hz.

5 Replies

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

    Hi,

    Only one process should generate "motor_state"

    but you get "motor_state <= stop;" in your 2nd process !

    It seems you are new to VHDL, I suggest you to

    first describe completely your finite state machine by a schema : inputs and transitions to select which state, outputs for each state.

    and then simply transcode to VHDL.

    look for "moore machine", "mealy machine".

    more secure like this.

    else you will spend hours and get headache to "debug" a bad conception.

    EDIT :

    "Multiple drivers" means that tour "motor_state" is driven by more than one source and the synthesizer don't know how to resolve this signal, beacause this signal is declared as unresolved.

    "Unresolved signal" declaration is a good thing to early catch this error.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Hi,

    Only one process should generate "motor_state"

    but you get "motor_state <= stop;" in your 2nd process !

    --- Quote End ---

    I realise that, and I realise that's where the error is from.

    What I was confused about was how else I'm supposed to drop out of that state automatically after a number of cycles without that assignment there? I NEED two constant drivers as far as I can see.

    EDIT: I think I found a solution, but it's giving me a weird error and I can't see any problem. argh! Code is in my post below.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You dont need two constant drivers. Yoy just need to signal to your state machine when to stop. You probably need another signal for this.

    Your new code should work as it's a single process. Remember that a signal takes the last thing assigned to it.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok, so here's my new code. Hopefully this is more appropriately written.

    EDIT: This doesn't work, obviously. It doesn't drive the motor because cw_45 and ccw_180 are low to begin so it just throws it into the STOP state during the 'else' of the second if statement and keeps it there. Suggestions on how to fix?

    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;
    use ieee.std_logic_arith.all;
    entity motor_demo is
        port(    clk: in std_logic;
            
                RST, EN, CTRL, HALF, CW, Step_clk: out std_logic;
                sw: in std_logic_vector(0 to 4);
                sw_check: out std_logic_vector(0 to 4)
                );
    end motor_demo;
    architecture stm of motor_demo is
        type motor_action is (STOP, CWISE, CCWISE);
        signal motor_state: motor_action := CWISE;
        
        signal stepcount: integer := 0;
        signal clk_div: std_logic;
        signal drive: std_logic := '0';
        signal cw_45, ccw_180: std_logic := '0';
    begin
        -- Clock divider for stepper action
        clk_divider: entity work.clk_divide port map(clk, clk_div);
        
        -- Motor control lines
        EN <= '1';
        RST <= '1';
        CTRL <= '1';
        HALF <= '1';
        
        -- switch debugging
        sw_check <= sw;
        
        -- driving the step clock
        with drive select
            step_clk <= clk_div when '1',
                            '0' when '0',
                            '0' when others;
                            
        process(clk_div, motor_state, sw) is
        begin
        
            if rising_edge(clk_div) then
            
                if sw(0) = '0' then
                    motor_state <= CWISE;
                elsif sw(1) = '0' then
                    motor_state <= CCWISE;
                elsif sw(2) = '0' then
                    motor_state <= STOP;
                elsif sw(3) = '0' then
                    motor_state <= CWISE;
                    cw_45 <= '1';
                elsif sw(4) = '0' then
                    motor_state <= CCWISE;
                    ccw_180 <= '1';
                end if;    
                
                -- counter conditions
                if cw_45 = '1' AND stepcount < 49 then
                    stepcount <= stepcount + 1;
                elsif ccw_180 = '1' AND stepcount < 199 then
                    stepcount <= stepcount + 1;
                else
                    ccw_180 <= '0';
                    cw_45 <= '0';
                    motor_state <= STOP;
                end if;    
            
                case motor_state is 
                    when STOP =>
                        drive <= '0';
                        stepcount <= 0;    
                    when CWISE =>
                        drive <= '1';
                        CW <= '1';        
                    when CCWISE =>
                        drive <= '1';
                        CW <= '0';    
                end case;
            
            end if;
        
        end process;
        
    end stm;
                        
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    What exactly doesnt work? what errros are you getting? in simulation or on hardware? have you got a testbench?

    You have a clock divider - if this is done in logic and not a PLL then you could have timing problems on a real circuit.