MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

stepper.c

Go to the documentation of this file.
00001 /*********************************************************************************
00002 
00003  Copyright 2006-2008 MakingThings
00004 
00005  Licensed under the Apache License, 
00006  Version 2.0 (the "License"); you may not use this file except in compliance 
00007  with the License. You may obtain a copy of the License at
00008 
00009  http://www.apache.org/licenses/LICENSE-2.0 
00010  
00011  Unless required by applicable law or agreed to in writing, software distributed
00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
00014  the specific language governing permissions and limitations under the License.
00015 
00016 *********************************************************************************/
00017 
00018 // MakingThings - Make Controller Board - 2006
00019 
00020 /** \file stepper.c 
00021   Stepper Motor Controls.
00022   Methods for controlling up to 2 stepper motors with the Make Application Board.
00023 */
00024 
00025 #include "stepper.h"
00026 #include "io.h"
00027 #include "fasttimer.h"
00028 #include "config.h"
00029 
00030 #include "AT91SAM7X256.h"
00031 
00032 #if ( APPBOARD_VERSION == 50 )
00033   #define STEPPER_0_IO_0 IO_PA02
00034   #define STEPPER_0_IO_1 IO_PA02
00035   #define STEPPER_0_IO_2 IO_PA02
00036   #define STEPPER_0_IO_3 IO_PA02
00037   #define STEPPER_1_IO_0 IO_PA02
00038   #define STEPPER_1_IO_1 IO_PA02
00039   #define STEPPER_1_IO_2 IO_PA02
00040   #define STEPPER_1_IO_3 IO_PA02
00041 #endif
00042 #if ( APPBOARD_VERSION == 90 || APPBOARD_VERSION == 95 || APPBOARD_VERSION == 100 )
00043   #define STEPPER_0_IO_0 IO_PA24
00044   #define STEPPER_0_IO_1 IO_PA05
00045   #define STEPPER_0_IO_2 IO_PA06
00046   #define STEPPER_0_IO_3 IO_PA02
00047   #define STEPPER_1_IO_0 IO_PB25
00048   #define STEPPER_1_IO_1 IO_PA25
00049   #define STEPPER_1_IO_2 IO_PA26
00050   #define STEPPER_1_IO_3 IO_PB23
00051 #endif
00052 
00053 #define STEPPER_COUNT 2
00054 
00055 typedef struct StepperControlS
00056 {
00057   int users;
00058   unsigned int bipolar : 1;
00059   unsigned int halfStep : 1;
00060   int speed;
00061   int duty;
00062   int acceleration;
00063   int positionRequested;
00064   int position;
00065   int io[ 4 ];  
00066   unsigned timerRunning : 1;
00067   FastTimerEntry fastTimerEntry;
00068 } StepperControl;
00069 
00070 typedef struct StepperS
00071 {
00072   int users;
00073   StepperControl* control[ STEPPER_COUNT ];
00074 } Stepper_;
00075 
00076 void Stepper_IRQCallback( int id );
00077 
00078 static int Stepper_Start( int index );
00079 static int Stepper_Stop( int index );
00080 static int Stepper_Init( void );
00081 static int Stepper_GetIo( int index, int io );
00082 static void Stepper_SetDetails( StepperControl* s );
00083 static void Stepper_SetUnipolarHalfStepOutput( StepperControl *s, int position );
00084 static void Stepper_SetUnipolarOutput( StepperControl *s, int position );
00085 static void Stepper_SetBipolarOutput( StepperControl *s, int position );
00086 static void Stepper_SetBipolarHalfStepOutput( StepperControl *s, int position );
00087 
00088 void Stepper_SetOn( int index, int* portAOn, int* portBOn );
00089 void Stepper_SetOff( int index, int* portAOff, int* portBOff );
00090 void Stepper_SetAll( int portAOn, int portBOn, int portAOff, int portBOff );
00091 
00092 Stepper_* Stepper;
00093 
00094 /** \defgroup Stepper Stepper
00095   The Stepper Motor subsystem provides speed and position control for one or two stepper motors.
00096   Up to 2 stepper motors can be controlled with the Make Application Board.
00097   Specify settings for your stepper motor by setting whether it's:
00098   - bipolar or unipolar
00099   - normal of half-stepping
00100   
00101   \section Positioning
00102   You can generally use the stepper motor in 2 modes - \b absolute positioning or \b relative positioning.
00103 
00104   For absolute positioning, call Stepper_SetPositionRequested() with the desired position, and the motor will move there.
00105   You can read back the stepper's position at any point along the way to determine where it is at a given moment.  The board
00106   keeps an internal count of how many steps the motor has taken in order to keep track of where it is.
00107 
00108   For relative positioning, use Stepper_Step( ) to simply move a number of steps from the current position.
00109   
00110   See the <a href="http://www.makingthings.com/documentation/how-to/stepper-motor">Stepper Motor how-to</a>
00111   for more detailed info on hooking up a stepper motor to the Make Controller.
00112 * \ingroup Libraries
00113 * @{
00114 */
00115 
00116 /**
00117   Sets whether the specified Stepper is active.
00118   @param index An integer specifying which stepper (0 or 1).
00119   @param state An integer specifying the active state - 1 (active) or 0 (inactive).
00120   @return Zero on success.
00121   
00122   \b Example
00123   \code
00124   // enable stepper 1
00125   Stepper_SetActive(1, 1);
00126   \endcode
00127 */
00128 int Stepper_SetActive( int index, int state )
00129 {
00130   if ( index < 0 || index >= STEPPER_COUNT )
00131     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00132 
00133   if ( state )
00134   {
00135     if( Stepper == NULL ) // if our subsystem has not been fired up
00136     {
00137       int retVal = Stepper_Init( );
00138       if( retVal != CONTROLLER_OK )
00139         return retVal;
00140     }
00141 
00142     if( Stepper->control[ index ] == NULL ) // if this particular stepper has not been fired up
00143     {
00144       Stepper->control[ index ] = MallocWait( sizeof( StepperControl ), 100 );
00145       Stepper->control[ index ]->users = 0;
00146       if( Stepper_Start( index ) != CONTROLLER_OK )
00147         return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00148     }
00149 
00150     if( Stepper->control[ index ] != NULL )
00151       return CONTROLLER_OK;
00152     else
00153       return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00154   }
00155   else
00156     return Stepper_Stop( index );
00157 }
00158 
00159 /**
00160   Check whether the stepper is active or not
00161   @param index An integer specifying which stepper (0-1).
00162   @return State - 1 (active) or 0 (inactive).
00163   
00164   \b Example
00165   \code
00166   if( Stepper_GetActive(1) )
00167   {
00168     // Stepper 1 is active
00169   }
00170   else
00171   {
00172     // Stepper 1 is inactive
00173   }
00174   \endcode
00175 */
00176 int Stepper_GetActive( int index )
00177 {
00178   if ( index < 0 || index >= STEPPER_COUNT )
00179     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00180 
00181   if( Stepper == NULL )
00182     return 0;
00183   else
00184     return Stepper->control[ index ] != NULL;
00185 }
00186 
00187 /** 
00188   Set the position of the specified stepper motor.
00189   Note that this will not ask the stepper to move.  It will simply update
00190   the position that the stepper thinks its at.  To move the stepper, see
00191   Stepper_SetPositionRequested() or Stepper_Step().
00192   @param index An integer specifying which stepper (0 or 1).
00193   @param position An integer specifying the stepper position.
00194   @return status (0 = OK).
00195   
00196   \b Example
00197   \code
00198   // reset stepper 1 to call its current position 0
00199   Stepper_SetPosition(1, 0);
00200   \endcode
00201 */
00202 int Stepper_SetPosition( int index, int position )
00203 {
00204   if ( index < 0 || index >= STEPPER_COUNT )
00205     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00206 
00207   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00208     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00209 
00210   StepperControl* s = Stepper->control[ index ]; 
00211   
00212   DisableFIQFromThumb();
00213   s->position = position;
00214   s->positionRequested = position;
00215   EnableFIQFromThumb();
00216 
00217   Stepper_SetDetails( s );
00218 
00219   return CONTROLLER_OK;
00220 }
00221 
00222 /** 
00223   Set the destination position for a stepper motor.
00224   This will start the stepper moving the given number of
00225   steps at the current speed, as set by Stepper_SetSpeed().
00226   
00227   While it's moving, you can call Stepper_GetPosition() to read
00228   its current position.
00229   @param index An integer specifying which stepper (0 or 1).
00230   @param positionRequested An integer specifying the desired stepper position.
00231   @return status (0 = OK).
00232   
00233   \b Example
00234   \code
00235   // start moving stepper 0 1500 steps
00236   Stepper_SetPositionRequested(0, 1500);
00237   \endcode
00238 */
00239 int Stepper_SetPositionRequested( int index, int positionRequested )
00240 {
00241   if ( index < 0 || index >= STEPPER_COUNT )
00242     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00243 
00244   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00245     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00246 
00247   StepperControl* s = Stepper->control[ index ]; 
00248   DisableFIQFromThumb();
00249   s->positionRequested = positionRequested;
00250   EnableFIQFromThumb();
00251 
00252   Stepper_SetDetails( s );
00253 
00254   return CONTROLLER_OK;
00255 }
00256 
00257 /** 
00258   Set the speed at which a stepper will move.
00259   This is a number of ms per step, rather than the more common steps per second.  
00260   Arranging it this way makes it easier to express as an integer.  
00261   Fastest speed is 1ms / step (1000 steps per second) and slowest is many seconds.
00262   @param index An integer specifying which stepper (0 or 1).
00263   @param speed An integer specifying the stepper speed in ms per step
00264   @return status (0 = OK).
00265   
00266   \b Example
00267   \code
00268   // set the speed to 1ms / step (1000 steps per second)
00269   Stepper_SetSpeed(0, 1);
00270   \endcode
00271 */
00272 int Stepper_SetSpeed( int index, int speed )
00273 {
00274   if ( index < 0 || index >= STEPPER_COUNT )
00275     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00276 
00277   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00278     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00279   
00280   StepperControl* s = Stepper->control[ index ]; 
00281 
00282   s->speed = speed * 1000;
00283 
00284   DisableFIQFromThumb();
00285   FastTimer_SetTime( &s->fastTimerEntry, s->speed );
00286   EnableFIQFromThumb();
00287 
00288   Stepper_SetDetails( s );
00289 
00290   return CONTROLLER_OK;
00291 }
00292 
00293 /** 
00294   Get the speed at which a stepper will move.
00295   Read the value previously set for the speed parameter.
00296   @param index An integer specifying which stepper (0 or 1).
00297   @return The speed (0 - 1023), or 0 on error.
00298   
00299   \b Example
00300   \code
00301   int step0_speed = Stepper_GetSpeed(0);
00302   // now step0_speed has the speed of stepper 0
00303   \endcode
00304 */
00305 int Stepper_GetSpeed( int index )
00306 {
00307   if ( index < 0 || index >= STEPPER_COUNT )
00308     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00309 
00310   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00311     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00312 
00313   return Stepper->control[ index ]->speed;
00314 }
00315 
00316 /** 
00317   Read the current position of a stepper motor.
00318   @param index An integer specifying which stepper (0 or 1).
00319   @return The position, 0 on error.
00320   
00321   \b Example
00322   \code
00323   int step0_pos = Stepper_GetPosition(0);
00324   // now step0_pos has the current position of stepper 0
00325   \endcode
00326 */
00327 int Stepper_GetPosition( int index )
00328 {
00329   if ( index < 0 || index >= STEPPER_COUNT )
00330     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00331 
00332   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00333     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00334 
00335   return Stepper->control[ index ]->position;
00336 }
00337 
00338 /** 
00339   Read the destination position of a stepper motor.
00340   This indicates where the stepper is ultimately headed.  To see
00341   where it actually is, see Stepper_GetPosition().
00342   @param index An integer specifying which stepper (0 or 1).
00343   @return The position and 0 on error
00344   
00345   \b Example
00346   \code
00347   int step1_destination = Stepper_GetPositionRequested(1);
00348   // step1_destination has the requested position for stepper 1
00349   \endcode
00350 */
00351 int Stepper_GetPositionRequested( int index )
00352 {
00353   if ( index < 0 || index >= STEPPER_COUNT )
00354     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00355 
00356   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00357     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00358 
00359   return Stepper->control[ index ]->positionRequested;
00360 }
00361 
00362 /** 
00363   Simply take a number of steps from wherever the motor is currently positioned.
00364   This function will move the motor a given number of steps from the current position.
00365   @param index An integer specifying which stepper (0 or 1).
00366   @param steps An integer specifying the number of steps.  Can be negative to go in reverse.
00367   @return status (0 = OK).
00368   
00369   \b Example
00370   \code
00371   // take 1200 steps forward from our current position
00372   Stepper_Step(0, 1200);
00373   \endcode
00374 */
00375 int Stepper_Step( int index, int steps )
00376 {
00377   if ( index < 0 || index >= STEPPER_COUNT )
00378     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00379 
00380   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00381     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00382 
00383   StepperControl* s = Stepper->control[ index ]; 
00384   DisableFIQFromThumb();
00385   s->positionRequested = (s->position + steps);
00386   EnableFIQFromThumb();
00387 
00388   Stepper_SetDetails( s );
00389   return CONTROLLER_OK;
00390 }
00391 
00392 /** 
00393   Set the duty - from 0 to 1023.  The default is for 100% power (1023).
00394   @param index An integer specifying which stepper (0 or 1).
00395   @param duty An integer specifying the stepper duty (0 - 1023).
00396   @return status (0 = OK).
00397   
00398   \b Example
00399   \code
00400   // set stepper 0 to half power
00401   Stepper_SetDuty(0, 512);
00402   \endcode
00403 */
00404 int Stepper_SetDuty( int index, int duty )
00405 {
00406   if ( index < 0 || index >= STEPPER_COUNT )
00407     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00408 
00409   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00410     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00411 
00412   StepperControl* s = Stepper->control[ index ]; 
00413   s->duty = duty;
00414 
00415   // Fire the PWM's up
00416   int pwm = index * 2;
00417   Pwm_Set( pwm, duty );
00418   Pwm_Set( pwm + 1, duty );
00419 
00420   return CONTROLLER_OK;
00421 }
00422 
00423 /** 
00424   Get the duty 
00425   Read the value previously set for the duty.
00426   @param index An integer specifying which stepper (0 or 1).
00427   @return The duty (0 - 1023), or 0 on error.
00428   
00429   \b Example
00430   \code
00431   int step1_duty = Stepper_GetDuty(1);
00432   // step1_duty has the current duty for stepper 1
00433   \endcode
00434 */
00435 int Stepper_GetDuty( int index )
00436 {
00437   if ( index < 0 || index >= STEPPER_COUNT )
00438     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00439 
00440   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00441     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00442 
00443   return Stepper->control[ index ]->duty;
00444 }
00445 
00446 /** 
00447   Declare whether the stepper is bipolar or not.  
00448   Default is bipolar.
00449   @param index An integer specifying which stepper (0 or 1).
00450   @param bipolar An integer 1 for bipolar, 0 for unipolar
00451   @return status (0 = OK).
00452   
00453   \b Example
00454   \code
00455   // set stepper 1 to unipolar
00456   Stepper_SetBipolar(1, 0);
00457   \endcode
00458 */
00459 int Stepper_SetBipolar( int index, int bipolar )
00460 {
00461   if ( index < 0 || index >= STEPPER_COUNT )
00462     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00463 
00464   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00465     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00466 
00467   StepperControl* s = Stepper->control[ index ]; 
00468   s->bipolar = bipolar;
00469 
00470   return CONTROLLER_OK;
00471 }
00472 
00473 /** 
00474   Get the bipolar setting
00475   Read the value previously set for bipolar.
00476   @param index An integer specifying which stepper (0 or 1).
00477   @return 1 for bipolar or 0 for unipolar.
00478   
00479   \b Example
00480   \code
00481   if( Stepper_GetBipolar(1) )
00482   {
00483     // stepper 1 is bipolar
00484   }
00485   else
00486   {
00487     // stepper 1 is unipolar
00488   }
00489   \endcode
00490 */
00491 int Stepper_GetBipolar( int index )
00492 {
00493   if ( index < 0 || index >= STEPPER_COUNT )
00494     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00495 
00496   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00497     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00498 
00499   return Stepper->control[ index ]->bipolar;
00500 }
00501 
00502 /** 
00503   Declare whether the stepper is in half stepping mode or not.  
00504   Default is not - i.e. in full step mode.
00505   @param index An integer specifying which stepper (0 or 1).
00506   @param halfStep An integer specifying 1 for half step, 0 for full step
00507   @return status (0 = OK).
00508   
00509   \b Example
00510   \code
00511   // set stepper 1 to half step mode
00512   Stepper_SetHalfStep(1, 1);
00513   \endcode
00514 */
00515 int Stepper_SetHalfStep( int index, int halfStep )
00516 {
00517   if ( index < 0 || index >= STEPPER_COUNT )
00518     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00519 
00520   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00521     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00522 
00523   StepperControl* s = Stepper->control[ index ]; 
00524   s->halfStep = halfStep;
00525 
00526   return CONTROLLER_OK;
00527 }
00528 
00529 /** 
00530   Read whether the stepper is in half stepping mode or not.
00531   @param index An integer specifying which stepper (0 or 1).
00532   @return the HalfStep setting.
00533   
00534   \b Example
00535   \code
00536   if( Stepper_GetHalfStep(1) )
00537   {
00538     // stepper 1 is in half step mode
00539   }
00540   else
00541   {
00542     // stepper 1 is in full step mode
00543   }
00544   \endcode
00545 */
00546 int Stepper_GetHalfStep( int index )
00547 {
00548   if ( index < 0 || index >= STEPPER_COUNT )
00549     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00550 
00551   if ( Stepper_SetActive( index, 1 ) != CONTROLLER_OK )
00552     return CONTROLLER_ERROR_SYSTEM_NOT_ACTIVE;
00553 
00554   return Stepper->control[ index ]->halfStep;
00555 }
00556 
00557 
00558 /** @}
00559 */
00560 
00561 int Stepper_Start( int index )
00562 {
00563   static int status; // why does this not seem to work at -O2 when this is not declared as static?
00564 
00565   if ( index < 0 || index >= STEPPER_COUNT )
00566     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00567 
00568   StepperControl* sc = Stepper->control[ index ];
00569   if ( sc->users++ == 0 )
00570   {
00571     status = Pwm_Start( index * 2 );
00572     if ( status != CONTROLLER_OK )
00573     {
00574       sc->users--;
00575       Stepper->users--;
00576       return status;
00577     }
00578 
00579     status = Pwm_Start( index * 2 + 1 );
00580     if ( status != CONTROLLER_OK )
00581     {
00582       Pwm_Stop( index * 2 );
00583       sc->users--;
00584       Stepper->users--;
00585       return status;
00586     }
00587 
00588     // Fire the PWM's up
00589     sc->duty = 1023;
00590 
00591     int pwm = index * 2;
00592     Pwm_Set( pwm, sc->duty );
00593     Pwm_Set( pwm + 1, sc->duty );
00594 
00595     // Get IO's
00596     int i;
00597     for ( i = 0; i < 4; i++ )
00598     {
00599       int io = Stepper_GetIo( index, i );      
00600       sc->io[ i ] = io;
00601         
00602       // Try to lock the stepper output
00603       status = Io_Start( io, true );
00604       if ( status != CONTROLLER_OK )
00605       {
00606         // Damn - unlock any that we did get
00607         int j;
00608         for ( j = 0; j < i; j++ )
00609           Io_Stop( sc->io[ j ] );
00610 
00611         Pwm_Stop( pwm );
00612         Pwm_Stop( pwm + 1 );
00613 
00614         Stepper->users--;
00615         sc->users--;
00616         return status;
00617       }
00618       Io_SetPio( io, true );
00619       Io_SetValue( io, true );
00620       Io_SetDirection( io, IO_OUTPUT );
00621     }
00622 
00623     DisableFIQFromThumb();
00624     sc->position = 0;
00625     sc->positionRequested = 0;
00626     sc->speed = 10;
00627     sc->timerRunning = 0;
00628     sc->halfStep = false;
00629     sc->bipolar = true;
00630     EnableFIQFromThumb();
00631 
00632     FastTimer_InitializeEntry( &sc->fastTimerEntry, Stepper_IRQCallback, index, sc->speed * 1000, true );
00633     Stepper->users++;
00634   }
00635 
00636   return CONTROLLER_OK;
00637 }
00638 
00639 int Stepper_Stop( int index )
00640 {
00641   if ( index < 0 || index >= STEPPER_COUNT || Stepper == NULL )
00642     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00643 
00644   if( Stepper->control[ index ] == NULL )
00645     return CONTROLLER_OK;
00646 
00647   StepperControl* s = Stepper->control[ index ]; 
00648 
00649   if ( s->users <= 0 )
00650     return CONTROLLER_ERROR_TOO_MANY_STOPS;
00651 
00652   if ( --s->users == 0 )
00653   {
00654     if ( s->timerRunning )
00655     {
00656       DisableFIQFromThumb();
00657       FastTimer_Cancel( &s->fastTimerEntry );
00658       EnableFIQFromThumb();
00659     }
00660 
00661     int i;
00662     for ( i = 0; i < 4; i++ )
00663     {
00664       int io = s->io[ i ];
00665       Io_SetValue( io, false );
00666       Io_Stop( io );
00667     }
00668  
00669     int pwm = index * 2;
00670     Pwm_Stop( pwm );
00671     Pwm_Stop( pwm + 1 );
00672 
00673     Free( s );
00674     s = NULL;
00675 
00676     if ( --Stepper->users == 0 )
00677     {
00678       Free( Stepper );
00679       Stepper = NULL;
00680     }
00681   }
00682 
00683   return CONTROLLER_OK;
00684 }
00685 
00686 
00687 int Stepper_GetIo( int stepperIndex, int ioIndex )
00688 {
00689   int io = -1;
00690   switch ( stepperIndex )
00691   {
00692     case 0:
00693       switch ( ioIndex )
00694       {
00695         case 0:
00696           io = STEPPER_0_IO_0;
00697           break;
00698         case 1:
00699           io = STEPPER_0_IO_1;
00700           break;
00701         case 2:
00702           io = STEPPER_0_IO_2;
00703           break;
00704         case 3:
00705           io = STEPPER_0_IO_3;
00706           break;
00707       }
00708       break;
00709     case 1:
00710       switch ( ioIndex )
00711       {
00712         case 0:
00713           io = STEPPER_1_IO_0;
00714           break;
00715         case 1:
00716           io = STEPPER_1_IO_1;
00717           break;
00718         case 2:
00719           io = STEPPER_1_IO_2;
00720           break;
00721         case 3:
00722           io = STEPPER_1_IO_3;
00723           break;
00724       }
00725       break;
00726   }
00727   return io;
00728 }
00729 
00730 int Stepper_Init()
00731 {
00732   if( Stepper == NULL )
00733   {
00734     Stepper = MallocWait( sizeof( Stepper_ ), 100 );
00735     Stepper->users = 0;
00736     int i;
00737     for( i = 0; i < STEPPER_COUNT; i++ )
00738       Stepper->control[ i ] = NULL;
00739   }
00740   // otherwise, we're all set.
00741   return CONTROLLER_OK;
00742 }
00743 
00744 void Stepper_IRQCallback( int id )
00745 {
00746   if(id < 0 || id > 1)
00747     return;
00748   StepperControl* s = Stepper->control[ id ]; 
00749 
00750   if ( s->position < s->positionRequested )
00751     s->position++;
00752   if ( s->position > s->positionRequested )
00753     s->position--;
00754 
00755   if ( s->bipolar )
00756   {
00757     if ( s->halfStep )
00758       Stepper_SetBipolarHalfStepOutput( s, s->position );
00759     else
00760       Stepper_SetBipolarOutput( s, s->position );
00761   }
00762   else
00763   {
00764     if ( s->halfStep ) 
00765       Stepper_SetUnipolarHalfStepOutput( s, s->position );
00766     else
00767       Stepper_SetUnipolarOutput( s, s->position );
00768   }
00769 
00770   if ( s->position == s->positionRequested )
00771   {
00772     FastTimer_Cancel( &s->fastTimerEntry );
00773     s->timerRunning = false;
00774   }
00775 }
00776 
00777 void Stepper_SetDetails( StepperControl* s )
00778 {
00779   if ( !s->timerRunning && ( s->position != s->positionRequested ) && ( s->speed != 0 ) )
00780   {
00781     s->timerRunning = true;
00782     DisableFIQFromThumb();
00783     FastTimer_Set( &s->fastTimerEntry );
00784     EnableFIQFromThumb();
00785   }
00786   else
00787   {
00788     if ( ( s->timerRunning ) && ( ( s->position == s->positionRequested ) || ( s->speed == 0 ) ) )
00789     {
00790       DisableFIQFromThumb();
00791       FastTimer_Cancel( &s->fastTimerEntry );
00792       EnableFIQFromThumb();
00793       s->timerRunning = false;
00794     }
00795   }
00796 }
00797 
00798 void Stepper_SetUnipolarHalfStepOutput( StepperControl *s, int position )
00799 {
00800   //int output = position % 8;
00801   int output = position & 0x7;
00802 
00803   int* iop = s->io;
00804 
00805   int portAOn = 0;
00806   int portBOn = 0;
00807   int portAOff = 0;
00808   int portBOff = 0;
00809 
00810   switch ( output )
00811   {
00812     case -1:
00813       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00814       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00815       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00816       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00817       break;
00818     case 0:
00819       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00820       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00821       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00822       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00823       break;
00824     case 1:
00825       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00826       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00827       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00828       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00829       break;
00830     case 2:
00831       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00832       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00833       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00834       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00835       break;
00836     case 3:
00837       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00838       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00839       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00840       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00841       break;
00842     case 4:
00843       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00844       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00845       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00846       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00847       break;
00848     case 5:
00849       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00850       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00851       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00852       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00853       break;
00854     case 6:
00855       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00856       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00857       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00858       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00859       break;
00860     case 7:
00861       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00862       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00863       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00864       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00865       break;
00866   }  
00867 
00868   Stepper_SetAll( portAOn, portBOn, portAOff, portBOff );
00869 }
00870 
00871 void Stepper_SetUnipolarOutput( StepperControl *s, int position )
00872 {
00873   //int output = position % 4;
00874   int output = position & 0x3;
00875   int* iop = s->io;
00876 
00877   int portAOn = 0;
00878   int portBOn = 0;
00879   int portAOff = 0;
00880   int portBOff = 0;
00881 
00882   switch ( output )
00883   {
00884     case -1:
00885       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00886       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00887       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00888       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00889       break;
00890     case 0:
00891       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00892       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00893       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00894       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00895       break;
00896     case 1:
00897       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00898       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00899       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00900       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00901       break;
00902     case 2:
00903       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00904       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00905       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00906       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00907       break;
00908     case 3:
00909       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00910       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00911       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00912       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00913       break;
00914   }  
00915   Stepper_SetAll( portAOn, portBOn, portAOff, portBOff );
00916 }
00917 
00918 void Stepper_SetBipolarHalfStepOutput( StepperControl *s, int position )
00919 {
00920   //int output = position % 8;
00921   int output = position & 0x7;
00922   int* iop = s->io;
00923 
00924   int portAOn = 0;
00925   int portBOn = 0;
00926   int portAOff = 0;
00927   int portBOff = 0;
00928 
00929   switch ( output )
00930   {
00931     case -1:
00932       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00933       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00934       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00935       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00936       break;
00937     case 0:
00938       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00939       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00940       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00941       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00942       break;
00943     case 1:
00944       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00945       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00946       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00947       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00948       break;
00949     case 2:
00950       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00951       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00952       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00953       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00954       break;
00955     case 3:
00956       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00957       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00958       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00959       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00960       break;
00961     case 4:
00962       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00963       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00964       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00965       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00966       break;
00967     case 5:
00968       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00969       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00970       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00971       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00972       break;
00973     case 6:
00974       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00975       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00976       Stepper_SetOff( *iop++, &portAOff, &portBOff );
00977       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00978       break;
00979     case 7:
00980       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00981       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00982       Stepper_SetOff( *iop++, &portAOff, &portBOff );      
00983       Stepper_SetOn( *iop++, &portAOn, &portBOn );
00984       break;
00985   }  
00986 
00987   Stepper_SetAll( portAOn, portBOn, portAOff, portBOff );
00988 }
00989 
00990 void Stepper_SetBipolarOutput( StepperControl *s, int position )
00991 {
00992   //int output = position % 4; // work around % bug - negative numbers not handled properly
00993   int output = position & 0x3;
00994   int* iop = s->io;
00995 
00996   int portAOn = 0;
00997   int portBOn = 0;
00998   int portAOff = 0;
00999   int portBOff = 0;
01000 
01001   // This may be the least efficient code I have ever written
01002   switch ( output )
01003   {
01004     case -1:
01005       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01006       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01007       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01008       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01009       break;
01010     case 0:
01011       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01012       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01013       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01014       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01015       break;
01016     case 1:
01017       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01018       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01019       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01020       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01021       break;
01022     case 2:
01023       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01024       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01025       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01026       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01027       break;
01028     case 3:
01029       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01030       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01031       Stepper_SetOff( *iop++, &portAOff, &portBOff );
01032       Stepper_SetOn( *iop++, &portAOn, &portBOn );
01033       break;
01034   }  
01035   Stepper_SetAll( portAOn, portBOn, portAOff, portBOff );
01036 }
01037 
01038 void Stepper_SetOn( int index, int* portAOn, int* portBOn )
01039 {
01040   int mask = 1 << ( index & 0x1F );
01041   if ( index < 32 )
01042     *portAOn |= mask;
01043   else
01044     *portBOn |= mask;
01045 }
01046 
01047 void Stepper_SetOff( int index, int* portAOff, int* portBOff )
01048 {
01049   int mask = 1 << ( index & 0x1F );
01050   if ( index < 32 )
01051     *portAOff |= mask;
01052   else
01053     *portBOff |= mask;
01054 }
01055 
01056 void Stepper_SetAll( int portAOn, int portBOn, int portAOff, int portBOff )
01057 {
01058   AT91C_BASE_PIOA->PIO_SODR = portAOn;
01059   AT91C_BASE_PIOB->PIO_SODR = portBOn;
01060   AT91C_BASE_PIOA->PIO_CODR = portAOff;
01061   AT91C_BASE_PIOB->PIO_CODR = portBOff;
01062 }
01063 
01064 #ifdef OSC // defined in config.h
01065 
01066 /** \defgroup StepperOSC Stepper - OSC
01067   \ingroup OSC
01068   Control Stepper motors with the Application Board via OSC.
01069   Specify settings for your stepper motor by setting whether it's:
01070   - bipolar or unipolar
01071   - normal of half-stepping
01072 
01073   You can generally use the stepper motor in 2 modes - \b absolute positioning or \b relative positioning.
01074 
01075   For absolute positioning, set \b positionrequested with the desired position, and the motor will move there.
01076   You can read back the stepper's \b position property at any point along the way to determine where it is at a given moment.  The board
01077   keeps an internal count of how many steps the motor has taken in order to keep track of where it is.
01078 
01079   For relative positioning, use the \b step property to simply move a number of steps from the current position.
01080   
01081   \section devices Devices
01082   There are 2 Stepper controllers available on the Application Board, numbered 0 & 1.
01083   See the Stepper section in the Application Board user's guide for more information
01084   on hooking steppers up to the board.
01085   
01086   \section properties Properties
01087   Each stepper controller has eight properties:
01088   - position
01089   - positionrequested
01090   - speed
01091   - duty
01092   - bipolar
01093   - halfstep
01094   - step
01095   - active
01096 
01097   \par Step
01098   The \b step property simply tells the motor to take a certain number of steps.
01099   This is a write-only value.
01100   \par
01101   To take 1000 steps with the first stepper, send the message
01102   \verbatim /stepper/0/step 1000\endverbatim
01103   
01104   \par Position
01105   The \b position property corresponds to the current step position of the stepper motor
01106   This value can be both read and written.  Writing this value changes where the motor thinks it is.
01107   The initial value of this parameter is 0.
01108   \par
01109   To set the first stepper to step position 10000, send the message
01110   \verbatim /stepper/0/position 10000\endverbatim
01111   Leave the argument value off to read the position of the stepper:
01112   \verbatim /stepper/0/position \endverbatim
01113 
01114   \par PositionRequested
01115   The \b positionrequested property describes the desired step position of the stepper motor
01116   This value can be both read and written.  Writing this value changes the motor's destination.
01117   \par
01118   To set the first stepper to go to position 10000, send the message
01119   \verbatim /stepper/0/positionrequested 10000\endverbatim
01120   Leave the argument value off to read the last requested position of the stepper:
01121   \verbatim /stepper/0/positionrequested \endverbatim
01122 
01123   \par Speed
01124   The \b speed property corresponds to the speed with which the stepper responds to changes 
01125   of position.  This value is the number of milliseconds between each step.  So, a speed of one
01126   would be a step every millisecond, or 1000 steps a second.  
01127   \par
01128   Note that not all stepper motors can be stepped quite that fast.  If you find your stepper motor acting strangely, 
01129   experiment with slowing down the speed a bit.
01130   \par
01131   To set the speed of the first stepper to step at 100ms per step, send a message like
01132   \verbatim /stepper/0/speed 100 \endverbatim
01133   Adjust the argument value to one that suits your application.\n
01134   Leave the argument value off to read the speed of the stepper:
01135   \verbatim /stepper/0/speed \endverbatim
01136   
01137   \par Duty
01138   The \b duty property corresponds to the how much of the power supply is to be sent to the
01139   stepper.  This is handy for when the stepper is static and not being required to perform too
01140   much work and reducing its power helps reduce heat dissipation.
01141   This value can be both read and written, and the range of values is 0 - 1023.  A duty of 0
01142   means the stepper gets no power, and the value of 1023 means the stepper gets full power.  
01143   \par
01144   To set the duty of the first stepper to 500, send a message like
01145   \verbatim /stepper/0/duty 500 \endverbatim
01146   Adjust the argument value to one that suits your application.\n
01147   Leave the argument value off to read the duty of the stepper:
01148   \verbatim /stepper/0/duty \endverbatim
01149 
01150   \par Bipolar
01151   The \b bipolar property is set to the style of stepper being used.  A value of 1 specifies bipolar
01152   (the default) and 0 specifies a unipolar stepper.
01153   This value can be both read and written.
01154 
01155   \par HalfStep
01156   The \b halfstep property controls whether the stepper is being half stepped or not.  A 0 here implies full stepping
01157   (the default) and 1 implies a half stepping.
01158   This value can be both read and written.
01159 
01160   \par Active
01161   The \b active property corresponds to the active state of the stepper.
01162   If the stepper is set to be active, no other tasks will be able to
01163   write to the same I/O lines.  If you're not seeing appropriate
01164   responses to your messages to a stepper, check the whether it's 
01165   locked by sending a message like
01166   \verbatim /stepper/1/active \endverbatim
01167 */
01168 
01169 #include "osc.h"
01170 #include "string.h"
01171 #include "stdio.h"
01172 
01173 // Need a list of property names
01174 // MUST end in zero
01175 static char* StepperOsc_Name = "stepper";
01176 static char* StepperOsc_PropertyNames[] = { "active", "position", "positionrequested", 
01177                                             "speed", "duty", "halfstep", 
01178                                             "bipolar", "step", 0 }; // must have a trailing 0
01179 
01180 int StepperOsc_PropertySet( int index, int property, int value );
01181 int StepperOsc_PropertyGet( int index, int property );
01182 
01183 // Returns the name of the subsystem
01184 const char* StepperOsc_GetName( )
01185 {
01186   return StepperOsc_Name;
01187 }
01188 
01189 // Now getting a message.  This is actually a part message, with the first
01190 // part (the subsystem) already parsed off.
01191 int StepperOsc_ReceiveMessage( int channel, char* message, int length )
01192 {
01193   int status = Osc_IndexIntReceiverHelper( channel, message, length, 
01194                                            STEPPER_COUNT, StepperOsc_Name,
01195                                            StepperOsc_PropertySet, StepperOsc_PropertyGet, 
01196                                            StepperOsc_PropertyNames );
01197 
01198   if ( status != CONTROLLER_OK )
01199     return Osc_SendError( channel, StepperOsc_Name, status );
01200   return CONTROLLER_OK;
01201 }
01202 
01203 // Set the index LED, property with the value
01204 int StepperOsc_PropertySet( int index, int property, int value )
01205 {
01206   switch ( property )
01207   {
01208     case 0:
01209       Stepper_SetActive( index, value );
01210       break;
01211     case 1:
01212       Stepper_SetPosition( index, value );
01213       break;
01214     case 2:
01215       Stepper_SetPositionRequested( index, value );
01216       break;
01217     case 3:
01218       Stepper_SetSpeed( index, value );
01219       break;
01220     case 4:
01221       Stepper_SetDuty( index, value );
01222       break;
01223     case 5:
01224       Stepper_SetHalfStep( index, value );
01225       break;
01226     case 6:
01227       Stepper_SetBipolar( index, value );
01228       break;
01229     case 7: // step
01230       Stepper_Step( index, value );
01231       break;
01232   }
01233   return CONTROLLER_OK;
01234 }
01235 
01236 // Get the index LED, property
01237 int StepperOsc_PropertyGet( int index, int property )
01238 {
01239   int value = 0;
01240   switch ( property )
01241   {
01242     case 0:
01243       value = Stepper_GetActive( index );
01244       break;
01245     case 1:
01246       value = Stepper_GetPosition( index );
01247       break;
01248     case 2:
01249       value = Stepper_GetPositionRequested( index );
01250       break;
01251     case 3:
01252       value = Stepper_GetSpeed( index );
01253       break;
01254     case 4:
01255       value = Stepper_GetDuty( index );
01256       break;
01257     case 5:
01258       value = Stepper_GetHalfStep( index );
01259       break;
01260     case 6:
01261       value = Stepper_GetBipolar( index );
01262       break;
01263   }
01264   return value;
01265 }
01266 
01267 #endif
01268 
01269 

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.