Moving to a RTOS on the RP2040

MicroPython and “Do You Even Need an RTOS?”

  • Several commenters report success using MicroPython with async/await for “real‑time enough” applications (steppers, LEDs, buttons) on RP2040/ESP32.
  • Hardware peripherals (PIO, timers, RMT, interrupts) can offload precise timing from Python, making cooperative multitasking viable for moderate step rates.
  • Some argue that for many projects (e.g., PTZ controller) this is simpler and more productive than adopting a full RTOS or large C codebase.

Rust, Embassy, RTIC, Hubris

  • Multiple people are moving RP2040 projects to Rust with the Embassy async framework; they find it removes much of the need for an RTOS while giving memory safety.
  • RTIC is seen as simple and lightweight but currently single‑core for RP2040 and harder to modularize; Embassy has its own async‑focused HALs and better ergonomics.
  • Advice: start with rp2040-hal, add Embassy/RTIC once task management becomes painful.
  • Hubris is mentioned as an attractive Rust microkernel for more structured systems; Embassy is suggested for tighter memory budgets.

RTOS Options: FreeRTOS, Zephyr, ThreadX, NuttX, Others

  • FreeRTOS is considered a de facto standard, especially when SOC vendors ship it and related stacks.
  • ThreadX (now open source) is praised for elegance and a POSIX layer; PX5 and RIOT are noted but proprietary cost or niche status limit appeal.
  • Zephyr fully supports RP2040; some say it’s easy and powerful with integrated stacks (e.g., Bluetooth, mcuboot/OTA).
  • Others find Zephyr bloated, slow to build, and confusing, especially for tightly constrained OEM firmware.
  • NuttX and ChibiOS are mentioned positively but with weaker or problematic RP2040 support.

Zephyr’s Hardware Abstractions vs Minimalism

  • One camp values Zephyr’s cross‑SOC abstractions, central Bluetooth and OTA story, and “less hacky Arduino” feel for prototypes.
  • Another camp (focused on shipping, cost‑sensitive devices) prefers minimal, self‑written HALs over heavy vendor abstractions, citing control, footprint, and predictability.
  • Consensus: SOC‑vendor choices often drive RTOS selection in practice.

Printf, I/O, and Concurrency Pitfalls

  • The original article’s printf problems are attributed to toolchain/newlib/heap issues, non‑reentrant printf, and calling it from multiple threads.
  • Suggestions include: per‑thread buffers, avoiding dynamic allocation, message‑passing logs through a single thread, Pico SDK’s pluggable stdio, UART interrupts, RTT via debuggers, and careful newlib configuration.
  • Several emphasize that “printf not working” is usually not an RTOS bug but a C library and concurrency design issue.

Tooling, Python vs Native, and Reproducibility

  • Strong criticism of Python‑based build tooling for embedded: version skew, dependency mess, non‑reproducible setups.
  • Advocates prefer statically linked tools (C/C++/Rust/Go) and integrated managers like Cargo; Rust + rustup is highlighted as particularly smooth for RP2040 flashing.
  • Others defend container/VM‑based toolchains (or CI‑built artifacts) for reproducibility, though some report USB/integration friction and container bloat.

PLCs vs Microcontrollers

  • For deterministic industrial control, some favor PLCs (Codesys/Twincat, EtherCAT ecosystems) over DIY RTOS setups; they “just work” together with strong real‑time guarantees.
  • Counterpoints note PLC cost, proprietary ecosystems, and poor integration with non‑industrial systems; for low‑volume or hobby gear, microcontrollers remain attractive.

Rolling Your Own Scheduler

  • A few contributors bypass RTOSes entirely by implementing simple green‑thread or timer‑callback schedulers on Cortex‑M, sometimes by hooking Pico SDK macros.
  • They report these lightweight approaches are sufficient for polling sensors, control loops, and basic multitasking, and avoid RTOS complexity—though without strong guarantees.