Last active
April 28, 2025 17:32
-
-
Save jancumps/c66e8af42dc30ee6dfbdfc06aea496e1 to your computer and use it in GitHub Desktop.
pio_stepper_lib example with 2 motors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "hardware/pio.h" // some constant definitions used | |
| #include "pico/stdlib.h" // for demo section (printf) | |
| #include <array> // for demo section (commands container) | |
| #include <iterator> // for demo section (commands container) | |
| #include <span> // for demo section (commands container) | |
| #include <algorithm> // for_each | |
| #include <numeric> // for demo section (accumulate) | |
| import stepper; // PIO stepper lib | |
| // TODO: adapt to your board design | |
| // TODO driver IC dependent. see dummy_driver.cpp | |
| import dummy_driver; | |
| using driver_t = dummy_driver; | |
| std::array<driver_t, 2> drivers; | |
| // #define MICROSTEP_8 | |
| #undef MICROSTEP_8 | |
| #ifdef MICROSTEP_8 | |
| const float clock_divider = 3; // works well for 8 microsteps | |
| const uint microstep_x = 8; | |
| #else | |
| const float clock_divider = 16; // works well for no microsteps | |
| const uint microstep_x = 1; | |
| #endif | |
| // TODO: adapt to your board design | |
| const uint motor1_dir = 4U; // implies that step is gpio 5 | |
| const uint motor2_dir = 6U; // implies that step is gpio 7 | |
| using motor_t = stepper::stepper_callback_controller; | |
| std::array<motor_t, 2> motors {{{pio0, 0}, {pio0, 1}}}; | |
| std::array<volatile size_t, motors.size()> commands_per_motor; | |
| void on_complete(const motor_t &stepper) { | |
| size_t index = 0U; | |
| for (auto &m: motors) { | |
| if (&m == &stepper) { | |
| commands_per_motor[index] = commands_per_motor[index] - 1; | |
| printf("motor %d executed command\n", index + 1); | |
| break; | |
| } | |
| index++; | |
| } | |
| } | |
| void init_pio() { | |
| // program the pio used for the motors | |
| // do this only once per used pio | |
| motor_t::pio_program(pio0); // not needed if all sms run on pio1 | |
| motor_t::pio_program(pio1); // not needed if all sms run on pio0 | |
| // individual settings | |
| motors[0].pio_init(motor1_dir, clock_divider); | |
| motors[1].pio_init(motor2_dir, clock_divider); | |
| // common settings | |
| // initialise and enable the motor state machine | |
| for (auto &m: motors) { | |
| m.register_pio_interrupt(0, true); | |
| m.enable(true); | |
| // and the notification, for demo purpose | |
| m.on_complete_callback(on_complete); | |
| } | |
| } | |
| void init_everything() { | |
| stdio_init_all(); | |
| // TODO driver IC dependent. see dummy_driver.cpp | |
| for (auto &d: drivers) { | |
| d.init(); | |
| } | |
| init_pio(); | |
| } | |
| // stepper demo: execute a series of commands ================================ | |
| // struct to hold command and motor | |
| struct motor_command { | |
| stepper::command cmd; | |
| size_t motor; | |
| motor_command(stepper::command cmd, size_t motor) : cmd(cmd), motor(motor) {} | |
| }; | |
| using commands_t = std::span<motor_command>; | |
| void run_commands(const commands_t& cmd, uint delay0, uint delay1) { | |
| motors[0].set_delay(delay0); | |
| motors[1].set_delay(delay1); | |
| for (auto& count: commands_per_motor) { count = 0; } | |
| for (auto& c : cmd) { | |
| // increment commands expected for the motor | |
| commands_per_motor[c.motor] = commands_per_motor[c.motor] + 1; | |
| } | |
| for (auto& c : cmd) { | |
| if (commands_per_motor[c.motor] > 0U) { | |
| motors[c.motor].take_steps(c.cmd); | |
| } | |
| } | |
| size_t todo = 0U; | |
| do { | |
| todo = std::accumulate(commands_per_motor.begin(),commands_per_motor.end(),0); | |
| } while (todo > 0U); | |
| sleep_ms(100); // pause for demo purpose | |
| } | |
| void full_demo(const commands_t & cmd) { | |
| // stepper driver IC should wake up here, if not yet | |
| // TODO driver IC dependent. see dummy_driver.cpp | |
| for (auto &d: drivers) { | |
| d.enable(true); | |
| } | |
| // sleep_ms(1); // some drivers require time between enable and step | |
| // demo 1 :run all in sequence | |
| for (auto &c: cmd) { | |
| std::array<motor_command,1> single_cmd {{c}}; | |
| run_commands(single_cmd, 9000, 7000); | |
| } | |
| // demo 2: run all in parallel | |
| run_commands(cmd, 7000, 4300); | |
| // TODO: stepper driver IC can go back to sleep here | |
| // TODO driver IC dependent. see dummy_driver.cpp | |
| for (auto &d: drivers) { | |
| d.enable(false); | |
| } | |
| } | |
| int main() { | |
| init_everything(); | |
| std::array<motor_command, 7> cmd{{ | |
| { {200 * microstep_x, true}, 0}, | |
| { {200 * microstep_x, true}, 1}, | |
| { {300 * microstep_x, false}, 1}, | |
| { {200 * microstep_x, false}, 1}, | |
| { {10 * microstep_x, true}, 1}, | |
| { {200 * microstep_x, false}, 1}, | |
| { {20 * microstep_x, true}, 0} | |
| }}; | |
| while (true) { | |
| full_demo(cmd); | |
| // sleep_ms(200); // pause for demo purpose | |
| } | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| cmake_minimum_required(VERSION 3.28) | |
| # set(PICO_BOARD pico_w) # for PICOW | |
| set(PICO_BOARD pico) | |
| # copy this file in project root directory. Get a copy from root of Pico C SDK you are using | |
| include(pico_sdk_import.cmake) | |
| project(pio_stepper_2motors C CXX ASM) | |
| set(CMAKE_CXX_STANDARD 26) | |
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmodules-ts -fcommon -fno-rtti -fno-exceptions") | |
| pico_sdk_init() | |
| include(FetchContent) | |
| FetchContent_Declare(stepper | |
| GIT_REPOSITORY "https://github.com/jancumps/pio_stepper_lib.git" | |
| GIT_TAG "origin/main" | |
| ) | |
| FetchContent_MakeAvailable(stepper) | |
| # start DRIVER IC specific | |
| FetchContent_Declare(stepper_driver | |
| GIT_REPOSITORY "https://github.com/jancumps/stepper_driver_lib.git" | |
| GIT_TAG "origin/main" | |
| ) | |
| FetchContent_MakeAvailable(stepper_driver) | |
| add_library(driver) | |
| target_sources(driver | |
| PUBLIC | |
| FILE_SET cxx_modules TYPE CXX_MODULES FILES | |
| ${stepper_driver_SOURCE_DIR}/source/stepper_driver.cpp | |
| ${CMAKE_CURRENT_SOURCE_DIR}/dummy_driver.cpp | |
| ) | |
| # end DRIVER IC specific | |
| add_executable(${CMAKE_PROJECT_NAME}) | |
| target_sources(${CMAKE_PROJECT_NAME} | |
| PUBLIC | |
| ${CMAKE_CURRENT_SOURCE_DIR}/2_motor_pio_stepper_example.cpp | |
| # PICOW ${CMAKE_CURRENT_SOURCE_DIR}/shabaz.cpp | |
| ) | |
| target_sources(${CMAKE_PROJECT_NAME} | |
| PUBLIC | |
| FILE_SET cxx_modules TYPE CXX_MODULES FILES | |
| ) | |
| target_link_libraries( ${CMAKE_PROJECT_NAME} | |
| pico_stdlib | |
| hardware_gpio | |
| stepper | |
| # pico_cyw43_arch_none # for PICO W | |
| # start DRIVER IC specific | |
| driver | |
| # end DRIVER IC specific | |
| ) | |
| pico_add_extra_outputs(${CMAKE_PROJECT_NAME} ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module; | |
| import stepper_driver; | |
| export module dummy_driver; | |
| /* | |
| for demo purposes | |
| replace with your own stepper driver IC code | |
| or create your own driver IC class derived from stepper_driver::stepper_driver | |
| for smooth integration | |
| */ | |
| export class dummy_driver: public stepper_driver::stepper_driver { | |
| public: | |
| virtual bool init() override { return true; } | |
| virtual bool microsteps(unsigned int microsteps) override { return true; } | |
| virtual void enable(bool enable) override {} | |
| }; |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
STEP pins capture of parallel and in sequential demo:
documentation: Raspberry PIO stepper library documentation - 3: control multiple motors with 1 or more PIOs