代码之家  ›  专栏  ›  技术社区  ›  Kureigu

VHDL可以很好地模拟,但在硬件中的作用不同

  •  0
  • Kureigu  · 技术社区  · 11 年前

    我已经编写了一些组件来前后移动步进电机。我已经在modelsim中对它进行了模拟,它可以按预期工作,但在硬件中根本无法工作。

    基本上,我有一个电机驱动部件,它可以控制步数、保持时间和速度,然后执行运动。然后我有了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;
    

    控件标识符(_A):

    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

    1 回复  |  直到 11 年前
        1
  •  1
  •   baldyHDL    11 年前

    快速扫描代码,您应该更改一些内容以进行合成:

    1) 时钟分频器:使motor_driver进程对clk而不是clknew敏感。为了划分时钟,每n个时钟生成一个时钟周期使能信号。该过程的开始可以看起来如下:

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

    2) 表单的初始化

        signal position: integer := 2000;
    

    只适用于模拟,但不适用于合成。为了在合成中进行初始化,在该过程中使用复位信号。

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