Suchen

Auswahl und Einsatz eines Embedded-Betriebssystems für Mikrocontroller

| Autor / Redakteur: Frank Benkert * / Sebastian Gerstl

Embedded-Entwicklungsprojekte sehen sich zu Beginn meist immer mit der gleichen, grundlegenden Frage konfrontiert: Mit oder ohne Betriebssystem? Und wenn mit, mit was? Anhand eines konkreten Beispiels wird hier erklärt, welche konkreten Fragen zur Wahl des richtigen Embedded OS zu klären sind.

Firmen zum Thema

Möchte man in seinem Embedded-Projekt ein Betriebssystem auf seinem Mikrocontroller auswählen, sieht man sich oft mit einer Vielzahl von Auswahlmöglichkeiten konfrontiert. Wie kann man sicherstellen, dass das gewählte Betriebssystem auf das "richtige" ist?
Möchte man in seinem Embedded-Projekt ein Betriebssystem auf seinem Mikrocontroller auswählen, sieht man sich oft mit einer Vielzahl von Auswahlmöglichkeiten konfrontiert. Wie kann man sicherstellen, dass das gewählte Betriebssystem auf das "richtige" ist?
(Bild: gemeinfrei / CC0 )

Welches Betriebssystem wähle ich als Entwickler für mein Embedded-Projekt aus? Was eignet sich für den Mikrocontroller, den ich einsetzen möchte, am Besten? Es gibt für diese Fragen natürlich keine allgemeingültige Antwort. Betrachtet man jedoch die Anforderungen an das neue Produkt genauer, so ergibt sich die Antwort oft von selbst. Welche Fakten helfen aber wirklich bei der Entscheidung? Wie erarbeitet man diese Informationen? Welche Fragen muss man stellen? Wer kann diese beantworten?

Im Folgenden soll anhand eines Projektes aus der Praxis aufgezeigt werden, wie dieser Auswahlprozess und die spätere Integration erfolgreich gelingen kann. Als Vorlage dient ein reales Projekt, welches die Neuentwicklung einer Gerätefamilie zur Steuerung von Großmotoren zum Ziel hatte. Als Plattform kam ein ARM Cortex-M7 von ATMEL (automotive Variante) zum Einsatz. Dieser Beitrag soll allerdings als eine allgemeine Grundlage für Embedded-Projekte aller Art dienen. Darum beziehen sich Formulierungen (wo immer möglich) nicht direkt auf das Projekt selbst.

Was ist ein Betriebssystem?

Um die Frage nach dem „Mit oder Ohne“ überhaupt stellen zu können muss klar sein, was die einzelnen Beteiligten unter dem Begriff „Betriebssystem“ verstehen.

Je tiefer ein Entwickler im System arbeitet, desto differenzierter ist seine Sicht auf das „Ding“ zwischen Hardware und Applikation. Unabhängig davon, auf welche Definition man sich letztendlich einigt, ist es äußerst wichtig das gleiche Verständnis von diesem Begriff zu haben.

Im Projekt einigte man sich auf die Formulierung: „Ein Betriebssystem besteht aus einem Task-Scheduler mit angebundener Treiberarchitektur“. Dabei war die Größe oder Vollständigkeit der „Treiberarchitektur“ nicht ausschlaggebend.

Mit oder ohne Betriebssystem?

Die Beantwortung dieser Frage ist viel einfacher als viele meinen. Als Entscheidungsgrundlage dienen nur wenige, wichtige Punkte:

  • Benötigt das Produkt mehrere nebenläufige Ausführungsstränge (Tasks)?
  • Sind diese Tasks aktiv (oder reagieren sie nur auf äußere Ereignisse)?
  • Gibt es zeitkritische Anforderungen an die gegenseitige Abarbeitung?

Sollte mindestens eine dieser Fragen mit „Ja“ beantworten werden, so ist man gut beraten zumindest schon mal einen Scheduler einzusetzen.

Die Frage nach dem aktiv oder reaktiv weist in die Richtung von Interrupts. Ein rein reaktives System kann z.B. mit mehreren Interrupt-Routinen ebenfalls mehr als einen Ausführungsstrang besitzen. Diese sind dann allerdings (normalerweise) sequentiell. Eine Ausnahme bilden Systeme mit „Interrupt-Prioritäten“ und „Nested-Interrupts“. Eine solche Technik kann man bereits als Pseudo-Scheduler bezeichnen.

Sollte man sich trotz eines „Ja“ gegen einen Scheduler entscheiden, so wird das Projekt mit absoluter Sicherheit neben dem eigentlichen Produkt zusätzlich einen Scheduler als Output liefern.

