Raspberry PIO stepper library (pio_stepper_lib) is a C++ library that runs stepper motors in PIO state machines. It's intended to be easy to integrate and use in Pico projects.
- 4 motors can be controlled per PIO
- can be used with any stepper motor driver that supports STEP and DIR operation
- can handle as many commands as PIO FIFO accepts without waiting (default 8).
- each command can autonomously handle 2147483647 steps, and the spin direction
- can notify the calling program when a command has finished
- can report how many commands it processed
Add the library to your Pico project
The library has its own CMake script. You add it to your own project by fetching it in your CMakeFiles.txt. It is then available to your code as a library.
Fetch and make available
# your CMakeFiles.txt
# ...
include(FetchContent)
FetchContent_Declare(stepper
GIT_REPOSITORY "https://github.com/jancumps/pio_stepper_lib.git"
GIT_TAG "origin/main"
)
FetchContent_MakeAvailable(stepper)
# ...
Link with your firmware executable
# add stepper as a library to your executable
add_executable(your_stepper_project)
# ...
target_link_libraries(your_stepper_project
pico_stdlib
hardware_gpio
stepper
)
That's it. When building your project, CMake will fetch the stepper code from GitHub, and build the stepper library.
The look and feel is identical to adding, say, hardware_spi. Something you will be familiar with.
No includes need to be defined, or sources individually added. It's all handled in the few lines in the make script above.
This will work if you use and IDE such as VSCode, CLion, Eclipse. And if you build from the Linux or Windows command line.
First project: simple stepper
This Pico firmware example will define a stepper motor, and will make it take 400 steps clockwise.
Resources used
pins |
dir: gpio4 |
PIO |
pio 1 |
stepper lib | 1 instance of class stepper_controller |
other | your stepper motor driver IC may require other resources, such as gpio for enable, reset, ... |
Use the library and create the motor
#include "pico/stdlib.h" // the PIOs are declared here // and we select one (or more) of those // to run the motor state machine(s) on #include "hardware/pio.h" import stepper; // PIO stepper lib // pins const uint dir = 4U; // implies that step is gpio 5 // config what PIO, SM to use const auto piostep = pio1; const uint sm = 2U; const float clock_divider = 16.0; // works well with full steps using motor_t = stepper::stepper_controller; motor_t motor1(piostep, sm);
We now have motor1, that we 'll use in our firmware.
PIO and stepper setup
All PIO activities are handled by the library. You invoke them by taking these steps:
We 'll first tell the motor class to load its firmware into the selected PIO. This is an activity that needs to be done one time for each PIO used.
In this example, we only use PIO1. It can host 4 motors. If you want more motors, you can also use PIO0.
And if you have a Pico 2, there's an additional PIO that enables you to control maximum 12 motors.
Then, we configure each motor. That takes care that the class sets up its PIO state machine and enables it.
void init_pio() { // program the pio used for the motors // do this only once per used pio motor_t::pio_program(piostep); // initialise and enable the motor state machine motor1.pio_init(dir, clock_divider); motor1.enable(true); }
You call this function at the start of your program. From then on, all is ready to use.
the main function
int main() { init_pio(); motor1.set_delay(4500); // this is fast motor1.take_steps({400, false}); // 400 steps clockwise sleep_ms(2000); // wait for the motor to complete return 0; }
motor speed: The delay takes care that we slow down the steps that are sent to the motor driver.
At the start of the program we already slowed down the PIO clock. I set the clock to a frequency that's not crazy, but fast enough to give us good speed finetune resolution.
In main(), I set a particular delay for the next commands. The higher the delay, the slower the motor will run.
With my motor, when I use full steps, I set the divider to 16. When using 8 microsteps per step, I set it to 3.
In both cases, a delay of 4500 is then about the fastest the motor can step, with little load.
classes used
where to find the code
The pio_stepper_lib is hosted on GitHub. You don't need to clone or build it, to use the library in your project. CMake does that for you.
A working project, using the Texas Instruments DRV8711 as stepper driver, is also in GitHub.
I took care to clearly define where driver specific code is used, in case your hardware uses another one.
If you like to read up on the example's history, and for wiring information, start here: Stepper Motor Control with Raspberry Pico PIO and DRV8711 driver- Part 1: Hardware Provisioning..
If you get a build error, check the toolchain requirements.
next chapter: get notification when the motor has executed a command