stepper.c

Go to the documentation of this file.
00001 
00042 #include "stepper.h"
00043 
00044 #include "hw/hw_stepper.h"
00045 #include "hw/hw_sensor.h"
00046 
00047 #include "cfg/cfg_stepper.h"
00048 #include <cfg/debug.h>
00049 
00050 // Define logging setting (for cfg/log.h module).
00051 #define LOG_LEVEL   STEPPER_LOG_LEVEL
00052 #define LOG_FORMAT  STEPPER_LOG_FORMAT
00053 #include <cfg/log.h>
00054 
00055 #include <kern/proc.h>
00056 
00057 #include <algo/ramp.h>
00058 
00059 #include CPU_HEADER(stepper)
00060 
00061 #include <string.h>  // memset
00062 
00067 #define MOTOR_SWITCH_TICKS      60000   
00068 #define MOTOR_SWITCH_COUNT          5   
00069 #define MOTOR_HOME_MAX_STEPS    30000   
00070 #define MOTOR_CURRENT_TICKS      6000   
00071 // \}
00072 
00074 static struct Stepper all_motors[CONFIG_NUM_STEPPER_MOTORS];
00075 
00077 static fsm_state general_states[STEPPER_MAX_STATES];
00078 
00079 // IRQ functions for stepper motors
00080 static void stepper_interrupt(struct Stepper *motor);
00081 
00082 static void stepper_accel(struct Stepper *motor);
00083 static void stepper_decel(struct Stepper *motor);
00084 
00085 static bool stepper_isState(struct Stepper *motor, enum StepperState state);
00086 INLINE void stepper_changeState(struct Stepper *motor, enum StepperState newState);
00087 
00088 static void stepper_enableCheckHome(struct Stepper *motor, bool bDirPositive);
00089 
00090 #define MOTOR_INDEX(motor)     (motor->index)
00091 
00092 //------------------------------------------------------------------------
00093 
00094 INLINE bool setLowCurrent(struct Stepper* motor)
00095 {
00096     if (motor->power == motor->cfg->powerIdle)
00097         return false;
00098 
00099     motor->power = motor->cfg->powerIdle;
00100     STEPPER_SET_POWER_CURRENT(MOTOR_INDEX(motor), motor->cfg->powerIdle);
00101 
00102     return true;
00103 }
00104 
00105 INLINE bool setHighCurrent(struct Stepper* motor)
00106 {
00107     if (motor->power == motor->cfg->powerRun)
00108         return false;
00109 
00110     motor->power = motor->cfg->powerRun;
00111     STEPPER_SET_POWER_CURRENT(MOTOR_INDEX(motor), motor->cfg->powerRun);
00112     return true;
00113 }
00114 
00115 INLINE void setCheckSensor(struct Stepper* motor, enum MotorHomeSensorCheck value)
00116 {
00117     motor->enableCheckHome = value;
00118 }
00119 
00120 INLINE int8_t getCheckSensor(struct Stepper* motor)
00121 {
00122     return motor->enableCheckHome;
00123 }
00124 
00125 INLINE void setDirection(struct Stepper* motor, enum MotorDirection dir)
00126 {
00127     ASSERT(dir == DIR_POSITIVE || dir == DIR_NEGATIVE);
00128     motor->dir = dir;
00129 
00130     if (!motor->cfg->flags.axisInverted)
00131     {
00132         STEPPER_SET_DIRECTION(MOTOR_INDEX(motor), (dir == DIR_POSITIVE));
00133     }
00134     else
00135     {
00136         STEPPER_SET_DIRECTION(MOTOR_INDEX(motor), (dir != DIR_POSITIVE));
00137     }
00138 }
00139 
00144 INLINE void FAST_FUNC stepper_schedule_irq(struct Stepper* motor, stepper_time_t delay, bool do_step)
00145 {
00146 
00147     if (do_step)
00148     {
00149         // Record the step we just did
00150         motor->step += motor->dir;
00151         stepper_tc_doPulse(motor->timer);
00152     }
00153     else
00154         stepper_tc_skipPulse(motor->timer);
00155 
00156     stepper_tc_setDelay(motor->timer, delay);
00157 }
00158 
00159 
00160 static void stepper_accel(struct Stepper *motor)
00161 {
00162     DB(uint16_t old_val = motor->rampValue;)
00163     DB(uint32_t old_clock = motor->rampClock;)
00164 
00165     const struct Ramp *ramp = &motor->cfg->ramp;
00166 
00167     ASSERT(motor->rampClock != 0);
00168 
00169     motor->rampValue = ramp_evaluate(ramp, motor->rampClock);
00170     motor->rampClock += motor->rampValue;
00171     motor->rampStep++;
00172 
00173     DB(if (old_val && motor->rampValue > old_val)
00174     {
00175         LOG_ERR("Runtime ramp error: (max=%x, min=%x)\n", ramp->clocksMaxWL, ramp->clocksMinWL);
00176         LOG_ERR("    %04x @ %lu   -->   %04x @ %lu\n", old_val, old_clock, motor->rampValue, motor->rampClock);
00177     })
00178 
00179 }
00180 
00181 static void stepper_decel(struct Stepper *motor)
00182 {
00183     const struct Ramp *ramp = &motor->cfg->ramp;
00184     DB(uint16_t old_val = motor->rampValue;)
00185 
00186     motor->rampClock -= motor->rampValue;
00187     ASSERT(motor->rampClock != 0);
00188     motor->rampValue = ramp_evaluate(ramp, motor->rampClock);
00189     motor->rampStep--;
00190     DB(ASSERT(!old_val || motor->rampValue >= old_val););
00191 }
00192 
00193 INLINE void stepper_enable_irq(struct Stepper* motor)
00194 {
00195     stepper_tc_irq_enable(motor->timer);
00196 }
00197 
00198 INLINE void stepper_disable_irq(struct Stepper* motor)
00199 {
00200     stepper_tc_irq_disable(motor->timer);
00201 }
00202 
00203 // the home sensor can be in the standard home list or in the digital
00204 // sensor list
00205 bool stepper_readHome(struct Stepper* motor)
00206 {
00207     return (motor->cfg->homeSensorIndex < NUM_HOME_SENSORS) ?
00208         hw_home_sensor_read(motor->cfg->homeSensorIndex) :
00209         bld_hw_sensor_read(motor->cfg->homeSensorIndex - NUM_HOME_SENSORS);
00210 }
00211 
00212 bool stepper_readLevel(struct Stepper* motor)
00213 {
00214     return hw_level_sensor_read(motor->cfg->levelSensorIndex);
00215 }
00216 
00217 /************************************************************************/
00218 /* Finite-state machine to drive stepper logic from IRQ                 */
00219 /************************************************************************/
00220 
00221 INLINE void stepper_changeState(struct Stepper* motor, enum StepperState newState)
00222 {
00223     ASSERT(newState < STEPPER_MAX_STATES);
00224 
00225     motor->state = motor->cfg->states[newState];
00226     if (!motor->state)
00227         motor->state = general_states[newState];
00228     ASSERT(motor->state);
00229 }
00230 
00231 static bool stepper_isState(struct Stepper* motor, enum StepperState state)
00232 {
00233     return (motor->cfg->states[state]
00234             ? motor->cfg->states[state] == motor->state
00235             : general_states[state] == motor->state);
00236 }
00237 
00238 static bool stepper_checkHomeErrors(struct Stepper* motor)
00239 {
00240     bool home;
00241 
00242     home = stepper_readHome(motor);
00243 
00244     if (motor->enableCheckHome == MOTOR_HOMESENSOR_INCHECK && home
00245         && (!motor->stepCircular || motor->step < motor->stepCircular / 2))
00246         /*
00247         * if home Sensor check enabled in movement to 0 position and
00248         * the motor is in home increase the counter
00249         * for rotating motor we include the check that the motor is
00250         * inside the last "lap" (FIXME: check it better)
00251         */
00252         motor->stepsErrorHome++;
00253     else if (motor->enableCheckHome == MOTOR_HOMESENSOR_OUTCHECK && !home)
00254         /*
00255         * if home Sensor check enabled in movement from 0 position and
00256         * the motor is not in home increase the counter
00257         */
00258         motor->stepsErrorHome++;
00259     else
00260         // clear error steps counter
00261         motor->stepsErrorHome = 0;
00262 
00263     // if this is the last consecutive position in which the motor is in/out home ...
00264     ASSERT(motor->stepsErrorHome <= MOTOR_CONSECUTIVE_ERROR_STEPS);
00265     if (motor->stepsErrorHome >= MOTOR_CONSECUTIVE_ERROR_STEPS)
00266     {
00267         // if the position at which the motor first saw/didn't see the home
00268         // is out of tolerance -> breakmotor -> ERROR
00269         if (motor->step > motor->stepsTollMax || motor->step < motor->stepsTollMin )
00270         {
00271             // break motor and error
00272             motor->speed = SPEED_STOPPED;
00273             motor->stepToReach = motor->step;
00274 
00275             stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00276             motor->skipIrqs = MOTOR_SWITCH_COUNT;
00277             return false;
00278         }
00279 
00280         // the motor reached the home crossing -> disable error check
00281         setCheckSensor(motor, MOTOR_HOMESENSOR_NOCHECK);
00282     }
00283 
00284     return true;
00285 }
00286 
00287 static void stepper_checkLevelSensor(struct Stepper* motor)
00288 {
00289     // level sensor check
00290     if (motor->step > motor->stepsDeaf)
00291     {
00292         if (stepper_readLevel(motor))
00293         {
00294             // record current position, disable check and stop motor
00295             motor->stepsDeaf = DEAFSTEPS_DEFAULT;
00296             motor->stepsLevel = motor->step;
00297                         //motor->stepToReach = motor->step + motor->rampStep * motor->dir;
00298 
00299             motor->stepToReach = motor->step;
00300             motor->rampClock = motor->cfg->ramp.clocksMaxWL;
00301             motor->rampValue = motor->cfg->ramp.clocksMaxWL;
00302         }
00303     }
00304 }
00305 
00306 static enum StepperState FAST_FUNC FSM_run(struct Stepper *motor)
00307 {
00308     uint16_t distance;
00309 
00310     if (!stepper_checkHomeErrors(motor))
00311         return MSTS_ERROR;
00312 
00313     stepper_checkLevelSensor(motor);
00314 
00315     if ((motor->stepToReach != STEPS_INFINITE_POSITIVE) &&
00316         (motor->stepToReach != STEPS_INFINITE_NEGATIVE ))
00317     {
00318         // Calculate (always positive) distance between current position and destination step
00319         distance = (uint16_t)((motor->stepToReach - motor->step) * motor->dir);
00320     }
00321     else
00322     {
00323         // We're at a very long distance ;-)
00324         distance = 0xFFFF;
00325         // if the motor is rotating and it has just ran a complete round
00326         // the position is set to 0
00327         if(motor->step == motor->stepCircular)
00328             motor->step = 0;
00329     }
00330 
00331     if (distance == 0)
00332         // Position reached - stop motor
00333         //motor->speed = SPEED_STOPPED;
00334         motor->rampStep = -1;
00335         //motor->rampClock = motor->ramp->clocksMaxWL;
00336         //motor->rampValue = 0;
00337         //motor->rampClock = motor->rampValue = motor->ramp->clocksMaxWL;
00338 
00339     else if (distance <= (uint16_t)motor->rampStep)
00340         stepper_decel(motor);
00341 
00342     // check whether the velocity must be changed
00343     else if (motor->speed < (uint16_t)motor->rampValue)
00344     {
00345         stepper_accel(motor);
00346         if (motor->speed > (uint16_t)motor->rampValue)
00347             motor->speed = (uint16_t)motor->rampValue;
00348     }
00349     else if (motor->speed > (uint16_t)motor->rampValue)
00350         stepper_decel(motor);
00351 
00352     // If rampStep == -1, leave output pin high and wait for low current
00353     if (motor->rampStep < 0)
00354     {
00355         // Wait before switching to low current
00356         motor->speed = SPEED_STOPPED;
00357 
00358         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00359         motor->skipIrqs = MOTOR_SWITCH_COUNT;
00360 
00361         /*
00362          * If there was a home sensor check activated, and the check has not
00363          * been done yet, it means that we reached the end position without
00364          * finding the home (or exiting from it). This is bad!
00365          */
00366         if (motor->enableCheckHome != MOTOR_HOMESENSOR_NOCHECK)
00367             return MSTS_ERROR;
00368 
00369         // check if the motor has to stay in high current
00370         if(motor->cfg->flags.highcurrentBit)
00371         {
00372             motor->changeCurrentIrqs = MOTOR_CURRENT_TICKS;
00373             return MSTS_IDLE;
00374         }
00375 
00376         return MSTS_PREIDLE;
00377     }
00378 
00379     // Wait for high->low transition
00380     ASSERT(motor->rampValue > motor->cfg->pulse);
00381     stepper_schedule_irq(motor, motor->rampValue, true);
00382 
00383     return MSTS_RUN;
00384 }
00385 
00386 static enum StepperState FSM_idle(struct Stepper* motor)
00387 {
00388     stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00389 
00390     if (motor->speed == SPEED_STOPPED)
00391     {
00392         // check if it's time to switch to low current
00393         if(motor->changeCurrentIrqs > 0)
00394         {
00395             if(--motor->changeCurrentIrqs == 0)
00396                 setLowCurrent(motor);
00397         }
00398         return MSTS_IDLE;
00399     }
00400 
00401     // Switch to high current and wait for stabilization
00402     // (if the motor is in low current)
00403     if(motor->changeCurrentIrqs == 0)
00404     {
00405         setHighCurrent(motor);
00406         motor->skipIrqs = MOTOR_SWITCH_COUNT;
00407     }
00408 
00409     return MSTS_PRERUN;
00410 }
00411 
00412 static enum StepperState FSM_preidle(struct Stepper* motor)
00413 {
00414     // Normal operation mode
00415     motor->changeCurrentIrqs = 0;
00416     setLowCurrent(motor);
00417     stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00418     return MSTS_IDLE;
00419 }
00420 
00421 static enum StepperState FSM_error(struct Stepper* motor)
00422 {
00423     // Error condition mode
00424     setLowCurrent(motor);
00425     stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00426     return MSTS_ERROR;
00427 }
00428 
00429 static enum StepperState FSM_prerun(struct Stepper* motor)
00430 {
00431     enum MotorDirection dir;
00432 
00433     // distance != 0?
00434     if ((motor->stepToReach != motor->step) ||
00435         (motor->stepToReach == STEPS_INFINITE_POSITIVE) ||
00436         (motor->stepToReach == STEPS_INFINITE_NEGATIVE)  )
00437     {
00438         // Setup for first step
00439         motor->rampStep = 0;
00440 
00441         // Setup Direction
00442         if(motor->stepToReach == STEPS_INFINITE_POSITIVE)
00443             dir = DIR_POSITIVE;
00444         else if(motor->stepToReach == STEPS_INFINITE_NEGATIVE)
00445              dir = DIR_NEGATIVE;
00446         else if(motor->stepToReach > motor->step)
00447             dir = DIR_POSITIVE;
00448         else
00449              dir = DIR_NEGATIVE;
00450 
00451         setDirection(motor, dir);
00452 
00453         // Enable of the home sensor control, if necessary
00454         // (before calling this function set the motor direction as above)
00455         stepper_enableCheckHome(motor, (dir == DIR_POSITIVE));
00456 
00457         // if the movement is infinite negative set the sw direction positive
00458         // (not the hw: see below) to count the steps
00459         if(motor->stepToReach == STEPS_INFINITE_NEGATIVE) motor->dir = DIR_POSITIVE;
00460 
00461         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00462         return MSTS_RUN;
00463     }
00464     else
00465     {
00466         /*
00467          * If we are here we should do at least one step.
00468          *  anyway ....
00469          */
00470         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00471         motor->skipIrqs = MOTOR_SWITCH_COUNT;
00472         return MSTS_PREIDLE;
00473     }
00474 }
00475 
00476 static enum StepperState FSM_preinit(struct Stepper* motor)
00477 {
00478     // Set current high, and wait for stabilization
00479     if (setHighCurrent(motor))
00480     {
00481         motor->skipIrqs = MOTOR_SWITCH_COUNT;
00482         return MSTS_PREINIT;
00483     }
00484 
00485     /*
00486      * This state is used when initializing the motor, to bring back
00487      * to the home. The idea is that we do not know where the motor
00488      * is at this point, so there can be two possibilities:
00489      *
00490      * - The motor is already in home. We do not know how much into the
00491      *   home we are. So we need to get out of the home (MSTS_LEAVING)
00492      *   and then get back into it of the desired number of steps.
00493      *
00494      * - The motor is not in home: we need to look for it (MSTS_INIT).
00495      *   We can safely assume that we will find the home in the negative
00496      *   direction. For circular motors, any direction would do. For
00497      *   other motors, the home is set at zero, so the current position
00498      *   has to be a positive value.
00499      *
00500      */
00501     if (stepper_readHome(motor))
00502     {
00503         setDirection(motor, DIR_POSITIVE);
00504         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00505         return MSTS_LEAVING;
00506     }
00507 
00508     setDirection(motor, DIR_NEGATIVE);
00509     stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00510     return MSTS_INIT;
00511 }
00512 
00513 
00514 static enum StepperState FSM_init(struct Stepper* motor)
00515 {
00516     // If we are not in home, keep looking
00517     if (!stepper_readHome(motor))
00518     {
00519         stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00520         return MSTS_INIT;
00521     }
00522 
00523     /*
00524      * Home! We still need to enter the home of the specified number of steps.
00525      * That will be our absolute zero.
00526      */
00527 
00528     motor->step = motor->cfg->stepsInHome - 1; // start counting down steps in home
00529     motor->stepToReach = 0;
00530 
00531     stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00532     return MSTS_ENTERING;
00533 }
00534 
00535 static enum StepperState FSM_entering(struct Stepper* motor)
00536 {
00537     // We must be in home
00538     //ASSERT(stepper_readHome(motor));
00539 
00540     // if while entering the sensor we are no more in home we reset the steps
00541     // counter (optical sensor)
00542     if(!stepper_readHome(motor))
00543         motor->step = motor->cfg->stepsInHome - 1;
00544 
00545     // Current Position must be non-negative
00546     ASSERT(motor->step >= 0);
00547 
00548     if(motor->step == 0)
00549     {
00550         // reach the final target inside home sensor
00551         motor->step = 0;
00552         return MSTS_PREIDLE;
00553     }
00554 
00555     // keep doing steps
00556     stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00557     return MSTS_ENTERING;
00558 }
00559 
00560 static enum StepperState FSM_leaving(struct Stepper* motor)
00561 {
00562     ASSERT(motor->dir == DIR_POSITIVE);
00563 
00564     motor->step = 0;
00565     if (!stepper_readHome(motor))
00566     {
00567         // we are out of home : change state and going far from sensor
00568         stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00569         return MSTS_OUTHOME;
00570     }
00571     else
00572     {
00573         // Still at home. Just wait here and keep doing steps
00574         stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00575         return MSTS_LEAVING;
00576     }
00577 }
00578 
00579 static enum StepperState FSM_outhome(struct Stepper* motor)
00580 {
00581     ASSERT(motor->dir == DIR_POSITIVE);
00582 
00583     // We must be out of home: once we are no more in home
00584     // we just need to move away, even if not very precide (optical sensor)
00585     // ASSERT(!stepper_readHome(motor));
00586 
00587     if(motor->step >= motor->cfg->stepsOutHome)
00588     {
00589         // reach the final target outside home sensor
00590         motor->step = 0;
00591 
00592         // start home entering procedure (delay in executing step)
00593         setDirection(motor, DIR_NEGATIVE);
00594         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00595         motor->skipIrqs = MOTOR_SWITCH_COUNT;
00596         return MSTS_INIT;
00597     }
00598 
00599     // keep doing steps
00600     stepper_schedule_irq(motor, motor->cfg->clocksHome, true);
00601     return MSTS_OUTHOME;
00602 }
00603 
00604 static void FAST_FUNC stepper_interrupt(struct Stepper *motor)
00605 {
00606     enum StepperState newState;
00607 
00608     // Check if we need to skip a certain number of IRQs
00609     if (motor->skipIrqs)
00610     {
00611         --motor->skipIrqs;
00612         stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00613         return;
00614     }
00615 
00616     ASSERT(motor->state);
00617     newState = motor->state(motor);
00618     stepper_changeState(motor, newState);
00619 }
00620 
00621 
00622 
00623 
00624 /************************************************************************/
00625 /* Public API                                                           */
00626 /************************************************************************/
00627 
00631 void stepper_init(void)
00632 {
00633     STEPPER_INIT();
00634 
00635     // before starting the power all the stepper enable must be surely low
00636     stepper_disable();
00637 
00638     // Bind functions to general states
00639     memset(general_states, 0, sizeof(general_states));
00640     general_states[MSTS_IDLE] = FSM_idle;
00641     general_states[MSTS_PREIDLE] = FSM_preidle;
00642     general_states[MSTS_PRERUN] = FSM_prerun;
00643     general_states[MSTS_RUN] = FSM_run;
00644     general_states[MSTS_PREINIT] = FSM_preinit;
00645     general_states[MSTS_INIT] = FSM_init;
00646     general_states[MSTS_ENTERING] = FSM_entering;
00647     general_states[MSTS_LEAVING]= FSM_leaving;
00648     general_states[MSTS_OUTHOME]= FSM_outhome;
00649     general_states[MSTS_ERROR]= FSM_error;
00650 }
00651 
00652 void stepper_end(void)
00653 {
00654     // Disable all stepper timer interrupt to stop motors
00655     for (int i = 0; i < CONFIG_NUM_STEPPER_MOTORS; i++)
00656         stepper_disable_irq(&all_motors[i]);
00657 }
00658 
00662 struct Stepper* stepper_setup(int index, struct StepperConfig *cfg)
00663 {
00664     struct Stepper* motor;
00665 
00666     ASSERT(index < CONFIG_NUM_STEPPER_MOTORS);
00667 
00668     motor = &all_motors[index];
00669     motor->index = index;
00670     motor->cfg = cfg;
00671 
00672     //Register timer to stepper, and enable irq
00673     stepper_tc_setup(motor->index, &stepper_interrupt, motor);
00674 
00675     stepper_reset(motor);
00676 
00677     stepper_enable_irq(motor);
00678 
00679     return motor;
00680 }
00681 
00685 void stepper_disable(void)
00686 {
00687     STEPPER_DISABLE_ALL();
00688 }
00689 
00693 void stepper_reset(struct Stepper *motor)
00694 {
00695     /*
00696      * To stop motor diable stepper irq.
00697      */
00698     stepper_disable_irq(motor);
00699 
00700     //Disable a stepper motor
00701     STEPPER_DISABLE(MOTOR_INDEX(motor));
00702 
00703     // Setup context variables
00704     motor->power = 0;
00705     motor->step = 0;
00706     motor->rampStep = -1;
00707     // We cannot set the clock at zero at start because of a limit in the fixed point ramp
00708     motor->rampClock = motor->cfg->ramp.clocksMaxWL;
00709     motor->rampValue = motor->cfg->ramp.clocksMaxWL;
00710     motor->speed = SPEED_STOPPED;
00711     motor->stepToReach = 0;
00712     motor->skipIrqs = 0;
00713     motor->stepCircular = 0;
00714     setDirection(motor, DIR_POSITIVE);
00715     setLowCurrent(motor);
00716 
00717     motor->changeCurrentIrqs = 0;
00718 
00719     // default value (disable level sensor check)
00720     motor->stepsDeaf = DEAFSTEPS_DEFAULT;
00721 
00722     STEPPER_SET_HALF_STEP(MOTOR_INDEX(motor), motor->cfg->flags.halfStep);
00723     STEPPER_SET_CONTROL_BIT(MOTOR_INDEX(motor), motor->cfg->flags.controlBit);
00724 
00725     if (motor->cfg->homeSensorIndex < NUM_HOME_SENSORS)
00726         hw_home_sensor_set_inverted(motor->cfg->homeSensorIndex, motor->cfg->flags.homeInverted);
00727 
00728     if (motor->cfg->levelSensorIndex != MOTOR_NO_LEVEL_SENSOR)
00729         hw_level_sensor_set_inverted(motor->cfg->levelSensorIndex, motor->cfg->flags.levelInverted);
00730 
00731     stepper_changeState(motor, MSTS_IDLE);
00732 
00733     // Reset stepper timer counter
00734     stepper_tc_resetTimer(motor->timer);
00735 
00736     // reset hw to the stepper motor
00737     STEPPER_RESET(MOTOR_INDEX(motor));
00738     STEPPER_ENABLE(MOTOR_INDEX(motor));
00739 }
00740 
00741 
00742 void stepper_updateHalfStep(struct Stepper *motor)
00743 {
00744     STEPPER_SET_HALF_STEP(MOTOR_INDEX(motor), motor->cfg->flags.halfStep);
00745 }
00746 
00747 void stepper_updateControlBit(struct Stepper *motor)
00748 {
00749     STEPPER_SET_CONTROL_BIT(MOTOR_INDEX(motor), motor->cfg->flags.controlBit);
00750 }
00751 
00752 void stepper_updateControlMoveBit(struct Stepper *motor)
00753 {
00754     STEPPER_SET_CONTROL_BIT(MOTOR_INDEX(motor), motor->cfg->flags.controlMoveBit);
00755 }
00756 
00766 void stepper_home(struct Stepper *motor)
00767 {
00768 
00769     // Begin home procedure
00770     stepper_disable_irq(motor);
00771 
00772     // disable home sensor check (default)
00773     setCheckSensor(motor, MOTOR_HOMESENSOR_NOCHECK);
00774     // deafult value (disable level sensor check)
00775     motor->stepsDeaf = DEAFSTEPS_DEFAULT;
00776 
00777     setDirection(motor, DIR_POSITIVE);
00778     stepper_schedule_irq(motor, MOTOR_SWITCH_TICKS, false);
00779     stepper_changeState(motor, MSTS_PREINIT);
00780 
00781     stepper_enable_irq(motor);
00782 }
00783 
00784 
00785 void stepper_setStep(struct Stepper *motor, int16_t step)
00786 {
00787     motor->step = step;
00788 }
00789 
00790 
00791 int16_t stepper_getStep(struct Stepper *motor)
00792 {
00793     return motor->step;
00794 }
00795 
00796 int16_t stepper_getLevelStep(struct Stepper *motor)
00797 {
00798     return motor->stepsLevel;
00799 }
00800 
00801 void stepper_set_stepCircular(struct Stepper *motor, int16_t steps)
00802 {
00803     motor->stepCircular = steps;
00804 }
00805 
00806 int16_t stepper_get_stepCircular(struct Stepper *motor)
00807 {
00808     return motor->stepCircular;
00809 }
00810 
00811 int16_t stepper_scaleSteps(struct Stepper *motor, int16_t dir)
00812 {
00813     int16_t steps;
00814 
00815     // scale the current position inside the motor lap
00816     if(!motor->stepCircular) return 0;
00817 
00818     // to be sure ....
00819     while(motor->step > motor->stepCircular) motor->step -= motor->stepCircular;
00820 
00821     if(dir == DIR_NEGATIVE)
00822     {
00823         steps = ((motor->stepCircular - motor->step) % motor->stepCircular);
00824         motor->step = steps;
00825     }
00826     /*
00827     else
00828         steps = (motor->step % motor->stepCircular);
00829     motor->step = steps;
00830     */
00831     return motor->step;
00832 }
00833 
00834 static void stepper_enableCheckHome(struct Stepper *motor, bool bDirPositive)
00835 {
00836     enum MotorHomeSensorCheck value = MOTOR_HOMESENSOR_NOCHECK; // default
00837 
00838     motor->stepsTollMin = 0;
00839 
00840     if((motor->stepToReach != STEPS_INFINITE_POSITIVE) &&
00841         (motor->stepToReach != STEPS_INFINITE_NEGATIVE)  )
00842     {
00843         if(bDirPositive) // else if(motor->dir == DIR_POSITIVE)
00844         {
00845             /* if the direction is positive (movement from 0 position),
00846              * if the starting position is inside home and the target position
00847              * is outside home -> the motor has to cross the home sensor -> enable the control
00848              */
00849             if (motor->step < motor->cfg->stepsInHome - motor->cfg->stepsTollOutHome &&
00850                 motor->stepToReach > motor->cfg->stepsInHome + motor->cfg->stepsTollOutHome)
00851             {
00852                 value = MOTOR_HOMESENSOR_OUTCHECK;
00853                 // home sensor out max position
00854                 motor->stepsTollMax = motor->cfg->stepsInHome + motor->cfg->stepsTollOutHome + MOTOR_CONSECUTIVE_ERROR_STEPS;
00855                 // home sensor in max position
00856                 if(motor->cfg->stepsInHome + MOTOR_CONSECUTIVE_ERROR_STEPS > motor->cfg->stepsTollOutHome)
00857                     motor->stepsTollMin = motor->cfg->stepsInHome + MOTOR_CONSECUTIVE_ERROR_STEPS - motor->cfg->stepsTollOutHome;
00858             }
00859         }
00860         else // if(motor->dir == DIR_NEGATIVE)
00861         {
00862             /*
00863              * if the direction is negative (movement to 0 position),
00864              * if the starting position is far from home and the target position
00865              * is inside home -> the motor has to cross the home sensor -> enable the control
00866              */
00867             if (motor->step > motor->cfg->stepsInHome + motor->cfg->stepsTollInHome &&
00868                 motor->stepToReach < motor->cfg->stepsInHome - motor->cfg->stepsTollInHome)
00869             {
00870                 value = MOTOR_HOMESENSOR_INCHECK;
00871                 // home sensor out max position
00872                 motor->stepsTollMax = motor->cfg->stepsInHome + motor->cfg->stepsTollInHome - MOTOR_CONSECUTIVE_ERROR_STEPS;
00873                 // home sensor in max position
00874                 if(motor->cfg->stepsInHome > motor->cfg->stepsTollInHome + MOTOR_CONSECUTIVE_ERROR_STEPS)
00875                     motor->stepsTollMin = motor->cfg->stepsInHome - (motor->cfg->stepsTollInHome + MOTOR_CONSECUTIVE_ERROR_STEPS);
00876             }
00877         }
00878     }
00879     setCheckSensor(motor, value);
00880 }
00881 
00888 int16_t stepper_move(struct Stepper *motor, int16_t steps, uint16_t speed, int16_t deafstep)
00889 {
00890     // if the stepper already is in the desired position -> nothing to do
00891     if (motor->step == steps)
00892         return 0;
00893 
00894     stepper_disable_irq(motor);
00895 
00896     // final position
00897     motor->stepToReach = steps;
00898 
00899     // clear error steps
00900     motor->stepsErrorHome = 0;
00901 
00902     // position to start level check
00903     motor->stepsDeaf = deafstep;
00904 
00905     // clear level position
00906     motor->stepsLevel = 0;
00907 
00908     if (speed < motor->cfg->ramp.clocksMinWL)
00909     {
00910         ASSERT2(0, "speed too fast (small number)");
00911         speed = motor->cfg->ramp.clocksMinWL;
00912     }
00913 
00914     motor->rampClock = motor->cfg->ramp.clocksMaxWL;
00915     motor->rampValue = motor->cfg->ramp.clocksMaxWL;
00916 
00917     // TODO: find the exact value for motor->speed searching  in the ramp array.
00918     motor->speed = speed;
00919 
00920     stepper_enable_irq(motor);
00921 
00922     return 0;
00923 }
00924 
00925 
00929 void stepper_stop(struct Stepper *motor)
00930 {
00931     /*
00932      * The best way is to set the target of the movement to the minimum
00933      * distance needed to decelerate. The logic in FSM_run will do the rest.
00934      */
00935     if(stepper_idle(motor))
00936         return;
00937 
00938     stepper_disable_irq(motor);
00939     motor->stepToReach = motor->step + motor->rampStep * motor->dir;
00940     stepper_enable_irq(motor);
00941 }
00942 
00943 
00947 void stepper_break(struct Stepper *motor, enum StepperState state)
00948 {
00949     // The best way to abort any operation is to go back to pre-idle mode
00950     stepper_disable_irq(motor);
00951 
00952     // Set of Speed disabled and Steps reached so that the function
00953     // stepper_idle() succeeds
00954     motor->speed = SPEED_STOPPED;
00955     motor->stepToReach = motor->step;
00956     stepper_changeState(motor, state);
00957     stepper_enable_irq(motor);
00958 }
00959 
00961 //  this means anyway that the motor is not moving
00962 bool stepper_idle(struct Stepper *motor)
00963 {
00964     return (stepper_isState(motor, MSTS_ERROR) ||
00965             (stepper_isState(motor, MSTS_IDLE) && motor->step == motor->stepToReach) );
00966 }
00967 
00969 bool stepper_error(struct Stepper *motor)
00970 {
00971     return (stepper_isState(motor, MSTS_ERROR));
00972 }
00973 
00975 bool stepper_inhome(struct Stepper *motor)
00976 {
00977     return(stepper_getStep(motor) == 0 &&
00978            !stepper_readHome(motor) );
00979 }