kureigu
Member level 2
I've written a few components to move a stepper motor back and forwards. I've simulated it in modelsim and it works as expected, but it won't work the same in hardware at all.
Basically I have a motor driving component, which takes a command of number of steps, hold time and speed and then performs the movement. Then I have the control_arbiter, which is just an intermediate bridge that connects components wanting access to the motors and the motor driving components.
Finally I have a 'search pattern' component, which basically issues the commands to move the motor back and forth.
My problem is that I can't seem to get direction to change when it's running in hardware, regardless of it working in simulation.
Any help with this would be greatly appreciated
Motor driver:
Control_arbiter:
Search Pattern:
Simulation attached
Basically I have a motor driving component, which takes a command of number of steps, hold time and speed and then performs the movement. Then I have the control_arbiter, which is just an intermediate bridge that connects components wanting access to the motors and the motor driving components.
Finally I have a 'search pattern' component, which basically issues the commands to move the motor back and forth.
My problem is that I can't seem to get direction to change when it's running in hardware, regardless of it working in simulation.
Any help with this would be greatly appreciated
Motor driver:
Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity motor_ctrl is
port( clk: in std_logic;
-- Hardware ports
SCLK, CW, EN: out std_logic; -- stepper driver control pins
-- Soft ports
Speed, steps: in integer;
dir: in std_logic; -- 1 = CW; 0 = CCW;
hold_time: in integer; -- if > 0, steppers will be held on for this many clock periods after moving
ready: out std_logic; -- indicates if ready for a movement
activate: in std_logic; -- setting activate starts instructed motion.
pos_out: out integer -- starts at 2000, 180deg = 200 steps, 10 full rotations trackable
);
end motor_ctrl;
architecture behavioural of motor_ctrl is
type action is (IDLE, HOLD, MOVE);
signal motor_action: action := IDLE;
signal clk_new: std_logic;
signal position: integer := 2000;
signal step_count: integer := 0;
signal drive: boolean := false;
begin
-- Clock divider
clk_manipulator: entity work.clk_divide port map(clk, speed, clk_new);
-- Drive motors
with drive select
SCLK <= clk_new when true,
'0' when false;
pos_out <= position;
process(clk_new)
-- Counter variables
variable hold_count: integer := 0;
begin
if rising_edge(clk_new) then
case motor_action is
when IDLE =>
-- reset counter vars, disable the driver and assert 'ready' signal
hold_count := 0;
step_count <= 0;
drive <= false;
EN <= '0';
ready <= '1';
-- When activated, start moving and de-assert ready signal
if(activate = '1') then
motor_action <= MOVE;
end if;
when HOLD =>
-- Stop the step clock signal
ready <= '0';
drive <= false;
-- Hold for given number of clock periods before returning to idle state
if(hold_count = hold_time) then
motor_action <= IDLE;
end if;
-- increment counter
hold_count := hold_count + 1;
when MOVE =>
-- Enable driver, apply clock output and set direction
ready <= '0';
EN <= '1';
drive <= true;
CW <= dir;
-- track the position of the motor
--if(dir = '1') then
-- position <= steps + step_count;
--else
-- position <= steps - step_count;
--end if;
-- Increment count until complete, then hold/idle
if(step_count < steps-1) then
step_count <= step_count + 1;
else
motor_action <= HOLD;
end if;
end case;
end if;
end process;
end behavioural;
Control_arbiter:
Code:
entity Control_arbiter is
port (clk: in std_logic;
EN, RST, CTRL, HALF, SCLK, CW: out std_logic_vector(2 downto 0)
-- needs signals for levelling and lock
);
end Control_arbiter;
architecture fsm of Control_arbiter is
type option is (INIT, SEARCH);
signal arbitration: option := INIT;
-- Motor controller arbiter signals
-- ELEVATION
signal El_spd, El_stps, El_hold, El_pos: integer;
signal El_dir, El_rdy, El_run: std_logic;
-- Search signals
signal search_spd, search_stps, search_hold: integer;
signal search_dir, search_Az_run, search_El_run: std_logic := '0';
-- status
signal lock: std_logic := '0';
begin
-- Motor controller components
El_motor: entity work.motor_ctrl port map(clk, SCLK(0), CW(0), EN(0),
El_spd, El_stps, El_dir, El_hold, El_rdy, El_run);
-- Search component
search_cpmnt: entity work.search_pattern port map( clk, '1', search_dir, search_stps, search_spd, search_hold,
El_rdy, search_El_run);
process(clk, arbitration)
begin
if rising_edge(clk) then
case arbitration is
when INIT =>
-- Initialise driver signals
EN(2 downto 1) <= "11";
CW(2 downto 1) <= "11";
SCLK(2 downto 1) <= "11";
RST <= "111";
CTRL <= "111";
HALF <= "111";
-- Move to first stage
arbitration <= SEARCH;
when SEARCH =>
-- Map search signals to motor controllers
El_dir <= search_dir;
El_stps <= search_stps;
El_spd <= search_spd;
El_hold <= search_hold;
El_run <= search_El_run;
end case;
end if;
end process;
end fsm;
Search Pattern:
Code:
entity search_pattern is
generic (step_inc: unsigned(7 downto 0) := "00010000"
);
port (clk: in std_logic;
enable: in std_logic;
dir: out std_logic;
steps, speed, hold_time: out integer;
El_rdy: in std_logic;
El_run: out std_logic
);
end search_pattern;
architecture behavioural of search_pattern is
type action is (WAIT_FOR_COMPLETE, LATCH_WAIT, MOVE_EL_CW, MOVE_EL_CCW);
signal search_state: action := WAIT_FOR_COMPLETE;
signal last_state: action := MOVE_EL_CCW;
begin
hold_time <= 1;
speed <= 1;
steps <= 2;
process(clk)
begin
if rising_edge(clk) then
-- enable if statement
case search_state is
when LATCH_WAIT =>
-- Make sure a GPMC has registered the command before waiting for it to complete
if(El_rdy = '0') then -- xx_rdy will go low if a stepper starts moving
search_state <= WAIT_FOR_COMPLETE; -- Go to waiting state and get ready to issue next cmd
end if;
when WAIT_FOR_COMPLETE =>
-- Wait for the movement to complete before making next
if(El_rdy = '1') then
-- Choose next command based on the last
if last_state = MOVE_EL_CCW then
search_state <= MOVE_EL_CW;
elsif last_state = MOVE_EL_CW then
search_state <= MOVE_EL_CCW;
end if;
end if;
when MOVE_EL_CW =>
dir <= '1';
El_run <= '1';
last_state <= MOVE_EL_CW;
search_state <= LATCH_WAIT;
when MOVE_EL_CCW =>
dir <= '0';
El_run <= '1';
last_state <= MOVE_EL_CCW;
search_state <= LATCH_WAIT;
when others =>
null;
end case;
-- else step reset on not enable
end if;
end process;
end behavioural;
Simulation attached