My embedded RTOS notes


Started 08Jan2019, updated 01Mar2026 (Fully fledged vs. kernel vs. library based OS vs. etc.. RTEMS ref [3], #Mbed)

This page is in group Technology and is a blog note where I will try to have a fresh view (as of 2019) of what might be going on with concurrency and Real-Time Operating Systems (RTOS) in the small embedded systems world. Here I would think mostly of what might run on platforms like ARM-based Arduino boards. I work mostly with XMOS boards and program in the XC language, so I would tend to view this through those glasses. So I would think of a big loop in main as only a single-threaded start in the boy’s (or girl’s) room, and would want real support for processes and then the «thread-safer» would be the better. Remember that a small embedded system landed on a comet in 2014 (see below), and many of them are indeed safety-critical.

Intro

This note started its life as cut and paste from an earlier note: My WiFi101 library port. There in particular, concurrency in the Arduino world was discussed. I guess that also the My SafeRTOS notesIEC 61508 and (safe?) concurrency and IEC 61508 and programming paradigms may relate to this note.

Fully fledged vs. kernel vs. library based OS vs. etc..

I haven’t really been too observant on the differences between these. For embedded I have never used any «fully fledged» OS, only library based kernels or runtimes. Even if many of my colleagues used Linux on embedded, it was perhaps more of a library based kernel than a fully fledged Linux distribution. The run-time or schedulers we wrote for smaller embedded processors of the time didn’t need much extra libraries. As an afterthought, as I see it, much of this would be close to protothreads or coroutines (Wikipedia: Protothread or my early RTX-51). (Thanks you who sent me a mail with «You should add protothreads to your compendium of multitasking zoo»). It was only after I retired that I started to use 32 bits processors, except for the transputer we used in the nineties. I guess that exceptions to the home grown runtimes I worked with would be occam on the transputer (by INMOS) and XC on XCORE (by XMOS), where much of the runtime (OS?) code is implemented as hardware assembly and microcode instructions and/or even separate hardware units. More in NOTES FROM THE VAULT.

Finally, I have had no experience with separation kernel-based hypervisor type RTOSes. These  support multiple logical partition types for various operating systems, like the commercial PikeOS – which is considered being in the L4 microkernel family. These technologies would probably make it less hard to get approvals like 065:[IEC 61508] (which I became familiar with at work) and isolate for different criticality levels (also timing / temporal isolation I think). When I first saw the XCORE architecture I thought that this architecture probably should make it into these kind of segments. However, to my surprise is seems like it’s been more embraced by the audio people. It’s excellent for it, but also for quite some approval-needy embedded systems (like fire detection with IEC 61508, aeronautics with DO-178C, road vehicles, functional safety with ISO 26262 or railway, with like EN 50716. Even cybersecurity with Evaluation Assurance Level and EAL5.) But I am not an expert on these matters, having only smelled a little of it as I passed  some seats of my life’s technological isle.

Arduino concurrency

Looping as fast as possible leaves no room for concurrency

SimpleWebServerWiFi_Teig.ino contains loop(). It just loops. I made a counter (unsigned long) and printed out its value every one mill counts. It took about 56 seconds to count to 5 mill, so it’s about 11.2 μs to loop around just counting up that value. It runs as fast as it can.

This is bad architecture. Lucky for the demos that there are no background or foreground tasks that have own state. There is no task / process / thread here. It’s as single threaded as possibly possible.

Disclaimer: Of course the ARM processors have a lot of hardware blocks that would live their own lives. And they would communicate with the main loop of running objects through interrupts. This is concurrency that all processors would need and have, and they have had it since 1954? They certainly make even the simplest of processors do more than one thing quite seamlessly. But it’s not concurrency at the occam, Ada, go, XC etc. level that I want to have here. The quite new (2017) Apache mynewt OS is also interesting in this context. I do not want my aquarium code and the communication to be in some one outer loop. One could say that each process, task or thread consists of local loops all over the place in the software. Then there is a scheduler that controls when each loop is run. Basically this is the basic theme of all of my Technology blogs and papers. But there’s more to it:

Arduino Scheduler concurrency is low-level yield-based

Arduino supplies an «experimental» Scheduler,  Scheduler (see https://www.arduino.cc/en/Reference/Scheduler) that’s «cooperative» (they don’t cooperate on data, just on passing of control). It’s based on starting an additional loop with Scheduler.startLoop(new_loop). Then new_loop must run a Scheduler.yield so that the original loop also will run. This is the lowest level of concurrency with no support for communication between them and no structured way to avoid busy poll.

Have a look at their blinking LED example (here). No no-skew timer. No communication between the loops. No communication into or out of the loops. Besides, all cycles are burned. And the cognitive understanding av what a task is probably isn’t easy to grasp in the light of how to next solve the missing points.

Later, working with the port of the RadioHead library My aquarium’s data radioed through the shelf, I discovered lots of YIELD; in the code. Like in file RHGenericDriver.cpp:

// Blocks until a valid message is received
void RHGenericDriver::waitAvailable()
{
    while (!available())
	YIELD;
}

Now it can do other things instead of blocking. (Aside: I have discussed blocking in Not so blocking after all.) In file RadioHead.h YIELD is defined as yield(); for Arduino is 1.55 or more. I then searched my installed libraries and found the Scheduler files. In Scheduler.h:

// Copyright (C) 2012 The Android Open Source Project
class SchedulerClass {
public:
	SchedulerClass();
	static void startLoop(SchedulerTask task, uint32_t stackSize = 1024);
	static void start(SchedulerTask task, uint32_t stackSize = 1024);
	static void start(SchedulerParametricTask task, void *data, uint32_t stackSize = 1024);

	static void yield() { ::yield(); };
};

We see that it’s based on what we saw above, new Loops may be started as tasks. Looking inside Scheduler.cpp then coopTaskStart, coopDoYield are assembly code, for ARM Arduinos (I think).

Adding YIELD; or yield(); to my .ino top level file for testing the RadioHead library did compile. I use ARM Arduinos. It compiles, yes, but yield(); probably is empty code. I edited in Scheduler.cpp and made sure it would not compile. It did. I then did Sketch | Include Library | Scheduler, and #include <Scheduler.h> arrived in the code. Then it didn’t compile before I had fixed the code again. So, in the RadioHead library blocking seems to block since I cannot find and start or startLoop in the code that would give the code any place to yield to.

I have queried about the sanity of the above inferring on the radiohead-arduino group, see YIELD; in RadioHead code.

Later I also found Ivan Seidel’s ArduinoThread (https://github.com/ivanseidel/ArduinoThread) and downloaded it. It’s a wrapper around callbacks for «blinking of LEDs» and it does not use C++11’s std::thread class. I have found no Arduino stuff that uses those native threads. Also, there is no communication between them.

I will not do my whole story here. Almost all of my technical blog notes deal with concurrency. Just search for yield, generator, CSP, concurrency or blocking in the search window above, or visit the main Technology blog note list here and see if you find a thread to pull.

That being said, to me this Scheduler.yield may be a starting point for building a CSP-type Scheduler on top. This may be interesting in the future.

Zephyr operating system

Moved to My Zephyr RTOS notes (Historical note).

RTEMS: Real-Time Executive for Multiprocessor Systems

I was (in Sep2019) pointed to this RTOS by a guy who works with space systems. He said that he met quite a few people who were talking about and using this RTOS. I start with a quote from Wikipedia:

RTEMS does not provide any form of memory management or processes. In POSIX terminology, it implements a single process, multithreaded environment. This is reflected in the fact that RTEMS provides nearly all POSIX services other than those which are related to memory mapping, process forking, or shared memory. RTEMS closely corresponds to POSIX Profile 52 which is «single process, threads, filesystem» [1] (4Sep2019)

This would mean that I should look out, because this smells like something I have seen before. No real processes (like «real» operating systems do), but threading («not concurrency»). That goes for stereotyping. But still they send it into outer space, so their concurrency model can’t be that bad. Quite some must have been thinking over this for the previous forty years.

I have been working with (more or less) real time systems, (more or less) concurrent systems, but they were safety critical and approved as such. Some in embedded boxes that at this very moment run in fire detection systems on cruise ships.

Update 06Feb2026. A guy showed me [3] in a mail. «2016 was ‘yesterday'» he wrote. During my career (and afterwards, like with the Beep-BRRR code (in XC on XCORE) My Beep-BRRR pages) where there is a lot of realtime-critical functions, I have never stumbled across priority inheritance, like after the code was written. I have had the tools to factorise it away from runtime code. For occam and the transputer I had only two task priorities, but any number of PRI ALT levels and an algorithm to ensure fairness. For XC it’s about one «logical thread» (new word these days for the same: HART for hardware task) plus using select, most often prioritised. Or select used as «don’t care» if more than one guard is ready when it’s treated. Therefore this priority inheritance stuff hasn’t been a problem I have experienced. Also see my note Nondeterminism. I have also used the XC interface function calls, a very smart pattern with kind of hidden task communication, kept running by the XC compiler for me (but see 219:[Chan or interface when critical timing]) and my own knock-come deadlock-free pattern (here).

[1] https://en.m.wikipedia.org/wiki/RTEMS
[2] https://www.rtems.org
[3] Verifying Nested Lock Priority Inheritance in RTEMS with Java Pathfinder by Gadia, Artho and Bloom. Read at https://people.kth.se/~artho/papers/gadia-2016.pdf

Timed C

Update Nov2021: A PhD student pointed me to this rather nice extension to the C language.

Timed C: An Extension to the C Programming Language for Real-Time Systems. Saranya Natarajan and David Broman. In the Proceedings of IEEE Real-Time and Embedded Technology and Applications Symposium (RTAS), Porto, Portugal, IEEE, 2018. See https://people.kth.se/~dbro/papers/natarajan-broman-2018-timed-c.pdf

Mbed

I have been on the «armMBED» (type style on the intro then) mailing list since early 2022, but haven’t really studied it. But they got my attention when I discovered that they effectively had been replaced. (05Feb2026)

The interesting thing for me is the following, from https://mbed-ce.dev:

Mbed OS Community Edition: Features of Mbed OS: RTOS (or not)
Mbed OS includes the Keil (pronounced «Kyle») RTX5 RTOS, wrapped with a C++ API that makes it easy to use. This lets you use threads, mutexes, semaphores, condition variables, and inter-thread queues just as easily, or even more so, than if you were using desktop C++.

See the 24Aug2024 page https://os.mbed.com/blog/entry/Important-Update-on-Mbed/ (or in the future, on the Wayback Machine of the Internet Archive, here).

I have taken the freedom to copy/pasting some from the above url:

Important Update on Mbed

Today we wanted to share some important updates with the Mbed community:

  • The Mbed platform and OS will reach end of life in July 2026, when the Mbed website will be archived and it will no longer be possible to build projects in our online tools
  • The device software – Mbed OS – is open source and will remain publicly available, but is no longer actively maintained or supported by Arm
  • The Mbed TLS project is unaffected by this announcement and continues to be supported as part of the TrustedFirmware community project.

What can I use instead?

A community fork of Mbed OS – Mbed CE – is under active development. If you would like to continue contributing to or using Mbed we recommend starting here. (I found it at https://github.com/mbed-ce)

For a free-to-use embedded development environment we recommend Arm Keil MDK v6 Community Edition, which works seamlessly with the CMSIS standard and CMSIS RTX RTOS:

For rapid prototyping and educational purposes, we suggest you investigate:

For an alternative RTOS we recommend:

For embedded Linux projects we recommend:

(They also refer to:) Mbed TLS, TF-PSA-Crypto at https://www.trustedfirmware.org/projects/mbed-tls/
.←

2 kommentarer til “My embedded RTOS notes

Leave a Reply

Dette nettstedet bruker Akismet for å redusere spam. Finn ut mer om hvordan kommentardataene dine behandles.