Echtzeit-Betriebssystem Zephyr im Überblick
Linux ist mit seinem vielschichtigen Aufbau und komplexen Speicherverwaltung geeignet für mittelkleine Embedded-Systeme bis hin zu den grössten Serversystemen. Das ist eine enorme Skalierbarkeit wie wir sie bei sonst keinem anderen Betriebssystem finden. Aber das Feld der ganz kleinen Embedded-Systeme, über den Bare-Metal-Systemen und kleiner als 4 MB RAM kann nicht abgedeckt werden. Genau diese Lücke füllt das Open-Source Echtzeit-Betriebssystem Zephyr.
Erreicht wird dies unter Anderem durch Reduzierung der Abtraktionsschichten. Während bei Unix und Linux die Devise "Alles ist eine Datei" gilt, was bedeutet dass (fast) alle Objekte auf die Dateischnittstelle (open, read, write, ...) gemappt sind.
Bei Zephyr gibt es diese Abstraktion nicht. Für jedes Subsystem und jeden Hardwaretyp gibt es eigene Funktionen. Das heisst aber nicht, dass es für jeden Chip eigene Funktionen gibt, sondern es gibt jeweils eine API für den Hardwaretyp und von dieser API als Abstraktionsschicht werden die Funktionen des herstellerspezifischen Treibers aufgerufen. Beispielsweise gibt es eine Funktion i2c_read() aus der I2C-API und von dieser werden dann die Treiberfunktionen aufgerufen, welche dann den eigentlichen Hardware-Register-Zugriff durchführen. Dieser Funktion i2c_read() wird ein Zeiger auf ein Device (struct device) mitgegeben, damit die Funktion auf das hardwarespezifische Gerät zugreifen kann.

Diese Referenz auf das Device wiederum wird aus dem sogenannten Device-Tree heraus generiert. Dieser Device-Tree spielt bei Zephyr eine ganz wichtige Rolle, da er die Hardware mit ihrem Busaufbau und den vorhandenen Geräten beschreibt. Das besondere an Zephyr ist dass dieser Device-Tree bereits zur Compilierzeit aufgelöst wird und die Device-Objekte angelegt werden. Zur Laufzeit ist der Device-Tree im Betriebssystem gar nicht mehr vorhanden. Dadurch kann auf resourcenintensive dynamische Speicherverwaltung bei der Auflösung des Device-Trees verzichtet werden.
Bei der Interprozess-Kommunikation existieren bei Zephyr neben den bekannten Klassikern wie beispielsweise FIFO, Message-Queue und Memory-Slabs auch Zephyr-spezifische wie zum Beispiel der ZBus (Zephyr-Bus). Dabei handelt es sich um eine sehr schlanke Busimplementierung für M-zu-N-Kommunikation zwischen Threads. Das besondere daran ist dass der Bus selber keinen eigenen Thread für die Übertragung der Nachrichten benötigt, wie dies beispielsweise beim DBus bei Linux der Fall ist. Stattdessen werden die Nachrichten entweder direkt im Kontext des Senders an eine Callback-Funktion des Listeners zugestellt oder ein Subscriber über das Vorhandensein einer neuen Nachricht auf dem Bus benachrichtigt und dafür aufgeweckt. Auch die Interprozess-Kommunikation kommt ganz ohne zusätzliche Abstraktionsschichten aus und ist daher ganz leichtgewichtig.

Besonderes Highlight ist zweifelsohne die Connectivity. Von Bluetooth über das klassische Networking bis zu USB ist kaum etwas zu finden, das nicht durch Zephyr unterstützt werden würde.
Bei der Entwicklung trifft man auf die aus der Linux-Entwicklung bekannten Werkzeuge wie beispielsweise C, Python, Kconfig, CMake, git und so weiter.
Eine Besonderheit ist das Metatool west. Es dient dazu der unterschiedlichen Tools zu vereinfachen. Die beginnt beim Aufsetzen des Repositories samt der erforderlichen Module, über den Buildvorgang, das Debugging bis hin zum Flashen auf das Target. Beinahe alle relevanten Vorgänge können von einem Tool ausgehend durchgeführt werden. Dies erleichtert den Einstieg für den Neuling ungemein.
Theoretisch und auch praktisch lässt sich Zephyr auch auf grossen Systemen mit vielen GB an RAM verwenden. Da stellt sich dann aber die Frage ob man bei so grossen Systemen wirklich auf die vielen Features welche Linux bietet verzichten möchte.
Zephyr ist ein ideales Open-Source Betriebssystem für kleine Embedded-Systeme wenn Bare-Metal zu aufwändig wird und auf gemeinsam entwickelte Treiber, Subsysteme und Kernel verwendet werden soll.
Im Bild ist ein typisches Projektbeispiel dargestellt.
