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.