Dieser technische Blogbeitrag vergleicht die Leistung, den Ressourcenbedarf und die Programmierergonomie von asynchronem Rust (unter Verwendung des Embassy-Frameworks) mit C (unter Verwendung von FreeRTOS) auf einem STM32F446ZET6 Mikrocontroller. Beide Software-Modelle implementieren identische Referenzanwendungen bestehend aus einem LED-Blinker, einer GPIO-Taster-Abfrage via Interrupt und einer UART-Nachrichtenwarteschlange. Die Evaluierung misst Interrupt-Zeiten, Thread-Ausführungszeiten, Interrupt-Latenzen, Programm-Speichergröße (.text) sowie den statischen RAM-Verbrauch (.data + .bss) mittels eines Oszilloskops. Ein zusätzliches Addendum evaluiert zudem das rein interrupt-getriebene RTIC-Framework.
Wichtigste Punkte
Hardware-Plattform: Tests wurden auf einem STM32F446ZET6 Mikrocontroller (ARM Cortex-M4 Kern bei 180 MHz) durchgeführt; Messungen erfolgten über ein Rigol DS1054Z Oszilloskop.
Testanwendung: Die parallel ausgeführten Aufgaben umfassen einen LED-Blinker (100 ms Intervall, unterdrückt bei gedrücktem Taster), einen Taster-Handler (GPIO-Interrupts mit Flankenerkennung und Übergabe an eine Nachrichtenwarteschlange) sowie einen UART-Writer (wartet auf Nachrichten und sendet diese seriell).
Statische Speichereffizienz: Embassy/Rust benötigte lediglich 872 Byte an statischem Speicher im Vergleich zu 5480 Byte bei FreeRTOS/C, was einer Einsparung von 84,1 % entspricht.
Programmgröße: Der Flash-Speicherbedarf (.text-Sektion) betrug 14.272 Byte für die Rust-Implementierung gegenüber 20.676 Byte für die C-Variante (-31,0 %).
Interrupt- und Thread-Performance: Die durchschnittliche Interrupt-Zeit lag bei Rust bei 1,450 µs (gegenüber 2,962 µs in C; eine Reduktion um 51,0 %), während die Thread-Ausführungszeit 11,64 µs (gegenüber 16,19 µs in C) betrug.
Interrupt-Latenz: Die durchschnittliche Zeit vom Beginn des Interrupts bis zum Wiederaufnehmen des Threads betrug 3,738 µs für Rust und 4,973 µs für C.
Multitasking-Modell: Embassy setzt auf kooperatives Multitasking ohne Task-Präemption innerhalb eines Executors, lässt sich jedoch durch mehrere Executor auf unterschiedlichen Interrupt-Prioritäten erweitern.
RTIC-Addendum: Das alternative, rein interrupt-getriebene RTIC-Framework unterbot Embassy in vielen Metriken deutlich und erreichte eine durchschnittliche Interrupt-Zeit von 650,8 ns sowie einen statischen Speicherbedarf von nur 392 Byte.
Glossar
STM32F446ZET6: Ein 32-Bit-Mikrocontroller von STMicroelectronics auf Basis eines ARM Cortex-M4-Prozessors, der mit bis zu 180 MHz taktet.
FreeRTOS: Ein weit verbreitetes, leichtgewichtiges Real-Time Operating System (Echtzeit-Betriebssystem) für eingebettete Systeme, entwickelt in der Programmiersprache C.
Embassy: Ein asynchrones Laufzeit- und Peripherie-Framework für die Programmiersprache Rust, das speziell für eingebettete Systeme ohne dynamische Speicherverwaltung (Heap) konzipiert wurde.
RTIC (Real-Time Interrupt-driven Concurrency): Ein ereignisgesteuertes Nebenläufigkeitsmodell und Framework für Rust in eingebetteten Systemen, das komplett auf Hardware-Interrupts anstelle eines traditionellen Betriebssystem-Kernels aufbaut.
RTOS (Real-Time Operating System): Ein Betriebssystem, das für zeitkritische Anwendungen entwickelt wurde und eine deterministische, fristgerechte Abarbeitung von Aufgaben garantiert.
Future (Rust): Ein abstrakter Datentyp in Rust, der eine asynchrone Operation repräsentiert. Er fungiert als Zustandsmaschine, die erst bei fortlaufender Abfrage (Polling) bis zum Abschluss ausgeführt wird.
Executor: Eine Softwarekomponente in asynchronen Systemen, die dafür zuständig ist, anstehende Aufgaben (Futures) abzufragen (zu pollen) und deren Ausführung zu steuern.
Waker: Ein Mechanismus im asynchronen Rust-Modell, der den Executor benachrichtigt, wenn eine blockierte Aufgabe (z. B. nach einem Interrupt) fortgesetzt werden kann.
Statischer Speicher (.data / .bss): Speicherbereiche im RAM, die während der Kompilierzeit fest zugewiesen werden; .data enthält initialisierte und .bss uninitialisierte globale oder statische Variablen.
EXTI (External Interrupt): Ein Hardware-Peripheriemodul auf STM32-Mikrocontrollern zur Überwachung externer Signale an GPIO-Pins und Auslösung von Interrupts.
Interrupt-Latenz: Die zeitliche Verzögerung zwischen dem physischen Auftreten eines Interrupt-Ereignisses und dem Beginn der tatsächlichen Ausführung des zugehörigen Programm-Codes oder Threads.
Atomare Operation (Atomic): Ein Rechen- oder Speicherbefehl, der unteilbar und ohne Unterbrechung durch andere Threads oder Interrupts ausgeführt wird, um Datenkonsistenz zu sichern.
UART (Universal Asynchronous Receiver-Transmitter): Eine Hardware-Schnittstelle für die serielle asynchrone Datenübertragung.