Tips for Migrating from Superloop/RTOS to QP Framework

migrating to QP framework
Table of Contents
Tags:   

A developer interested in the QP/C framework has recently posted the following questions on the qpc GitHub repository:

  1. For developers transitioning from traditional superloop or RTOS task-based embedded architectures, what is the recommended migration strategy for restructuring an existing firmware project into QP/C active objects and hierarchical state machines?
  2. In resource-constrained MCUs, what practical guidelines are recommended for balancing the benefits of hierarchical state machines and active objects against RAM/flash overhead and event queue sizing?
  3. When integrating QP/C with vendor SDKs or existing peripheral drivers (such as STM32 HAL/CMSIS-based projects), what architectural boundaries are recommended to keep hardware abstraction, event flow, and application logic cleanly separated?

Here is my reply:

Thank you for the interest in QP frameworks.

Before diving into architecture and migration strategy, I strongly recommend the following practical learning path. It gives you the necessary intuition for how active objects, event queues, and hierarchical state machines behave in practice:

  1. Watch the videos in the “Beyond the RTOS” playlist. They explain the paradigm shift from traditional superloops/RTOS tasks based on blocking to event‑driven, non-blocking active objects and hierarchical state machines.
  2. Install the QP‑Bundle and build/run the provided examples on the host. Running the examples on your PC (no hardware required) is the fastest way to understand the event-driven execution model. Here you could watch the videos from the State Machines playlist.
  3. Get one of the inexpensive boards supported by the examples and run them unmodified. Build, flash, and debug the examples as-is first. Once everything works, start introducing small changes gradually so you can see how the architecture responds.
  4. Copy and adapt the DPP example for your specific board. DPP is intentionally structured as a clean, minimal reference for real-time event-driven design. Adapting it to your hardware is the most reliable way to bootstrap a new QP/C project.

With that foundation in place, here are direct answers to your three questions:

1. Migration strategy from superloop/RTOS tasks to QP/C active objects and HSMs

The recommended approach is incremental refactoring, not a rewrite.

  • Keep using your RTOS but add to your application the QP framework and the QP-port to the RTOS.
  • Identify the first RTOS thread most easy to convert into active object.
  • Convert this one thread into an active object replacing all blocking waits and shared-variable signaling with events and time events.
  • Once stable, refactor internal logic into hierarchical states to eliminate duplication and clarify modes.
  • The “hybrid” system (a combination of threads and active objects) is OK but remember NOT to mix paradigms within a single Active Object. Specifically, never call blocking RTOS mechanisms from your active object.
  • Gradually retire legacy threads one by one, remembering that you can combine functionality from multiple threads into an active object (because it remains responsive to all events).

The DPP example is an excellent template for this process.

2. Balancing HSM/AO benefits with RAM/flash constraints

Event-driven paradigm is generally more efficient for resource constrained systems than the sequential paradigm based on blocking. In small MCUs, the key is to use the provided QP mechanisms rather than duplicating them by inventing your own.

  • Use one of the custom kernels built into QP (QV, QK) to save RAM for the stack (savings of 80% compared to the RTOS threads requiring private stacks)
  • Use QP events and event pools as data buffers: produce data directly into events rather than copying the data from local buffers to events.
  • Measure the worst-case event pool and event queue usage. QP provides internal “low watermark” variables that store the worst-case usage. You can then inspect them in your debugger (or output them with QS software tracing). This will allow you to save RAM by avoiding oversizing the pools and queues.
  • Use hierarchical state machines to avoid duplication of behavior and this save code space (ROM).

Running the provided examples on your board will give you a concrete sense of memory footprint and queue sizing.

3. Architectural boundaries when integrating QP/C with vendor SDKs (e.g., STM32 HAL/CMSIS)

QP works well with many SDKs, HALs, and CMSIS.

For example, QP works well with STM32 HAL, as demonstrated in the examples (see qpc/examples/stm32cube) and videos


QP active objects + hierarchical state machines: All application logic, modes, sequencing, and event flow. AOs call BSP functions for hardware actions and receive events from ISRs. This structure keeps hardware details out of your state machines and ensures deterministic, event-driven behavior.