Provides an API software interface to TIMER2 to control upto four stepper motors.

Dependents:   Steppermotor

Committer:
AjK
Date:
Fri May 20 09:13:31 2011 +0000
Revision:
4:7b7940df7865
Parent:
3:71ab7209adb3
1.1 See ChangeLog.h

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:7393c52297ee 1 /*
AjK 0:7393c52297ee 2 Copyright (c) 2011 Andy Kirkham
AjK 0:7393c52297ee 3
AjK 0:7393c52297ee 4 Permission is hereby granted, free of charge, to any person obtaining a copy
AjK 0:7393c52297ee 5 of this software and associated documentation files (the "Software"), to deal
AjK 0:7393c52297ee 6 in the Software without restriction, including without limitation the rights
AjK 0:7393c52297ee 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
AjK 0:7393c52297ee 8 copies of the Software, and to permit persons to whom the Software is
AjK 0:7393c52297ee 9 furnished to do so, subject to the following conditions:
AjK 0:7393c52297ee 10
AjK 0:7393c52297ee 11 The above copyright notice and this permission notice shall be included in
AjK 0:7393c52297ee 12 all copies or substantial portions of the Software.
AjK 0:7393c52297ee 13
AjK 0:7393c52297ee 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
AjK 0:7393c52297ee 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
AjK 0:7393c52297ee 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AjK 0:7393c52297ee 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
AjK 0:7393c52297ee 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
AjK 0:7393c52297ee 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
AjK 0:7393c52297ee 20 THE SOFTWARE.
AjK 0:7393c52297ee 21 */
AjK 0:7393c52297ee 22
AjK 0:7393c52297ee 23 #ifndef AJK_SIMPLESTEPPERS_H
AjK 0:7393c52297ee 24 #define AJK_SIMPLESTEPPERS_H
AjK 0:7393c52297ee 25
AjK 0:7393c52297ee 26 #define SIMPLESTEPPER_F 100000
AjK 0:7393c52297ee 27 #include "LPC17xx.h"
AjK 0:7393c52297ee 28 #include "core_cm3.h"
AjK 0:7393c52297ee 29 #include <stdint.h>
AjK 0:7393c52297ee 30
AjK 0:7393c52297ee 31 #ifndef __ARMCC_VERSION
AjK 0:7393c52297ee 32 #include "SimpleStepperMbed.h"
AjK 0:7393c52297ee 33 #else
AjK 0:7393c52297ee 34 #include "mbed.h"
AjK 0:7393c52297ee 35 #endif
AjK 0:7393c52297ee 36
AjK 0:7393c52297ee 37 #include "SimpleStepperOutput.h"
AjK 0:7393c52297ee 38
AjK 0:7393c52297ee 39 namespace AjK {
AjK 0:7393c52297ee 40
AjK 0:7393c52297ee 41 // Forward reference the main controller.
AjK 0:7393c52297ee 42 class SimpleStepperController;
AjK 0:7393c52297ee 43
AjK 0:7393c52297ee 44 /** SimpleStepper
AjK 0:7393c52297ee 45 *
AjK 0:7393c52297ee 46 * SimpleStepper is a class designed to handle the pulse and direction
AjK 0:7393c52297ee 47 * signals for a stepper motor. A simple API is exposed to allow the
AjK 0:7393c52297ee 48 * setting of the pulse width and the number of pulses per second.
AjK 0:7393c52297ee 49 *
AjK 0:7393c52297ee 50 * Note, SimpleStepper uses the SimpleStepperController class to manage
AjK 0:7393c52297ee 51 * the TIMER2. SimpleStepperController and SimpleStepper take total
AjK 0:7393c52297ee 52 * control of the LPC17xx's TIMER2. Your application or other library that
AjK 3:71ab7209adb3 53 * your application uses, should <b>not</b>use TIMER2.
AjK 3:71ab7209adb3 54 *
AjK 3:71ab7209adb3 55 * This library is a software interface to the TIMER2 MATCH system. It does
AjK 3:71ab7209adb3 56 * <b>not</b> provide position and/or acceleration, PID control, etc, of
AjK 3:71ab7209adb3 57 * the motors. Your application or other library should provide the control
AjK 3:71ab7209adb3 58 * function needed to position/run your stepper motor(s).
AjK 0:7393c52297ee 59 *
AjK 3:71ab7209adb3 60 * @code
AjK 3:71ab7209adb3 61 * #include "mbed.h"
AjK 3:71ab7209adb3 62 * #include "SimpleSteppers.h"
AjK 3:71ab7209adb3 63 *
AjK 3:71ab7209adb3 64 * SimpleStepperOutput led1(LED1);
AjK 3:71ab7209adb3 65 *
AjK 3:71ab7209adb3 66 * // SimpleStepperOutput is basically the same as
AjK 3:71ab7209adb3 67 * // Mbed's DigitalOut class. However, it's more
AjK 3:71ab7209adb3 68 * // portable to other platforms without having
AjK 3:71ab7209adb3 69 * // to also port the entire Mbed library.
AjK 3:71ab7209adb3 70 * SimpleStepperOutput sdir0(p17);
AjK 3:71ab7209adb3 71 * SimpleStepperOutput sdir1(p18);
AjK 3:71ab7209adb3 72 * SimpleStepperOutput sdir2(p19);
AjK 3:71ab7209adb3 73 * SimpleStepperOutput sdir3(p20);
AjK 3:71ab7209adb3 74 *
AjK 3:71ab7209adb3 75 * // Create four steppers.
AjK 3:71ab7209adb3 76 * // Stepper0 has the pulse output on p8 and dir on p17
AjK 3:71ab7209adb3 77 * SimpleStepper stepper0(p8, &sdir0);
AjK 3:71ab7209adb3 78 * // Stepper1 has the pulse output on p7 and dir on p18
AjK 3:71ab7209adb3 79 * SimpleStepper stepper1(p7, &sdir1);
AjK 3:71ab7209adb3 80 * // Stepper2 has the pulse output on p7 and dir on p19
AjK 3:71ab7209adb3 81 * SimpleStepper stepper2(p6, &sdir2);
AjK 3:71ab7209adb3 82 * // Stepper3 has the pulse output on p7 and dir on p20
AjK 3:71ab7209adb3 83 * SimpleStepper stepper3(p5, &sdir3);
AjK 3:71ab7209adb3 84 *
AjK 3:71ab7209adb3 85 * int main() {
AjK 3:71ab7209adb3 86 *
AjK 3:71ab7209adb3 87 * // We do not need to maintain the stepper position
AjK 3:71ab7209adb3 88 * // for this simple example. This reduces the amount
AjK 3:71ab7209adb3 89 * // of work the ISR has to do.
AjK 3:71ab7209adb3 90 * stepper0.setMaintainPositionData(false);
AjK 3:71ab7209adb3 91 * stepper1.setMaintainPositionData(false);
AjK 3:71ab7209adb3 92 * stepper2.setMaintainPositionData(false);
AjK 3:71ab7209adb3 93 * stepper3.setMaintainPositionData(false);
AjK 3:71ab7209adb3 94 *
AjK 3:71ab7209adb3 95 * // Set all steppers to top speed of 5000 pulses/second.
AjK 3:71ab7209adb3 96 * stepper0.setSpeed(5000);
AjK 3:71ab7209adb3 97 * stepper1.setSpeed(5000);
AjK 3:71ab7209adb3 98 * stepper2.setSpeed(5000);
AjK 3:71ab7209adb3 99 * stepper3.setSpeed(5000);
AjK 3:71ab7209adb3 100 *
AjK 3:71ab7209adb3 101 * while(1) {
AjK 3:71ab7209adb3 102 * led1 = !led1;
AjK 3:71ab7209adb3 103 * wait(0.2);
AjK 3:71ab7209adb3 104 * }
AjK 3:71ab7209adb3 105 * }
AjK 3:71ab7209adb3 106 * @endcode
AjK 3:71ab7209adb3 107 * @see example1.h
AjK 0:7393c52297ee 108 */
AjK 0:7393c52297ee 109 class SimpleStepper {
AjK 0:7393c52297ee 110
AjK 0:7393c52297ee 111 public:
AjK 0:7393c52297ee 112 enum MAT { MAT2_0, MAT2_1, MAT2_2, MAT2_3 };
AjK 0:7393c52297ee 113 enum MATCH_OP { NothingOnMatch, ClrOnMatch, SetOnMatch, ToggleOnMatch };
AjK 0:7393c52297ee 114 enum PULSE_STATE { PulseIdle, PulseAssert, PulseDeassert };
AjK 0:7393c52297ee 115 enum STEPPER_STATE { Stopped, ConstantSpeed };
AjK 0:7393c52297ee 116
AjK 0:7393c52297ee 117 protected:
AjK 0:7393c52297ee 118 SimpleStepperController *_simpleStepperController;
AjK 0:7393c52297ee 119 SimpleStepperOutput *_direction;
AjK 0:7393c52297ee 120
AjK 0:7393c52297ee 121 PinName _pulse;
AjK 0:7393c52297ee 122 MAT _pulseMAT;
AjK 0:7393c52297ee 123 uint32_t _operShift;
AjK 0:7393c52297ee 124 uint32_t _pMR;
AjK 0:7393c52297ee 125 uint32_t _match_shift;
AjK 0:7393c52297ee 126 uint32_t _EMmask;
AjK 0:7393c52297ee 127 uint32_t _EMCshift;
AjK 0:7393c52297ee 128 int _pulseLen;
AjK 0:7393c52297ee 129 int _pulseSense;
AjK 0:7393c52297ee 130 int _directionSense;
AjK 0:7393c52297ee 131 int _commandSpeed;
AjK 0:7393c52297ee 132 int64_t _pulseCounter;
AjK 0:7393c52297ee 133 int64_t _pulseWrapPos;
AjK 0:7393c52297ee 134 int64_t _pulseWrapNeg;
AjK 0:7393c52297ee 135 uint32_t _currentMatch;
AjK 0:7393c52297ee 136
AjK 4:7b7940df7865 137 volatile int _steps_per_second;
AjK 4:7b7940df7865 138
AjK 0:7393c52297ee 139 bool _maintainPositionData;
AjK 0:7393c52297ee 140
AjK 0:7393c52297ee 141 PULSE_STATE _pulseState;
AjK 0:7393c52297ee 142
AjK 0:7393c52297ee 143 STEPPER_STATE _stepperState;
AjK 0:7393c52297ee 144
AjK 0:7393c52297ee 145 void init(void);
AjK 0:7393c52297ee 146
AjK 0:7393c52297ee 147 void isr(uint32_t);
AjK 0:7393c52297ee 148
AjK 0:7393c52297ee 149 void next_step(void);
AjK 0:7393c52297ee 150
AjK 0:7393c52297ee 151 public:
AjK 0:7393c52297ee 152 friend class SimpleStepperController;
AjK 0:7393c52297ee 153
AjK 0:7393c52297ee 154 /** Constructor
AjK 0:7393c52297ee 155 *
AjK 0:7393c52297ee 156 * PinName pulse can be p5, p6, p7 or p8
AjK 0:7393c52297ee 157 * SimpleStepperOutput *direction is a pointer to an output.
AjK 0:7393c52297ee 158 *
AjK 0:7393c52297ee 159 * @param PinName The output for the pulse output.
AjK 0:7393c52297ee 160 * @param SimpleStepperOutput *direction The output pin for direction control
AjK 0:7393c52297ee 161 */
AjK 0:7393c52297ee 162 SimpleStepper(PinName pulse, SimpleStepperOutput *direction = 0);
AjK 0:7393c52297ee 163
AjK 0:7393c52297ee 164 /** Constructor
AjK 0:7393c52297ee 165 *
AjK 0:7393c52297ee 166 * PinName pulse can be p5, p6, p7 or p8
AjK 0:7393c52297ee 167 * SimpleStepperOutput *direction is a pointer to an output.
AjK 0:7393c52297ee 168 *
AjK 0:7393c52297ee 169 * @param SimpleStepperController *con A pointer to a base controller.
AjK 0:7393c52297ee 170 * @param PinName The output for the pulse output.
AjK 0:7393c52297ee 171 * @param SimpleStepperOutput *direction The output pin for direction control
AjK 0:7393c52297ee 172 */
AjK 0:7393c52297ee 173 SimpleStepper(SimpleStepperController *con, PinName pulse, SimpleStepperOutput *direction);
AjK 0:7393c52297ee 174
AjK 0:7393c52297ee 175 /** setPulseSense
AjK 0:7393c52297ee 176 *
AjK 0:7393c52297ee 177 * Set's the logic value that pulse asserted assumes. Default is 1.
AjK 0:7393c52297ee 178 *
AjK 0:7393c52297ee 179 * 1 means pulse goes from 0 to 1 and remains 1 for pulseLen time then goes to 0.
AjK 0:7393c52297ee 180 * 0 means pulse goes from 1 to 0 and remains 0 for pulseLen time then goes to 1.
AjK 0:7393c52297ee 181 *
AjK 0:7393c52297ee 182 * @param int What is the logic sense for the pulse output.
AjK 0:7393c52297ee 183 */
AjK 0:7393c52297ee 184 void setPulseSense(int i = 1) { _pulseSense = i; }
AjK 0:7393c52297ee 185
AjK 0:7393c52297ee 186 /** setDirectionSense
AjK 0:7393c52297ee 187 *
AjK 0:7393c52297ee 188 * Set's the logic value that direction forward assumes. Default is 1.
AjK 0:7393c52297ee 189 *
AjK 0:7393c52297ee 190 * 1 means that the direction output is 1 for forward and 0 for reverse.
AjK 0:7393c52297ee 191 * 0 means that the direction output is 0 for forward and 1 for reverse.
AjK 0:7393c52297ee 192 *
AjK 0:7393c52297ee 193 * Additionally, for position:-
AjK 0:7393c52297ee 194 * 1 means forward pulses are counted upwards, reverse means counted downwards.
AjK 0:7393c52297ee 195 * 0 means forward pulses are counted downwards, reverse means counted upwards.
AjK 0:7393c52297ee 196 *
AjK 0:7393c52297ee 197 * @param int What is the logic sense for the direction output.
AjK 0:7393c52297ee 198 */
AjK 0:7393c52297ee 199 void setDirectionSense(int i = 1) { _directionSense = i; }
AjK 0:7393c52297ee 200
AjK 0:7393c52297ee 201 /** setPulseLen
AjK 0:7393c52297ee 202 *
AjK 0:7393c52297ee 203 * Used to set the pulse length. Default pulse length is 50us.
AjK 0:7393c52297ee 204 * If no arg supplied returns the current pulse length.
AjK 0:7393c52297ee 205 * <b>Note,</b> the length is specified as 10us increments.
AjK 0:7393c52297ee 206 * The default is 5 which is 50us
AjK 0:7393c52297ee 207 * @param int pulse length
AjK 0:7393c52297ee 208 * @return int the value of the pulse length.
AjK 0:7393c52297ee 209 */
AjK 0:7393c52297ee 210 int setPulseLen(int i = 0) { if (i) _pulseLen = i; return _pulseLen; }
AjK 0:7393c52297ee 211
AjK 0:7393c52297ee 212 /** setSpeed
AjK 0:7393c52297ee 213 *
AjK 0:7393c52297ee 214 * Set the motor speed in pulses per second. Zero stops all motor pulses.
AjK 0:7393c52297ee 215 *
AjK 0:7393c52297ee 216 * With the default pulseLen of 50us (5 timer "ticks") the maximum speed
AjK 0:7393c52297ee 217 * that can be set is 10000 pulses per second (pps) which will produce a square
AjK 0:7393c52297ee 218 * wave with 50% duty cycle. Pushing it beyond will give a square wave a duty
AjK 0:7393c52297ee 219 * cycle shifts so that the off time between pulses becomes shorter than the on
AjK 0:7393c52297ee 220 * pulse length.
AjK 0:7393c52297ee 221 *
AjK 0:7393c52297ee 222 * The pulseLen can be adjusted using setPulseLen() down even more to eek out
AjK 0:7393c52297ee 223 * some extra bandwidth. However, you really should be checking both the datasheet
AjK 0:7393c52297ee 224 * for your stepper motor amplifier and stepper motor. Running a stepper motor at
AjK 0:7393c52297ee 225 * such high speed may have electrical and mechanical issues.
AjK 0:7393c52297ee 226 *
AjK 0:7393c52297ee 227 * The arg raw is used when you want to "sync" channels. Suppose for example you
AjK 0:7393c52297ee 228 * have the following code to set the speed to two front wheels:-
AjK 0:7393c52297ee 229 * @code
AjK 0:7393c52297ee 230 * stepper0.setSpeed(100);
AjK 0:7393c52297ee 231 * stepper1.setSpeed(100);
AjK 0:7393c52297ee 232 * @endcode
AjK 0:7393c52297ee 233 *
AjK 0:7393c52297ee 234 * The problem here is they will be a few "clock ticks" out from each other as the
AjK 0:7393c52297ee 235 * TIMER2 TC increments between the two calls. If you wanted to make two motors sync
AjK 0:7393c52297ee 236 * together you can pass in the raw value of TIMER2 TC to make both functions calculate
AjK 0:7393c52297ee 237 * the same stepp values and so sync together:-
AjK 0:7393c52297ee 238 * @code
AjK 0:7393c52297ee 239 * uint32_t i = LPC_TIM2->TC; // Capture TC.
AjK 0:7393c52297ee 240 * stepper0.setSpeed(100, i);
AjK 0:7393c52297ee 241 * stepper1.setSpeed(100, i);
AjK 0:7393c52297ee 242 * @endcode
AjK 0:7393c52297ee 243 *
AjK 0:7393c52297ee 244 * The above code forces setSpeed() to calculate both axis in sync with respect to
AjK 0:7393c52297ee 245 * a common TC value.
AjK 0:7393c52297ee 246 *
AjK 0:7393c52297ee 247 * @param int steps_per_second Number of pulses per second required.
AjK 0:7393c52297ee 248 */
AjK 0:7393c52297ee 249 void setSpeed(int steps_per_second = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 250
AjK 0:7393c52297ee 251 /** setSpeed
AjK 0:7393c52297ee 252 *
AjK 0:7393c52297ee 253 * Set the motor speed in pulses per second. Zero stops all motor pulses.
AjK 0:7393c52297ee 254 * @param double steps_per_second Number of pulses per second required.
AjK 0:7393c52297ee 255 */
AjK 0:7393c52297ee 256 void setSpeed(double steps_per_second = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 257
AjK 4:7b7940df7865 258 /** getSpeed
AjK 4:7b7940df7865 259 *
AjK 4:7b7940df7865 260 * Get the demanded motor speed in pulses per second. Zero stops all motor pulses.
AjK 4:7b7940df7865 261 * @return int steps_per_second Number of pulses per second demanded.
AjK 4:7b7940df7865 262 */
AjK 4:7b7940df7865 263 int getSpeed(void) { return _steps_per_second; }
AjK 4:7b7940df7865 264
AjK 0:7393c52297ee 265 /** setInterval
AjK 0:7393c52297ee 266 *
AjK 0:7393c52297ee 267 * Set the motor speed pulse interval. Zero stops all motor pulses.
AjK 0:7393c52297ee 268 * @param int interval
AjK 0:7393c52297ee 269 */
AjK 0:7393c52297ee 270 void setInterval(int i = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 271
AjK 0:7393c52297ee 272 /** getPosition
AjK 0:7393c52297ee 273 *
AjK 0:7393c52297ee 274 * Get the current position (the pulse counter).
AjK 0:7393c52297ee 275 *
AjK 0:7393c52297ee 276 * @return int64_t The current position as maintained by the interrupts.
AjK 0:7393c52297ee 277 */
AjK 0:7393c52297ee 278 int64_t getPosition(void) { return _pulseCounter; }
AjK 0:7393c52297ee 279
AjK 0:7393c52297ee 280 /** setWrapPos
AjK 0:7393c52297ee 281 *
AjK 0:7393c52297ee 282 * Set the value that we should wrap the pulse position counter.
AjK 0:7393c52297ee 283 * Zero (default) means no wrap occurs.
AjK 0:7393c52297ee 284 *
AjK 0:7393c52297ee 285 * @param int64_t The value to wrap to NEG at.
AjK 0:7393c52297ee 286 */
AjK 0:7393c52297ee 287 void setWrapPos(int64_t i = 0) { _pulseWrapPos = i; }
AjK 0:7393c52297ee 288
AjK 0:7393c52297ee 289 /** setWrapNeg
AjK 0:7393c52297ee 290 *
AjK 0:7393c52297ee 291 * Set the value that we should wrap the pulse position counter.
AjK 0:7393c52297ee 292 * Zero (default) means no wrap occurs.
AjK 0:7393c52297ee 293 *
AjK 0:7393c52297ee 294 * @param int64_t The value to wrap to POS at.
AjK 0:7393c52297ee 295 */
AjK 0:7393c52297ee 296 void setWrapNeg(int64_t i = 0) { _pulseWrapNeg = i; }
AjK 0:7393c52297ee 297
AjK 0:7393c52297ee 298 /** setMaintainPositionData
AjK 0:7393c52297ee 299 *
AjK 0:7393c52297ee 300 * Setting this false removes the maintainence of positional data.
AjK 0:7393c52297ee 301 * This allows the interrupt service routine to not perform these
AjK 0:7393c52297ee 302 * steps (if not required) thus making the ISR run slightly fatser.
AjK 0:7393c52297ee 303 * You might want to do this if positional data isn't required.
AjK 0:7393c52297ee 304 */
AjK 0:7393c52297ee 305 void setMaintainPositionData(bool b) { _maintainPositionData = b; }
AjK 0:7393c52297ee 306
AjK 0:7393c52297ee 307 };
AjK 0:7393c52297ee 308
AjK 0:7393c52297ee 309 class SimpleStepperController {
AjK 0:7393c52297ee 310 protected:
AjK 0:7393c52297ee 311 SimpleStepper *_stepper[4];
AjK 0:7393c52297ee 312
AjK 0:7393c52297ee 313 public:
AjK 0:7393c52297ee 314 friend class SimpleStepper;
AjK 0:7393c52297ee 315
AjK 0:7393c52297ee 316 SimpleStepperController();
AjK 0:7393c52297ee 317 ~SimpleStepperController();
AjK 0:7393c52297ee 318 void isr(void);
AjK 0:7393c52297ee 319 };
AjK 0:7393c52297ee 320
AjK 0:7393c52297ee 321 }; // namespace AjK ends
AjK 0:7393c52297ee 322
AjK 0:7393c52297ee 323 #endif