Um die Frage nach der Notwendigkeit einer Treiberarchitektur zu beantworten gibt es hingegen tatsächlich nur einen einzigen Punkt:

  • Gibt es Hardware, welche der Applikation gegenüber abstrahiert werden soll(te)?

Ein „Ja“ bedeutet, dass mindestens ein Treiber benötigt wird.

Zusammen mit der Antwort auf die Frage nach dem Scheduler lässt sich nun sehr leicht die grundlegendste Frage nach dem „Mit oder Ohne“ beantworten.

Im vorliegenden Projekt entschied man sich für das „Mit“. Deswegen behandeln wir in der Folge: Welche Fragen muss ich mir als Entwickler stellen, wenn ich ein geeignetes Betriebssystem für mein Embedded-Projekt finden will?

Anforderungen an das Betriebssystem

Um später eine Auswahl zwischen den hunderten am Markt vertretenen Betriebssystemen treffen zu können, ist es wichtig die Anforderungen in einer Art Matrix zusammenzutragen.

Die folgende Liste soll einen Einstieg in die Fragestellung geben. Je nach Produkt muss diese natürlich erweitert, verändert oder gekürzt werden.

Wird der Prozessor-Kern unterstützt?

Prozessoren unterstützen Betriebssysteme mittlerweile mit einer Vielzahl von integrierten Funktionen. Was früher im Scheduler „von Hand“ implementiert werden musste, wird heute über wenige Assemblerbefehle direkt vom Prozessor erledigt. Von Automatismen zur Taskumschaltung über Stackmanagement bis hin zur Prüfung von Berechtigungen sind viele Funktionen mittlerweile in die Prozessoren integriert. Dafür ist es jedoch notwendig, dass der Kern des Scheduler diese Besonderheiten kennt und ansteuert. Nur so ist es möglich die optimale Leistung aus dem Prozessor zu holen.

Unterstützt der Scheduler die notwendigen Scheduler-Strategien?

Aus der Entwicklung von embedded Produkten quasi nicht mehr wegzudenken ist ein Echtzeit-Scheduler. Dieser hat dafür zu sorgen, dass Deadlines eingehalten werden und die Vorhersagbarkeit gewährleistet bleibt. Für dessen Umsetzung ist zunächst lediglich eine strikt prioritätsgetriebene Umsetzung ausreichend. Doch was ist, wenn mehrere Tasks auf der gleichen Priorität arbeiten müssen. Welche von diesen wird dann bevorzugt?

Hierfür gibt es zusätzliche Strategien wie „Round Robin“ oder „First In, First Out“.

Auch sind Scheduler erhältlich, welche Fairness auf die eine oder andere Art garantieren. Allerdings werden diese nur selten in embedded Systemen gefordert.

Welche Granularität muss der Scheduler bieten?

Ein embedded System muss teilweise im Mikrosekunden-Raster Entscheidungen treffen oder Aktionen triggern können. Abhängig von der angestrebten Systemarchitektur ist es wichtig zu fragen, ob z.B. eine externe Nachricht alle 2 Millisekunden verarbeitet werden kann oder ein Aktorwert innerhalb einer Deadline von 300 Mikrosekunden neu beschrieben wird. Hat man dann einen Scheduler mit festem 20ms Raster, so ist das zwar schnell, aber unbrauchbar.

Werden Synchronisation und Signalisierung unterstützt?

Sobald mehrere Tasks innerhalb eines Systems laufen, bleibt es nicht aus, dass diese sich Ressourcen teilen müssen. Um den Zugriff auf diese Ressourcen zu synchronisieren sind atomare Mechanismen erforderlich.

Üblicherweise sind diese in Form von „Counting Semaphores“ abgebildet, auf denen wiederum verschiedene andere Synchronisationsmechanismen aufgebaut werden können.

Benötigt das Projekt Interprozess-Kommunikation (IPC)?

Werden Informationen in mehreren Tasks verarbeitet, so kann es notwendig werden Nachrichten zwischen den Systemteilen auszutauschen. Dies kann z.B. über Pipes oder Queues geschehen. Sofern das Produkt diese Problemstellung aufweist sollte ein Betriebssystemkandidat auch gegen diese Anforderung geprüft werden.

Beinhaltet das System Unterstützung für MMUs?

