Home > On-Demand Archives > Talks >

Practical Strategies for Developing with the QP Framework

Jeff Gable - Watch Now - EOC 2025 - Duration: 44:39

Practical Strategies for Developing with the QP Framework
Jeff Gable

Quantum Leap's QP framework offers a compelling alternative to traditional RTOS solutions for hard real-time, high-reliability embedded software development. The event-driven hierarchical state machine framework and implementation of the actor model are excellent for effectively managing complexity and preventing common concurrency issues. However, good resources and examples of design patterns using QP for common microcontroller use cases are limited.

This talk provides an opinionated guide to developing a complex microcontroller application using the QP framework, in C or C++. I’ll cover device drivers, shared I2C and SPI buses, board communication with USB and/or UART, host-based unit testing, and design patterns for controlling electromechanical systems.

By the end of this talk, you should have a roadmap for how to use QP in your next microcontroller project.

M↓ MARKDOWN HELP
italicssurround text with
*asterisks*
boldsurround text with
**two asterisks**
hyperlink
[hyperlink](https://example.com)
or just a bare URL
code
surround text with
`backticks`
strikethroughsurround text with
~~two tilde characters~~
quote
prefix with
>

zhardware
Score: 0 | 2 weeks ago | no reply

Hey Jeff, this was a great video. Thanks for sharing your experience using QP. If I didn't misunderstand, I'm curious why you don't use QM for building your applications? Since we must think at a higher level of abstraction when using QP, it makes sense to use QM, rather than work with C/C++ directly. Does it make it easier to write tests with? Or perhaps for you, thinking in terms of C/C++ headers/APIs feels more natural?

RaulPando
Score: 0 | 1 month ago | 1 reply

Thank you Jeff for a quality presentation as always, I think it pays a fair tribute to QP's framework.
Since you seem to be following a solid development process with a quality framework, I suspect there is little opportunity for debugging which is great :D. I was wondering if you had any views on how much nut&bolt/low-level knowledge of the abstractions was required if one wanted, or needed, to step through the execution of an asynchronous application leveraging the QP framework and; if any, how the debugging experience compares in general terms to introspecting a task scheduled by an RTOS when usually keeping a coherent context with other threads needs preserving. Similar or does the decoupling offered by AOs with pub/sub improve that experience too?

Jeff GableSpeaker
Score: 1 | 4 weeks ago | no reply

I don't think a strong low-level knowledge of QP internals is necessary at all. The only exception to this is when you do make a mistake and hit one of QP's assert statements, it can be a little challenging to figure out the reason for it. Matthew Eshleman also created a repo of better documentation of QP assert codes to help with this:
https://github.com/covemountainsoftware/qassert-meta

Setting breakpoints and stepping through your application code is just fine, and I'll sometimes do the dance of setting a breakpoint at a publish statement, and then setting another breakpoint where that event is supposed to be used, and find my error that I forgot to subscribe to the event. Again, good unit testing helps eliminate most of these.

datamstr
Score: 0 | 1 month ago | 1 reply

Excellent presentation Jeff!

Jeff GableSpeaker
Score: 0 | 4 weeks ago | no reply

Thanks!

John_Singleton
Score: 0 | 1 month ago | 1 reply

Thank you, Jeff. I'm just starting to learn about HSMs using Zephyr's State Machine Framework. This talk might help me stick with it while I climb the learning curve.

Jeff GableSpeaker
Score: 0 | 4 weeks ago | no reply

Thanks John! I haven't used Zephyr's state machine framework, but from a brief review, it's not nearly as powerful as QP. But, still probably much better than rolling your own. Curious to hear how it goes for you.

SteveM
Score: 1 | 1 month ago | 1 reply

1) You mention making each device an AO. Would you do this at the "Driver" level or "BSP" level?
2) How do I convince management to pay the big business licencing fees when FreeRTOS and Zephyr are available and already in use at no extra cost?

Jeff GableSpeaker
Score: 0 | 1 month ago | no reply

I tend to make a separate AO for everything at the device driver level. Rarely if ever at the BSP level. That’s personal preference of course, but I want to reuse all my state machines across targets and app builds.

As at as licensing fees, QP is relatively inexpensive. $3-4k one-time (no royalty) for a project. Far far cheaper than it would be to pay you to try (and likely fail) to replicate its functionality. The abstractions are simply better than the primitives in FreeRTOS. I haven’t used the HSM framework in Zephyr but a brief review of the documentation suggests to me that it is nowhere close in terms of utility and usability. And remember, QP has a port to Zephyr so you can use Zephyr and take advantage of all the wonderful libraries, middleware, and board support, but still layer QP on top of it.

Tommy
Score: 1 | 1 month ago | 1 reply

Around minute 38, do we not see the intended screen?

Jeff GableSpeaker
Score: 0 | 1 month ago | no reply

Oops! Sorry Tommy, you’re absolutely right. Sorry about that. The pdf of the slides has the correct screen.

SimonSmith
Score: 0 | 1 month ago | 1 reply

Good to hear the mention of Micrium uC/OS-III, which felt like it died when it was open-sourced a few years back around the time when SiliconLabs took it over and FreeRTOS took off. It's well documented, easy to use and has full source code.
https://github.com/weston-embedded/uC-OS3
https://micrium.atlassian.net/wiki/download/attachments/132386/100-uCOS-III-ST-STM32-003.pdf?version=1&modificationDate=1383921876000&cacheVersion=1&api=v2

acassis
Score: 1 | 1 month ago | no reply

Hi SimonSmith,
that is true, if you use SiliconLabs chips, then uC-OS is a good option!

Miro
Score: 1 | 1 month ago | no reply

Hi Jeff,
Thank you for presenting QP. You captured the benefits of the event-driven Active Object model combined with hierarchical state machines more succinctly than I have. The functional safety standards, such as IEC 61508 and IEC 62304 (medical), also highly recommend these techniques, so I understand why you find them useful in medical devices.

I'm happy to see the growing interest in safer concurrency than the "naked" RTOS threads and state machines as the most effective "spaghetti reducers". To this end, your QP presentation nicely complements the other sessions of this conference, specifically "ActiveCpp: Active Objects for Modern C++" by Amir Alavi and "Visualize Your State Machines" by Adam Fraser-Kruck. QP demonstrates how to combine the two concepts in a lightweight package suitable for hard real-time embedded MCUs, such as ARM Cortex-M.

QP also ties to the other hot topics of this conference related to memory safety and resource ownership ("Memory Safety Dance" by Tim Guite and "Rust and Medical Device Development" by Milica Kostic). By replacing direct resource sharing with thread-safe events, Active Objects naturally prevent most concurrency hazards. Also, the "zero-copy event management" in QP is based on the reference-counting algorithm, which results in the event ownership rules almost identical to the Rust's Rc<> smart pointers. QP also supports immutable events. Both these features predate Rust and are available in C and C++. (Come to think, a native Rust version of QP (QP/Rust) seems like a natural progression.)

My one technical comment to your presentation is to take even greater advantage of the QP event management system. Specifically, instead of using external data buffers (e.g., for DMA transfers), you can use the QP mutable events directly and thus let QP handle all the buffering for you in a thread-safe way. Please note that the event ownership rules allow you to keep the event allocated with Q_NEW() beyond the RTC step for as long as you like. Among others, you can use the event's payload as the buffer (and pass a pointer to it to the DMA hardware). Only after the buffer fills up, you eventually post or publish the event (thus ending your ownership), at which point you can allocate the next event to have another working buffer.

OUR SPONSORS & PARTNERS