FastAccelStepper drives stepper motors at 200 kSteps/s on an ESP32 and 50 on an AVR
A high speed stepper library for Atmega 168/328p (nano), Atmega32u4, Atmega 2560, ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C6, Atmel SAM Due, SAMD51, Raspberry pi pico and pico 2
At a glance
- What is it?
- FastAccelStepper is a C++ stepper motor library for Arduino-class microcontrollers that uses the hardware timer rather than a delay in the application loop, supports up to forty-six steppers on an ESP32, and trades exact floating point for a log2 speed representation.
- Who is it for?
- FastAccelStepper fits a maker or robotics project where a stepper has to move faster than an AccelStepper loop can manage, and where the hardware has a timer that can be driven directly, which covers every platform in the table.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The timer does the work, not the application loop
FastAccelStepper is a high speed alternative to the AccelStepper library, and the difference in approach is stated in the feature list: it is fully interrupt and task driven, with no periodic function to be called from the application loop.
That is the whole point of the library. The classic Arduino approach to stepping a motor is to toggle a pin, wait a calculated interval, toggle again, and repeat, which means the timing accuracy is a function of how busy your loop is and how long your delay calls actually take. FastAccelStepper instead configures the hardware timer of the microcontroller to generate the step pulses, so the pulses keep their timing whether or not the sketch does anything else.
The consequence for a user is visible in the quick start example. The setup function connects a stepper to a pin, sets its direction and enable pins, turns on auto enable, sets the speed and acceleration, and issues the move. The loop function is empty, and it stays empty:
void loop() {
}Everything else in the library follows from that decision. A lower limit on step timing is documented at one step every four minutes on ESP32, AVR and SAMD51, and 198 seconds on the SAM Due, which is the practical floor of what a timer based approach can do.
The library is published for Arduino, for the PlatformIO registry and as an ESP-IDF component, and the repository carries badges for the Arduino library index, PlatformIO, the test workflow, the simulation tests and build matrices for the Arduino examples and the ESP-IDF examples.
The platform table is the real spec
The supported platforms table is where the practical limits are, and it is worth reading line by line because the differences are large.
The AVR entries top out at 50 kSteps per second. The ATmega 168 and 328 support one or two steppers, the ATmega32u4 and the ATmega2560 support three, and the command queue depth is 16 on all of them. The Atmel SAM Due also runs at 50 with six steppers, and the Microchip SAMD51 at 100 with three to five.
The ESP32 family reaches 200 kSteps per second, and the stepper counts differ because the peripherals differ. The original ESP32 offers 14, split as 6 from the MCPWM and PCNT units and 8 from RMT. The ESP32-S2 has 4 RMT channels, the S3 has 4 MCPWM/PCNT plus 4 RMT, the C3 has 2 RMT, the C6 has 2 MCPWM/PCNT plus 2 RMT, and the P4 has 4 RMT. Queue depth is 32 across the ESP32 and the other 32-bit platforms.
The Raspberry Pi Pico and Pico 2 also reach 200, with 4 and 8 steppers respectively, and the notes say 8 and 12 with riscv. Teensy 4.0 and 4.1 are listed as experimental at 200 with 16 steppers.
Two footnotes explain the asterisk in the table. The 32 I2S steppers need an external demultiplexer such as a 74HC154, or a 74HC138 cascade or 74HC595 shift registers, on the I2S data line, and using the I2S slots directly provides only one to three extra steppers.
No floating point, and a log2 speed representation
One feature line is unusual enough to be worth its own attention: there is no float calculation, with a log2 representation in the range of -64 to 64, a 16-bit integer representation, and a resolution of 1/512th.
The reason is the target hardware. On an AVR with a few kilobytes of RAM, a floating point speed calculation on every step is expensive, and a library that wants to run at 50 kSteps per second on an ATmega328 cannot afford it. The log2 representation sidesteps that by working in a fixed point domain where the step period is a power of two with a fractional part.
The cost is precision and API surprise. Speeds and accelerations are not the numbers you would type into a naive library, and the resolution of one 512th means the achievable speed is quantised. Anyone porting code from AccelStepper, where speed is in steps per second as a plain number, has to read the conversion carefully.
There is a related design point about the command queues. The API gives each stepper a command queue, and those commands are tied to timer ticks, which means the CPU frequency, since the queue depth is expressed in the units the timer counts. Filling a queue with commands and then starting it allows a near synchronous start of several steppers, which is what a multi axis machine needs so that the axes move together rather than each starting when its own queue happens to be ready.
Acceleration is the library's own model, and there are two of them
The library supports acceleration and deceleration with a per stepper maximum speed and acceleration, and it offers several ways to shape the motion rather than one.
The first is constant acceleration control, where the motor is controlled by acceleration values and, with acceleration set to zero, it keeps the current speed. The second is linear acceleration increase from and to standstill using a cubic speed function, configurable through setLinearAcceleration. A third is a jump start from standstill, configurable through setJumpStart.
Speed and acceleration can be varied while the stepper is running, with the caveat stated in the README that a call to move or moveTo is needed in order to apply the new values. That is a deliberate API choice, since applying a new speed mid motion changes the profile and the library makes you ask for it explicitly rather than surprising you.
The other motion features are more operational. There is an auto enable mode, where the motor is enabled before movement and disabled afterwards with configurable delays, and enable pins and direction pins can be shared between motors. A configurable delay between the direction change and the following step exists because some drivers need the direction line settled before the step edge arrives, and an external callback function can drive the enable pins and, on the ESP32 derivatives, the direction pins, which is what you need when those pins are behind a shift register.
One pin, two pins or three, and what that changes
The stepper motors are connected through a driver IC such as an A4988, with a 1, 2 or 3 wire connection covering step, direction and enable. The feature list explains what each mode buys.
One pin operation is for cases like a peristaltic pump, where only positive moves are needed, so the library omits the direction line entirely. Two pin operation is for axis control. Three pin operation adds the enable line, and the stated reason is to reduce power dissipation in the driver and the stepper, since holding the driver enabled keeps the motor energised and therefore warm.
Auto enable ties into that third mode. The library enables the motor before movement and disables it afterwards, with delays you configure, so a machine that sits idle does not keep its motors powered up. Enable pins can be shared between motors, so several axes can be enabled together with one line.
The pin restrictions differ per platform, and the README points at a hardware and pin connection document for them, because the number of pins you can dedicate to steppers depends on what the microcontroller has left after the serial port, the timers and whatever else the board uses.
FasNAxis, the multi-axis planner, and its white paper
The one item marked experimental in the feature list is a multi-axis planner called FasNAxis, in src/FasNAxis.h, which drives N stepper queues from one polyline so that the axes stay time synchronised. The README is explicit that the API is not stable yet, and it points at an n-axis whitepaper, an example called NaxesAFAP, and a future work section.
The idea addresses a real problem with independent stepper queues. If each axis has its own queue and its own timer, they drift relative to each other, and on a machine where the axes must describe the same straight line at the same time, that drift shows up as the tool path curving. A single planner that emits one polyline and distributes it across the queues keeps the motion coordinated.
The examples directory shows the same idea explored from several angles, with directories for NaxesAFAP and NaxesTimed alongside the more conventional ones such as LinearAcceleration, MoveTimed, Pulses, RawAccess, PrintPosition and StepperDemo. There is also a set of Teensy bring-up and test examples, which fits the experimental status of that platform.
For anyone evaluating the library, the multi-axis work is the part to watch rather than the part to depend on today.
Where FastAccelStepper is the wrong choice
The first limit is the number precision. The library deliberately avoids floating point, so the speed and acceleration you request are quantised to a log2 representation with a 1/512th resolution. For a CNC router or a 3D printer that is fine. For a machine where the commanded speed has to match a calibrated value exactly, the quantisation is a real constraint and you need to check the resolution against your stepper's microstepping.
The second is that the acceleration model is the library's own, not a trapezoidal planner. If you need a specific velocity profile, or the ability to change the profile mid move, you are choosing the library's model rather than expressing your own.
The third is the platform coverage in practice. Although the table lists a wide range of chips, the ESP32 variants differ so much in their available peripherals that the per-platform documents matter. The ESP32-P4 notes say MCPWM and PCNT are not implemented for it yet, the S2 has PCNT but no MCPWM, and the C3 has neither, so only RMT and I2S are available there.
The fourth is the Arduino framing. The library targets Arduino-class boards, so a team with a bare-metal or RTOS project without the Arduino core will find the examples, the build and the API conventions all shaped around the Arduino model, even though the ESP-IDF component is published too.
Licence, packaging and the state of the project
The library is released under the MIT Licence, with the LICENSE file at the root of the repository. There are no GitHub releases, and the last push was on 2026-10-20 with the repository not archived, so the version comes from the repository rather than from a tag.
The packaging supports the three ways people use these boards. The Arduino library manifest is library.properties, the keywords.txt file registers the API with the Arduino IDE for autocompletion, and the PlatformIO registry badge shows it is published there as well. For the ESP-IDF side there is an idf_component.yml, and there is a manifest.json. A CMakeLists.txt, a shell.nix and a .clang-format file cover the other build paths, and a CHANGELOG.md is at the root.
The documentation is unusually thorough for a library of this size. There is a hardware and pin connection document, a memory report with memory footprint information across the supported architectures, per-platform documents for avr, esp32, pico, sam, samd51 and teensy, the n-axis whitepaper, and a deepwiki page with an AI generated description of the implementation and diagrams, which the README recommends as a starting point for understanding the internals.
The tests are visible in the badges too, with a test workflow, a separate simulation test workflow for AVR, and build matrices for the Arduino and ESP-IDF examples, so a change is checked against more than one toolchain before it lands.
Editorial conclusion
FastAccelStepper fits a maker or robotics project where a stepper has to move faster than an AccelStepper loop can manage, and where the hardware has a timer that can be driven directly, which covers every platform in the table. It is the wrong tool if you need sub-microsecond positioning accuracy, because the speed and acceleration are held as log2 values with a 1/512th resolution and no floating point is used, and it is the wrong tool if you want the library to compute a trapezoidal profile for you, since the acceleration model is the library's own. Before you adopt it, check three things: that your board is in the supported platform table with the step rate you need, that you can meet the pin restrictions for that platform, and that you read the platform document for your board, since the ESP32 variants differ considerably in how many steppers they can drive and by which peripheral. The code is MIT licensed, the last push was on 2026-10-20, and the repository publishes no GitHub releases.
Frequently asked questions
What is the maximum step rate FastAccelStepper can reach?
50 kSteps/s on the AVR boards and the SAM Due, 100 on the SAMD51, and 200 on the ESP32 family, the Raspberry Pi Pico and Pico 2, and the experimental Teensy 4.0 and 4.1.
How many steppers can I connect to an ESP32 with FastAccelStepper?
The table lists 14 on the original ESP32, from 6 MCPWM/PCNT plus 8 RMT, and fewer on the other variants, with 4 RMT on the S2, 4 MCPWM/PCNT plus 4 RMT on the S3, 2 RMT on the C3, and 4 RMT on the P4. The 32 extra I2S steppers need an external demultiplexer on the I2S data line.
Do I need to call a function repeatedly in the Arduino loop?
No. The library is fully interrupt and task driven, with no periodic function to be called from the application loop, because the step pulses come from the hardware timer. The quick start example leaves the loop function empty.
Does FastAccelStepper use floating point for speed and acceleration?
No. There is no float calculation, and speed and acceleration use a log2 representation in the range -64 to 64, held in 16-bit integers with a resolution of 1/512th.
How do I add FastAccelStepper to my project?
Through the Arduino library index or the PlatformIO registry, or as an ESP-IDF component using the idf_component.yml in the repository. The project is MIT licensed and the last push to the repository was on 2026-10-20.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gin66-fastaccelstepper)Was this useful?