Immer mehr embedded Systeme sind mit „Memory Management Units“ (MMUs) ausgestattet. Je nach Größe des Systems bergen diese MMUs unterschiedlich viele Funktionen. Vom einfachen Cache-Management (welcher Speicherbereich wird durch den CPU-Cache abgebildet) über Zugriffsteuerung bis hin zu komplexen Mappingaufgaben innerhalb eines virtuellen Adressraums. Je nach Anforderung des Produktes und Gegebenheiten der Hardware stellt dies eine hilfreiche Funktion des Betriebssystems dar.

Beinhaltet das System Unterstützung für Speichermanagement?

Die Standard-Schnittstellen zur dynamischen Speicherallokation sind jedem Programmierer gut bekannt: „malloc“ und „free“. Hinter diesem sehr einfachen Interface verbergen sich jedoch komplexe Strategien um z.B. eine Fragmentierung des Speichers zu reduzieren. Falls das Produkt eine solche Funktion benötigt ist es wichtig im Betriebssystem bereits erprobte und getestete Mechanismen hierfür vorzufinden.

Unterstützung für Peripherie und Schnittstellen

Auch wenn die Anbindung von Peripherie oft als Referenzimplementation bereits durch die Hersteller zur Verfügung gestellt wird, so spart es dennoch viel Arbeit, wenn ein ähnlicher Baustein oder die geforderte Schnittstelle bereits als fertiger Treiber für genau dieses Betriebssystem existiert. Bevorzugt natürlich bereits fertig „abgehangen“ und getestet. Zumindest aber mit einem Satz von Testfunktionen, welche auf der eigenen Hardware abgearbeitet werden können.

Unterstützung IDE und Debugging.

Ob ein Betriebssystem mit seiner eigenen „full featured IDE“ geliefert wird, in die bereits der Compiler integriert ist oder ob man die Komponenten selbst zusammenstellen kann ist unerheblich. Wichtig bei der Bewertung dieses Punktes ist, dass ein geschlossener Kreislauf vom Programmieren in einem komfortablen Editor über die Kompilation und das Aufbringen des Kompilats auf das Target bis hin zum Debuggen auf Zeilenebene möglich ist. Letzteres lässt sich natürlich bei manchen Produkten nur durch Emulatoren erreichen.

Diese Möglichkeiten sollten im Zweifel getestet werden, bevor man sich für eine Lösung entscheidet.

Liegt der Quellcode des Betriebssystems vor?

Auf embedded Systemen ist die Verzahnung zwischen Applikation, Treibern und Scheduler naturgemäß sehr eng. Das bedingt oft, dass während des Debuggings fremde Funktionen des besseren Verständnisses wegen durchlaufen werden wollen. Viele kommerziellen Anbieter gewähren deshalb unter bestimmten vertraglichen Bedingungen einen begrenzten Einblick in ihre Sourcecodes um dieses Vorgehen zu unterstützen.

Bei Open Source-Systemen stellt sich diese Frage naturgemäß nicht.

Welcher Lizenz unterliegt das Betriebssystem?

Eine Frage, die nicht nur die Techniker, sondern auch die Produktverantwortlichen umtreibt. So viele Lizenzmodelle es in der Open Source Welt gibt, so viele gibt es auch in der Welt der kommerziellen Produkte. Was welche Lizenz genau bedeutet muss am jeweiligen Produkt detailliert geprüft werden. Z.B. ist eine kommerzielle Lizenz pro Entwicklungsstandort bei verteilten Teams ebenso schädlich, wie eine Lizenz, welche die Nennung des Autors im Handbuch bei einem Produkt ohne Kundendokumentation verlangt.

Support und Community

Oft vernachlässigt, aber trotzdem wichtig ist die Frage nach der Community. Selbst der kommerzielle Support des Herstellers kann eine rege Diskussionsgruppe im Internet nur schwer ersetzen. Ein Ort, an dem unbürokratisch Fragen beantwortet, Codeschnipsel gepostet oder Fehler gemeldet werden ist oft mehr wert als ein Supportvertrag. Seit einiger Zeit gehen auch kommerzielle Anbieter dazu über Mailinglisten zu hosten in denen sowohl Anwender, wie auch Supportmitarbeiter sich gegenseitig austauschen können.

Neben dieser allgemein gehaltenen Liste spielten im realen Projekt noch viele weitere Aspekte eine Rolle. So z.B. die Unterstützung für die Schnittstellen I2C, SPI, QSPI und USB, sowie Dateisysteme und Feldbusse. Weiterhin wurden in die Bewertung weiche Faktoren wie Zukunftssicherheit, Lizenzrisiko, Testbarkeit und Einarbeitungsaufwand mit einbezogen.

(ID:45416846)