element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog modern C++ on a Pico: use C++ Standard Library algorithms - embedded friendly
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
GPIO Pinout
Raspberry Pi Wishlist
Comparison Chart
Quiz
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 7 Nov 2025 6:43 PM Date Created
  • Views 604 views
  • Likes 6 likes
  • Comments 10 comments
Related
Recommended
  • Modern C++
  • pico
  • c++26
  • stl
  • PIO
  • object oriented
  • c++

modern C++ on a Pico: use C++ Standard Library algorithms - embedded friendly

Jan Cumps
Jan Cumps
7 Nov 2025
modern C++ on a Pico: use C++ Standard Library algorithms - embedded friendly

C++ has embedded friendly mechanisms that can help to structure your firmware. While keeping the design resource-lean.
In this post, I use classes,  C++ stl containers and algorithms to manage close-to-the-hardware resources with objects. With runtime costs that are similar to a good C design.

example context:

  • you want to use PIO state machines (example:  you have a set of stepper motors that you want to control with PIO state machines)
  • you only want to program the PIOs and state machines that have a stepper motor assigned to it
  • you are a C++ fanboy and want to handle the motors with objects
I'm using stepper motors and Pico PIO co-controllers as real world examples. 
The mechanism works for many real world designs where you want to process, filter, aggregate ...
(I also used these concepts for a GPS data parser)

In this little post, I use STL algorithms that take care that:

  • a PIO is only programmed if at least one of its state machines serves a motor, and
  • a state machine is only initialised if it serves a motor.

pseudocode:

if a PIO is used

  program it

  initialise its state machines that you are using

post condition 1: PIOs and state machines that are not used, are not touched
post condition 2: PIOs that are used are programmed
post condition 3: state machines that are used are initialised

declare a motor handler class

In this post, the class that can handle a motor is called demo_handler, because this is demo code. For a real class that can handle a stepper motor, check pio_stepper_lib.

struct demo_handler {
    demo_handler(PIO pio, uint sm) : pio(pio), sm(sm) {}
    PIO pio;
    uint sm;
};

I tried to make this as small as possible. Just enough to be usable in this example.

declare an STL container with stepper motor handlers

In my example, I have 6 motors. 4 run on the state machines of the first PIO. 2 others run on the second PIO.

image

I use an array, because that's a good choice for an embedded application container. 

std::array<demo_handler, 6> handlers {{
      {pio0, 0}, {pio0, 1}, {pio0, 2}, {pio0, 3}
    , {pio1, 0}, {pio1, 1}
}};

Use STL algorithms to program only relevant PIOs and State Machines

I only want to load my PIO code in the PIOs that have at least 1 motor assigned to them. In this example I use PIO 1 and 2. If this runs on a Pico2, I don't want to program PIO3, because it doesn't control any stepper motor.

any_of

I use the stl any_if algorithm to check, for each PIO, if my container has at least one motor for that PIO. If yes, I program it.

    for (uint u = 0u; u < NUM_PIOS; u++) {
        if (std::ranges::any_of(handlers, [u](auto& h){ return h.pio == PIO_INSTANCE(u); })) {
            uint offset  = pio_add_program(PIO_INSTANCE(u), &run_program); 
            
            // more code later :)
        }        
    } 

This code loops over the available PIOs on the Pico. only if it finds at least one motor in the array that runs on that PIO, it programs it.

for_each with filter

Then, it'll initiate each used state machine of that PIO:

            for(auto &h : handlers | std::views::filter([u](const auto& h){ return h.pio == PIO_INSTANCE(u);})) {
                run_program_init(h.pio, h.sm, offset);

pio_add_program() and run_program_init() are functions that any PIO developer will recognise. They are part of the Pico C SDK.

The for will only invoke code on the items in the container that match the current PIO in our loop. The filter takes care that the loop only returns items that match that condition. For Linux users: this is similar to filtering pipes.

everything together

This is all of the code. It takes care that only the used PIOs are programmed. And that only the used state machines of those PIOs are initialised:

    // program each PIO, and initialise each sm - only if they are used
    for (uint u = 0u; u < NUM_PIOS; u++) {
        if (std::ranges::any_of(handlers, [u](auto& h){ return h.pio == PIO_INSTANCE(u); })) {
            uint offset  = pio_add_program(PIO_INSTANCE(u), &run_program); 
            for(auto &h : handlers | std::views::filter([u](const auto& h){ return h.pio == PIO_INSTANCE(u);})) {
                run_program_init(h.pio, h.sm, offset);
            }
        }        
    } 

This may look odd to a C++98 user, or if you are used to C. It compiles to efficient code though.
There are 4 learning ramps to climb:
  • the OO ramp. The motor handlers are objects. This will be common to any C++ user: learn classes
  • the stl container ramp: all motors handlers reside in an stl array:  learn stl containers
  • the stl array is defined via a template. It is specialised (and perfectly sized) to manage motor handler objects: learn templates
  • the stl algorithms. any_if and filter take care that only those objects inside the container that match your condition (predicate) are handled: learn modern C++

I put embedded friendly in the title of this post, because this is resource light. If you would write similar functionality in C, your logic would have a comparable cost.

Thank you for reading.

  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps 18 days ago in reply to Jan Cumps +1
    > I bought a book C++Standard Library by Rainer Grimm.
  • Jan Cumps
    Jan Cumps 10 days ago in reply to pvit

    > the same as std, but without dynamic allocations everywhere

    There's the std::array container that is suited for embedded. No dynamic allocation.

    I've been busy checking the latest C++26 standard and GCC 15, to check the (b)leading edge functionality - and to check what's in it for low resource embedded (ARM M, ARM R, small RISC-V...).

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 10 days ago in reply to pvit

    i check it regularly, more for learning than to use it. I also visit the boost projects feom tie to time - specificly when they are doinf proof-of-concepts for new c++ standard proposals.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • pvit
    pvit 11 days ago

    I'd suggest you take a look at the Embedded Templates Library https://www.etlcpp.com/. It's more focused on embedded-specific demands and portability between c++ standards.

    ~ the same as std, but without dynamic allocations everywhere, with backports of new features like string_view to ancient C++11 compilers when nothing better is available on your target MCU. And of course, both can be used at the same time, if needed.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 18 days ago in reply to Jan Cumps

    > I bought a book

    C++Standard Library by Rainer Grimm.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 18 days ago in reply to colporteur

    for these somewhat more involved topics, gasping doesn't do the trick :) - I tried to master it by staring at the code, and got nowhere.

    I needed to find my teenage eagerness back, to dig into every aspect of the language and get it. I bought a book and tried all of the subjects. Stepped trough all code with a debugger. Until It stuck.

    Also, Cisco has a free training: netacad.com/courses/c-plus-plus-advanced

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube