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

Dependents:   Steppermotor

Committer:
AjK
Date:
Mon May 02 10:02:18 2011 +0000
Revision:
0:7393c52297ee
Child:
1:1030a91cbf4c

        

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 0:7393c52297ee 53 * your application uses, should use TIMER2.
AjK 0:7393c52297ee 54 *
AjK 0:7393c52297ee 55 * @include example1.h
AjK 0:7393c52297ee 56 */
AjK 0:7393c52297ee 57 class SimpleStepper {
AjK 0:7393c52297ee 58
AjK 0:7393c52297ee 59 public:
AjK 0:7393c52297ee 60 enum MAT { MAT2_0, MAT2_1, MAT2_2, MAT2_3 };
AjK 0:7393c52297ee 61 enum MATCH_OP { NothingOnMatch, ClrOnMatch, SetOnMatch, ToggleOnMatch };
AjK 0:7393c52297ee 62 enum PULSE_STATE { PulseIdle, PulseAssert, PulseDeassert };
AjK 0:7393c52297ee 63 enum STEPPER_STATE { Stopped, ConstantSpeed };
AjK 0:7393c52297ee 64
AjK 0:7393c52297ee 65 protected:
AjK 0:7393c52297ee 66 SimpleStepperController *_simpleStepperController;
AjK 0:7393c52297ee 67 SimpleStepperOutput *_direction;
AjK 0:7393c52297ee 68
AjK 0:7393c52297ee 69 PinName _pulse;
AjK 0:7393c52297ee 70 MAT _pulseMAT;
AjK 0:7393c52297ee 71 uint32_t _operShift;
AjK 0:7393c52297ee 72 uint32_t _pMR;
AjK 0:7393c52297ee 73 uint32_t _match_shift;
AjK 0:7393c52297ee 74 uint32_t _EMmask;
AjK 0:7393c52297ee 75 uint32_t _EMCshift;
AjK 0:7393c52297ee 76 int _pulseLen;
AjK 0:7393c52297ee 77 int _pulseSense;
AjK 0:7393c52297ee 78 int _directionSense;
AjK 0:7393c52297ee 79 int _commandSpeed;
AjK 0:7393c52297ee 80 int64_t _pulseCounter;
AjK 0:7393c52297ee 81 int64_t _pulseWrapPos;
AjK 0:7393c52297ee 82 int64_t _pulseWrapNeg;
AjK 0:7393c52297ee 83 uint32_t _currentMatch;
AjK 0:7393c52297ee 84
AjK 0:7393c52297ee 85 bool _maintainPositionData;
AjK 0:7393c52297ee 86
AjK 0:7393c52297ee 87 PULSE_STATE _pulseState;
AjK 0:7393c52297ee 88
AjK 0:7393c52297ee 89 STEPPER_STATE _stepperState;
AjK 0:7393c52297ee 90
AjK 0:7393c52297ee 91 void init(void);
AjK 0:7393c52297ee 92
AjK 0:7393c52297ee 93 void isr(uint32_t);
AjK 0:7393c52297ee 94
AjK 0:7393c52297ee 95 void next_step(void);
AjK 0:7393c52297ee 96
AjK 0:7393c52297ee 97 public:
AjK 0:7393c52297ee 98 friend class SimpleStepperController;
AjK 0:7393c52297ee 99
AjK 0:7393c52297ee 100 /** Constructor
AjK 0:7393c52297ee 101 *
AjK 0:7393c52297ee 102 * PinName pulse can be p5, p6, p7 or p8
AjK 0:7393c52297ee 103 * SimpleStepperOutput *direction is a pointer to an output.
AjK 0:7393c52297ee 104 *
AjK 0:7393c52297ee 105 * @param PinName The output for the pulse output.
AjK 0:7393c52297ee 106 * @param SimpleStepperOutput *direction The output pin for direction control
AjK 0:7393c52297ee 107 */
AjK 0:7393c52297ee 108 SimpleStepper(PinName pulse, SimpleStepperOutput *direction = 0);
AjK 0:7393c52297ee 109
AjK 0:7393c52297ee 110 /** Constructor
AjK 0:7393c52297ee 111 *
AjK 0:7393c52297ee 112 * PinName pulse can be p5, p6, p7 or p8
AjK 0:7393c52297ee 113 * SimpleStepperOutput *direction is a pointer to an output.
AjK 0:7393c52297ee 114 *
AjK 0:7393c52297ee 115 * @param SimpleStepperController *con A pointer to a base controller.
AjK 0:7393c52297ee 116 * @param PinName The output for the pulse output.
AjK 0:7393c52297ee 117 * @param SimpleStepperOutput *direction The output pin for direction control
AjK 0:7393c52297ee 118 */
AjK 0:7393c52297ee 119 SimpleStepper(SimpleStepperController *con, PinName pulse, SimpleStepperOutput *direction);
AjK 0:7393c52297ee 120
AjK 0:7393c52297ee 121 /** setPulseSense
AjK 0:7393c52297ee 122 *
AjK 0:7393c52297ee 123 * Set's the logic value that pulse asserted assumes. Default is 1.
AjK 0:7393c52297ee 124 *
AjK 0:7393c52297ee 125 * 1 means pulse goes from 0 to 1 and remains 1 for pulseLen time then goes to 0.
AjK 0:7393c52297ee 126 * 0 means pulse goes from 1 to 0 and remains 0 for pulseLen time then goes to 1.
AjK 0:7393c52297ee 127 *
AjK 0:7393c52297ee 128 * @param int What is the logic sense for the pulse output.
AjK 0:7393c52297ee 129 */
AjK 0:7393c52297ee 130 void setPulseSense(int i = 1) { _pulseSense = i; }
AjK 0:7393c52297ee 131
AjK 0:7393c52297ee 132 /** setDirectionSense
AjK 0:7393c52297ee 133 *
AjK 0:7393c52297ee 134 * Set's the logic value that direction forward assumes. Default is 1.
AjK 0:7393c52297ee 135 *
AjK 0:7393c52297ee 136 * 1 means that the direction output is 1 for forward and 0 for reverse.
AjK 0:7393c52297ee 137 * 0 means that the direction output is 0 for forward and 1 for reverse.
AjK 0:7393c52297ee 138 *
AjK 0:7393c52297ee 139 * Additionally, for position:-
AjK 0:7393c52297ee 140 * 1 means forward pulses are counted upwards, reverse means counted downwards.
AjK 0:7393c52297ee 141 * 0 means forward pulses are counted downwards, reverse means counted upwards.
AjK 0:7393c52297ee 142 *
AjK 0:7393c52297ee 143 * @param int What is the logic sense for the direction output.
AjK 0:7393c52297ee 144 */
AjK 0:7393c52297ee 145 void setDirectionSense(int i = 1) { _directionSense = i; }
AjK 0:7393c52297ee 146
AjK 0:7393c52297ee 147 /** setPulseLen
AjK 0:7393c52297ee 148 *
AjK 0:7393c52297ee 149 * Used to set the pulse length. Default pulse length is 50us.
AjK 0:7393c52297ee 150 * If no arg supplied returns the current pulse length.
AjK 0:7393c52297ee 151 * <b>Note,</b> the length is specified as 10us increments.
AjK 0:7393c52297ee 152 * The default is 5 which is 50us
AjK 0:7393c52297ee 153 * @param int pulse length
AjK 0:7393c52297ee 154 * @return int the value of the pulse length.
AjK 0:7393c52297ee 155 */
AjK 0:7393c52297ee 156 int setPulseLen(int i = 0) { if (i) _pulseLen = i; return _pulseLen; }
AjK 0:7393c52297ee 157
AjK 0:7393c52297ee 158 /** setSpeed
AjK 0:7393c52297ee 159 *
AjK 0:7393c52297ee 160 * Set the motor speed in pulses per second. Zero stops all motor pulses.
AjK 0:7393c52297ee 161 *
AjK 0:7393c52297ee 162 * With the default pulseLen of 50us (5 timer "ticks") the maximum speed
AjK 0:7393c52297ee 163 * that can be set is 10000 pulses per second (pps) which will produce a square
AjK 0:7393c52297ee 164 * wave with 50% duty cycle. Pushing it beyond will give a square wave a duty
AjK 0:7393c52297ee 165 * cycle shifts so that the off time between pulses becomes shorter than the on
AjK 0:7393c52297ee 166 * pulse length.
AjK 0:7393c52297ee 167 *
AjK 0:7393c52297ee 168 * The pulseLen can be adjusted using setPulseLen() down even more to eek out
AjK 0:7393c52297ee 169 * some extra bandwidth. However, you really should be checking both the datasheet
AjK 0:7393c52297ee 170 * for your stepper motor amplifier and stepper motor. Running a stepper motor at
AjK 0:7393c52297ee 171 * such high speed may have electrical and mechanical issues.
AjK 0:7393c52297ee 172 *
AjK 0:7393c52297ee 173 * The arg raw is used when you want to "sync" channels. Suppose for example you
AjK 0:7393c52297ee 174 * have the following code to set the speed to two front wheels:-
AjK 0:7393c52297ee 175 * @code
AjK 0:7393c52297ee 176 * stepper0.setSpeed(100);
AjK 0:7393c52297ee 177 * stepper1.setSpeed(100);
AjK 0:7393c52297ee 178 * @endcode
AjK 0:7393c52297ee 179 *
AjK 0:7393c52297ee 180 * The problem here is they will be a few "clock ticks" out from each other as the
AjK 0:7393c52297ee 181 * TIMER2 TC increments between the two calls. If you wanted to make two motors sync
AjK 0:7393c52297ee 182 * together you can pass in the raw value of TIMER2 TC to make both functions calculate
AjK 0:7393c52297ee 183 * the same stepp values and so sync together:-
AjK 0:7393c52297ee 184 * @code
AjK 0:7393c52297ee 185 * uint32_t i = LPC_TIM2->TC; // Capture TC.
AjK 0:7393c52297ee 186 * stepper0.setSpeed(100, i);
AjK 0:7393c52297ee 187 * stepper1.setSpeed(100, i);
AjK 0:7393c52297ee 188 * @endcode
AjK 0:7393c52297ee 189 *
AjK 0:7393c52297ee 190 * The above code forces setSpeed() to calculate both axis in sync with respect to
AjK 0:7393c52297ee 191 * a common TC value.
AjK 0:7393c52297ee 192 *
AjK 0:7393c52297ee 193 * @param int steps_per_second Number of pulses per second required.
AjK 0:7393c52297ee 194 */
AjK 0:7393c52297ee 195 void setSpeed(int steps_per_second = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 196
AjK 0:7393c52297ee 197 /** setSpeed
AjK 0:7393c52297ee 198 *
AjK 0:7393c52297ee 199 * Set the motor speed in pulses per second. Zero stops all motor pulses.
AjK 0:7393c52297ee 200 * @param double steps_per_second Number of pulses per second required.
AjK 0:7393c52297ee 201 */
AjK 0:7393c52297ee 202 void setSpeed(double steps_per_second = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 203
AjK 0:7393c52297ee 204 /** setInterval
AjK 0:7393c52297ee 205 *
AjK 0:7393c52297ee 206 * Set the motor speed pulse interval. Zero stops all motor pulses.
AjK 0:7393c52297ee 207 * @param int interval
AjK 0:7393c52297ee 208 */
AjK 0:7393c52297ee 209 void setInterval(int i = 0, uint32_t raw = 0);
AjK 0:7393c52297ee 210
AjK 0:7393c52297ee 211 /** getPosition
AjK 0:7393c52297ee 212 *
AjK 0:7393c52297ee 213 * Get the current position (the pulse counter).
AjK 0:7393c52297ee 214 *
AjK 0:7393c52297ee 215 * @return int64_t The current position as maintained by the interrupts.
AjK 0:7393c52297ee 216 */
AjK 0:7393c52297ee 217 int64_t getPosition(void) { return _pulseCounter; }
AjK 0:7393c52297ee 218
AjK 0:7393c52297ee 219 /** setWrapPos
AjK 0:7393c52297ee 220 *
AjK 0:7393c52297ee 221 * Set the value that we should wrap the pulse position counter.
AjK 0:7393c52297ee 222 * Zero (default) means no wrap occurs.
AjK 0:7393c52297ee 223 *
AjK 0:7393c52297ee 224 * @param int64_t The value to wrap to NEG at.
AjK 0:7393c52297ee 225 */
AjK 0:7393c52297ee 226 void setWrapPos(int64_t i = 0) { _pulseWrapPos = i; }
AjK 0:7393c52297ee 227
AjK 0:7393c52297ee 228 /** setWrapNeg
AjK 0:7393c52297ee 229 *
AjK 0:7393c52297ee 230 * Set the value that we should wrap the pulse position counter.
AjK 0:7393c52297ee 231 * Zero (default) means no wrap occurs.
AjK 0:7393c52297ee 232 *
AjK 0:7393c52297ee 233 * @param int64_t The value to wrap to POS at.
AjK 0:7393c52297ee 234 */
AjK 0:7393c52297ee 235 void setWrapNeg(int64_t i = 0) { _pulseWrapNeg = i; }
AjK 0:7393c52297ee 236
AjK 0:7393c52297ee 237 /** setMaintainPositionData
AjK 0:7393c52297ee 238 *
AjK 0:7393c52297ee 239 * Setting this false removes the maintainence of positional data.
AjK 0:7393c52297ee 240 * This allows the interrupt service routine to not perform these
AjK 0:7393c52297ee 241 * steps (if not required) thus making the ISR run slightly fatser.
AjK 0:7393c52297ee 242 * You might want to do this if positional data isn't required.
AjK 0:7393c52297ee 243 */
AjK 0:7393c52297ee 244 void setMaintainPositionData(bool b) { _maintainPositionData = b; }
AjK 0:7393c52297ee 245
AjK 0:7393c52297ee 246 };
AjK 0:7393c52297ee 247
AjK 0:7393c52297ee 248 class SimpleStepperController {
AjK 0:7393c52297ee 249 protected:
AjK 0:7393c52297ee 250 SimpleStepper *_stepper[4];
AjK 0:7393c52297ee 251
AjK 0:7393c52297ee 252 public:
AjK 0:7393c52297ee 253 friend class SimpleStepper;
AjK 0:7393c52297ee 254
AjK 0:7393c52297ee 255 SimpleStepperController();
AjK 0:7393c52297ee 256 ~SimpleStepperController();
AjK 0:7393c52297ee 257 void isr(void);
AjK 0:7393c52297ee 258 };
AjK 0:7393c52297ee 259
AjK 0:7393c52297ee 260 }; // namespace AjK ends
AjK 0:7393c52297ee 261
AjK 0:7393c52297ee 262 #endif