TeensyStep Fast Stepper Library
repository·master·Indexed 43 days ago
https://github.com/luni64/teensystepA high-performance stepper motor control library for PJRC Teensy boards (3.0, 3.1, 3.2, 3.5, 3.6) and STM32F4. It supports pulse rates up to 300kHz, synchronous movement for up to 10 motors, and independent movement for 4 groups. The library includes acceleration profiles via LinRotAccelerator, LinStepAccelerator, and SinRotAccelerator, as well as a custom ErrorHandler for intercepting module-specific errors.
What's inside TeensyStep
- TeensyStep is a high-performance Arduino library designed for PJRC Teensy boards (3.0, 3.1, 3.2, 3.5, 3.6) and STM32F4. It is optimized for handling synchronous and independent stepper motor movements, including continuous rotation. The library supports high-speed operation with pulse rates up to 300,000 steps per second.
Use multiple motors with StepperArray
masterTheStepperArrayexample demonstrates how to control more than three stepper motors simultaneously using the TeensyStep library. This is useful for complex motion control applications requiring high-degree-of-freedom systems.TeensyStep Technical Specifications
masterTeensyStep provides high-speed stepper control with the following capabilities:
Feature Specification Default Motor speed / pulse rate 1 - 300,000 stp/s 800 stp/s Acceleration 0 - 500,000 stp/s² 2,500 stp/s² Pull in speed 50 - 10,000 stp/s 100 stp/s Synchronous movement Up to 10 motors - Independent movement 4 groups (1 to 10 motors per group) - Step pulse polarity Active HIGH or LOW Active HIGH Step pulse width 1 - 100µs 5µs Direction signal polarity cw / ccw cw Manage delay channels in TeensyStepFTM
masterThe
TeensyStepFTMnamespace provides functions to manage hardware-backed delay channels used for timing interrupts. You can register a handler that implements theIDelayHandlerinterface to receive interrupt callbacks viaaddDelayChannel.To use this, implement the
delayISR(unsigned channel)method in a class derived fromIDelayHandler. This method will be called when the timer reaches the specified delay value for that channel.class MyHandler : public IDelayHandler { public: void delayISR(unsigned channel) override { // Handle the interrupt for this specific channel } }; MyHandler handler; unsigned myChannel = TeensyStepFTM::addDelayChannel(&handler); // ... later ... TeensyStepFTM::removeDelayChannel(myChannel);Control the step timer in TimerField
masterThe step timer controls the frequency of motor steps. Use
setStepFrequencyto define the speed andstepTimerStart/stepTimerStopto control execution.setStepFrequency(unsigned f): Sets the step frequency in Hertz. Passing0will automatically stop the step timer.stepTimerStart(): Resumes and refreshes the step timer to ensure immediate start.stepTimerStop(): Pauses the step timer.stepTimerIsRunning(): Returnstrueif the step timer is currently active.getStepFrequency(): Returns the current timer clock frequency.
timerField.setStepFrequency(1000); // 1kHz timerField.stepTimerStart(); if (timerField.stepTimerIsRunning()) { // ... } timerField.stepTimerStop();Manage timers with TimerControl
masterThe
TimerControlclass acts as the manager for all timer instances. To make a timer functional, it must be registered with the controller.Workflow:
- Call
TimerControl::begin()once in your setup. - Create a
PeriodicTimerorOneShotTimerinstance. - Register the timer using
TimerControl::attachTimer(timer_pointer). - Call
TimerControl::tick()frequently in your main loop to process timer expirations. - Use
TimerControl::detachTimer(timer_pointer)to remove a timer from the management list.
Note:
TimerControl::tick()is the engine that drives the callbacks. If it is not called, timers will not fire.PeriodicTimer myTimer([]() { /* task */ }); void setup() { TimerControl::begin(); TimerControl::attachTimer(&myTimer); myTimer.setFrequency(10.0f); myTimer.start(); } void loop() { TimerControl::tick(); }- Call
Use LinRotAccelerator for linear rotation acceleration profiles
masterThe
LinRotAcceleratorclass implements a linear acceleration/deceleration profile for rotation. It allows you to define a target speed and acceleration rate, which the accelerator then uses to smoothly ramp the speed up or down over time based on a specified update period.Key Methods:
prepareRotation(currentPosition, targetSpeed, acceleration, accUpdatePeriod, speedFactor): Initializes the acceleration profile.targetSpeed: The desired final speed.acceleration: The acceleration rate (typically in units/s²).accUpdatePeriod: The time interval (in microseconds) between speed updates.speedFactor: A multiplier for the target speed (defaults to1.0).
updateSpeed(currentPosition): Calculates and returns the new target speed for the current step. This should be called periodically to advance the acceleration profile.initiateStopping(currentPosition): Sets the target speed to 0 to begin a deceleration phase.overrideSpeed(factor): Dynamically scales the target speed by a multiplier.overrideAcceleration(factor): Dynamically scales the acceleration rate by a multiplier.
LinRotAccelerator accel; // Initialize: target speed 1000, acceleration 5000, update every 1000us accel.prepareRotation(0, 1000, 5000, 1000); // In your main loop or timer interrupt: int32_t nextSpeed = accel.updateSpeed(currentPosition); // Use nextSpeed to drive your stepper motor...Perform non-blocking continuous rotation with rotateAsync()
masterUse
rotateAsync()to command one or more steppers to rotate continuously without blocking the main execution loop. This method calculates Bresenham parameters for synchronized multi-motor rotation based on thevMaxof each stepper and uses the lowest acceleration among the provided steppers.You can pass steppers as a variadic list of arguments or as an array of pointers.
Note: The rotation is managed via an internal accelerator and timer ISR. The rotation continues until
stopAsync()is called or the speed reaches zero.// Using variadic arguments controller.rotateAsync(stepper1, stepper2, stepper3); // Using an array of stepper pointers Stepper* motors[] = {&stepper1, &stepper2}; controller.rotateAsync(motors);Configure PIT frequency and reload values
masterThe
PITclass allows fine-grained control over the timer's timing parameters:setFrequency(uint32_t val): Sets the timer frequency based on the bus frequency (F_BUS).setThisReload(uint32_t ldval): Sets the reload value (LDVAL) immediately for the current cycle.setNextReload(uint32_t ldval): Sets the reload value to be used for the next timer cycle.getLDVAL(): Returns the current reload value.getCVAL(): Returns the current compare value.
Initialize the timer system with TimerControl::begin()
masterBefore using any timers, you must call
TimerControl::begin()to initialize the hardware cycle counter (DWT CYCCNT) on supported ARM Cortex-M processors. This enables the high-resolution timing mechanism used by the library.TimerControl::begin();Get and set current position
masterUse these methods to track or manually override the stepper's current position.
getPosition(): Returns the current position as anint32_t.setPosition(int32_t pos): Manually sets the current position value.
int32_t currentPos = myStepper.getPosition(); // Reset position to zero myStepper.setPosition(0);Monitor motor controller status
masterUse the following methods to query the state of the motor controller:
isOk(): Returnstrueif the controller is in a valid state.isRunning(): Returnstrueif the step timer is currently active (motors are moving).isAllocated(): Returnstrueif the step timer has been allocated.getCurrentSpeed(): Returns the current step frequency (speed) of the motors.