Provides an API software interface to TIMER2 to control upto four stepper motors.
Diff: inc/SimpleSteppers.h
- Revision:
- 0:7393c52297ee
- Child:
- 1:1030a91cbf4c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/SimpleSteppers.h Mon May 02 10:02:18 2011 +0000 @@ -0,0 +1,262 @@ +/* + Copyright (c) 2011 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef AJK_SIMPLESTEPPERS_H +#define AJK_SIMPLESTEPPERS_H + +#define SIMPLESTEPPER_F 100000 +#include "LPC17xx.h" +#include "core_cm3.h" +#include <stdint.h> + +#ifndef __ARMCC_VERSION +#include "SimpleStepperMbed.h" +#else +#include "mbed.h" +#endif + +#include "SimpleStepperOutput.h" + +namespace AjK { + +// Forward reference the main controller. +class SimpleStepperController; + +/** SimpleStepper + * + * SimpleStepper is a class designed to handle the pulse and direction + * signals for a stepper motor. A simple API is exposed to allow the + * setting of the pulse width and the number of pulses per second. + * + * Note, SimpleStepper uses the SimpleStepperController class to manage + * the TIMER2. SimpleStepperController and SimpleStepper take total + * control of the LPC17xx's TIMER2. Your application or other library that + * your application uses, should use TIMER2. + * + * @include example1.h + */ +class SimpleStepper { + +public: + enum MAT { MAT2_0, MAT2_1, MAT2_2, MAT2_3 }; + enum MATCH_OP { NothingOnMatch, ClrOnMatch, SetOnMatch, ToggleOnMatch }; + enum PULSE_STATE { PulseIdle, PulseAssert, PulseDeassert }; + enum STEPPER_STATE { Stopped, ConstantSpeed }; + +protected: + SimpleStepperController *_simpleStepperController; + SimpleStepperOutput *_direction; + + PinName _pulse; + MAT _pulseMAT; + uint32_t _operShift; + uint32_t _pMR; + uint32_t _match_shift; + uint32_t _EMmask; + uint32_t _EMCshift; + int _pulseLen; + int _pulseSense; + int _directionSense; + int _commandSpeed; + int64_t _pulseCounter; + int64_t _pulseWrapPos; + int64_t _pulseWrapNeg; + uint32_t _currentMatch; + + bool _maintainPositionData; + + PULSE_STATE _pulseState; + + STEPPER_STATE _stepperState; + + void init(void); + + void isr(uint32_t); + + void next_step(void); + +public: + friend class SimpleStepperController; + + /** Constructor + * + * PinName pulse can be p5, p6, p7 or p8 + * SimpleStepperOutput *direction is a pointer to an output. + * + * @param PinName The output for the pulse output. + * @param SimpleStepperOutput *direction The output pin for direction control + */ + SimpleStepper(PinName pulse, SimpleStepperOutput *direction = 0); + + /** Constructor + * + * PinName pulse can be p5, p6, p7 or p8 + * SimpleStepperOutput *direction is a pointer to an output. + * + * @param SimpleStepperController *con A pointer to a base controller. + * @param PinName The output for the pulse output. + * @param SimpleStepperOutput *direction The output pin for direction control + */ + SimpleStepper(SimpleStepperController *con, PinName pulse, SimpleStepperOutput *direction); + + /** setPulseSense + * + * Set's the logic value that pulse asserted assumes. Default is 1. + * + * 1 means pulse goes from 0 to 1 and remains 1 for pulseLen time then goes to 0. + * 0 means pulse goes from 1 to 0 and remains 0 for pulseLen time then goes to 1. + * + * @param int What is the logic sense for the pulse output. + */ + void setPulseSense(int i = 1) { _pulseSense = i; } + + /** setDirectionSense + * + * Set's the logic value that direction forward assumes. Default is 1. + * + * 1 means that the direction output is 1 for forward and 0 for reverse. + * 0 means that the direction output is 0 for forward and 1 for reverse. + * + * Additionally, for position:- + * 1 means forward pulses are counted upwards, reverse means counted downwards. + * 0 means forward pulses are counted downwards, reverse means counted upwards. + * + * @param int What is the logic sense for the direction output. + */ + void setDirectionSense(int i = 1) { _directionSense = i; } + + /** setPulseLen + * + * Used to set the pulse length. Default pulse length is 50us. + * If no arg supplied returns the current pulse length. + * <b>Note,</b> the length is specified as 10us increments. + * The default is 5 which is 50us + * @param int pulse length + * @return int the value of the pulse length. + */ + int setPulseLen(int i = 0) { if (i) _pulseLen = i; return _pulseLen; } + + /** setSpeed + * + * Set the motor speed in pulses per second. Zero stops all motor pulses. + * + * With the default pulseLen of 50us (5 timer "ticks") the maximum speed + * that can be set is 10000 pulses per second (pps) which will produce a square + * wave with 50% duty cycle. Pushing it beyond will give a square wave a duty + * cycle shifts so that the off time between pulses becomes shorter than the on + * pulse length. + * + * The pulseLen can be adjusted using setPulseLen() down even more to eek out + * some extra bandwidth. However, you really should be checking both the datasheet + * for your stepper motor amplifier and stepper motor. Running a stepper motor at + * such high speed may have electrical and mechanical issues. + * + * The arg raw is used when you want to "sync" channels. Suppose for example you + * have the following code to set the speed to two front wheels:- + * @code + * stepper0.setSpeed(100); + * stepper1.setSpeed(100); + * @endcode + * + * The problem here is they will be a few "clock ticks" out from each other as the + * TIMER2 TC increments between the two calls. If you wanted to make two motors sync + * together you can pass in the raw value of TIMER2 TC to make both functions calculate + * the same stepp values and so sync together:- + * @code + * uint32_t i = LPC_TIM2->TC; // Capture TC. + * stepper0.setSpeed(100, i); + * stepper1.setSpeed(100, i); + * @endcode + * + * The above code forces setSpeed() to calculate both axis in sync with respect to + * a common TC value. + * + * @param int steps_per_second Number of pulses per second required. + */ + void setSpeed(int steps_per_second = 0, uint32_t raw = 0); + + /** setSpeed + * + * Set the motor speed in pulses per second. Zero stops all motor pulses. + * @param double steps_per_second Number of pulses per second required. + */ + void setSpeed(double steps_per_second = 0, uint32_t raw = 0); + + /** setInterval + * + * Set the motor speed pulse interval. Zero stops all motor pulses. + * @param int interval + */ + void setInterval(int i = 0, uint32_t raw = 0); + + /** getPosition + * + * Get the current position (the pulse counter). + * + * @return int64_t The current position as maintained by the interrupts. + */ + int64_t getPosition(void) { return _pulseCounter; } + + /** setWrapPos + * + * Set the value that we should wrap the pulse position counter. + * Zero (default) means no wrap occurs. + * + * @param int64_t The value to wrap to NEG at. + */ + void setWrapPos(int64_t i = 0) { _pulseWrapPos = i; } + + /** setWrapNeg + * + * Set the value that we should wrap the pulse position counter. + * Zero (default) means no wrap occurs. + * + * @param int64_t The value to wrap to POS at. + */ + void setWrapNeg(int64_t i = 0) { _pulseWrapNeg = i; } + + /** setMaintainPositionData + * + * Setting this false removes the maintainence of positional data. + * This allows the interrupt service routine to not perform these + * steps (if not required) thus making the ISR run slightly fatser. + * You might want to do this if positional data isn't required. + */ + void setMaintainPositionData(bool b) { _maintainPositionData = b; } + +}; + +class SimpleStepperController { +protected: + SimpleStepper *_stepper[4]; + +public: + friend class SimpleStepper; + + SimpleStepperController(); + ~SimpleStepperController(); + void isr(void); +}; + +}; // namespace AjK ends + +#endif