2013-03-21 46 views
0

我已经写了几个组件来前后移动步进电机。我在modelsim中模拟了它,它按预期工作,但它在硬件上完全不一样。VHDL模拟正常,但在硬件中不起作用

基本上我有一个电机驱动组件,它接收一个步数,保持时间和速度的命令,然后执行运动。然后,我有了control_arbiter,它只是一个连接要访问电机和电机驱动组件的组件的中间桥。 最后,我有一个“搜索模式”组件,它基本上发出命令来移动电机来回。

我的问题是,无论模拟工作如何,我都无法在硬件中运行时改变方向。

任何帮助,将不胜感激

电机驱动器:

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:

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; 
       -- Pass control to search 
       -- Once pointed, begin search maneuvers 
       -- map search signals to motor controllers 
       -- set a flag to begin search 
       -- if new pointing instruction received, break and move to that position (keep track of change) 
       -- On sensing 'lock', halt search 
       -- return to holding that position 


     end case; 

    end if; 

end process; 


end fsm; 

搜索模式:

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;   

辛:http://i.imgur.com/JAuevvP.png

+0

你更可能从http://electronics.stackexchange.com/获得VHDL专家的答案。 – Lundin 2013-03-21 14:18:48

+0

我刚刚查看了代码,并注意到在控制仲裁器中,您有一个对仲裁信号敏感的时钟进程。时钟进程应该只对时钟信号敏感,并且可能是异步复位。您可以尝试研究进一步... – sonicwave 2013-03-21 14:31:47

+0

当模拟和真实分歧: http://stackoverflow.com/a/15204291/106092 – 2013-03-21 16:15:35

回答

1

扫描快速通过您的代码,有一些事情,你应该为合成改变​​:

1)时钟分频器:使你的motor_driver过程敏感CLK的替代clk_new。划分时钟,每n个时钟产生一个时钟周期使能信号。该过程的开始可能看起来如下:形式

signal position: integer := 2000; 

process(clk) 
     ... 
    begin 

    if rising_edge(clk) then 
     if enable='1' then 
      case motor_action is 
      ... 

2)初始化仅适用于模拟工作,但没有为合成工作。对于合成中的初始化,在该过程中使用复位信号。

3)为所有状态机添加“when others”子句,其中状态设置为定义的值(例如,search_state < = INIT)。

+0

我想我看到你说的话居多,但我我很难理解如何生成时钟使能。它是通过在单独的进程中计数时钟边沿并在达到所需值时触发启用的? – Kureigu 2013-03-22 10:16:49

+0

是的,如果计数器达到目标值,重新启动计数器并设置使能信号有效。确保只激活一个clk周期的启用! – baldyHDL 2013-03-22 14:19:14

+0

我现在试过这个,但我仍然有同样的问题。无论我做什么,'dir'输出仍然不会改变,尽管它在模拟时间中改变很好。 如果有人感兴趣,[这里是组件的zip](https://www.dropbox.com/s/bsy2vgwuv6wt8uh/TB_search_pattern.zip) – Kureigu 2013-03-26 11:43:06

相关问题