Neue Programmiersprachen werden in der Regel als Reaktion auf Unzulänglichkeiten bestehender Sprachen entwickelt. Dies steht häufig mit der Leistung, Benutzerfreundlichkeit oder fehlenden Unterstützung neuer Informatikkonzepte in Zusammenhang. Im Bereich der Embedded Electronics, insbesondere in Bezug auf Mikrocontroller, wurde die Programmiersprache Rust vor allem infolge zahlreicher Unzulänglichkeiten der Programmiersprache C eingeführt – seit Jahrzehnten das Maß der Dinge bei der Entwicklung von Embedded Systems.
Der bereits in den frühen 1970er Jahren entwickelten Sprache C fehlen viele moderne Funktionen, auf die Softwareentwickler heute angewiesen sind. In der folgenden Liste werden einige der wichtigsten Unzulänglichkeiten von C bei der Entwicklung von Embedded Systems hervorgehoben:
Obwohl C zahlreiche Unzulänglichkeiten aufweist, ist sie auch heute noch die vorherrschende Sprache. So haben die Entwickler von Rust sichergestellt, dass ihre neue Sprache mit C-Code interoperabel ist, sodass Entwickler von Embedded Systems vorhandene C-Bibliotheken in Rust-Anwendungen nutzen können.
Die Idee für Rust stammt von Graydon Hoare, der 2006 im Rahmen eines privaten Projekts mit der Entwicklung dieser Programmiersprache begann, während er bei Mozilla beschäftigt war. Ihm ging es damals darum, die Leistung und Zuverlässigkeit komplexer paralleler Computingaufgaben zu verbessern, die bei den damaligen Webbrowsern zu erheblichen Problemen führten. Im Jahr 2022 war Rust dann nach Assembly und C erst die dritte Programmiersprache, die für die Entwicklung des Linux-Kernels zugelassen wurde.
Die Rust-Benutzergruppe gründete 2018 die Embedded Rust Working Group, um die Entwicklung einer leichtgewichtigen Version von Rust zu überwachen, die speziell für eingebettete Plattformen wie ARM® Cortex®-M, MSP430 und RISC-V vorgesehen war. Embedded Rust Development Tools sind für Windows, macOS und zahlreiche Linux-Distributionen verfügbar. Viele moderne Code-Editoren – wie Visual Studio Code, Sublime, Atom, RustOver und Eclipse – bieten Unterstützung für Rust. Bevor wir uns aber mit den praktischen Aspekten von Embedded Rust befassen, wollen wir einige einzigartige Konzepte betrachten, die traditionellen Softwareentwicklern beim Übergang zur Entwicklung von Embedded Systems helfen können:
Der wichtigste Teil des Rust-Embedded-Ökosystems ist die embedded-hal-Rust-Bibliothek, die eine gemeinsame Schnittstelle für die Arbeit mit Hardware-Peripheriegeräten auf verschiedenen Mikrocontroller-Plattformen bietet. Das Ziel von embedded-hal ist es, Code-Portabilität und Wiederverwendbarkeit bei der Entwicklung von Software für Embedded Systems zu ermöglichen. Embedded-hal definiert Traits und Abstraktionen für gängige Embedded-Hardware-Peripheriegeräte wie GPIO-Pins, SPI, I²C, UART, Timer und mehr. Diese Traits bieten eine standardisierte API für die Interaktion mit diesen Peripheriegeräten, was das Schreiben von portierbarem Embedded-Code erleichtert.
Einer der Hauptvorteile von embedded-hal ist seine Plattformunabhängigkeit. Sie können mit embedded-hal Code schreiben, der auf verschiedenen Mikrocontroller-Architekturen und Development Boards funktioniert, ohne geändert werden zu müssen. Voraussetzung ist, dass die Zielplattform die erforderlichen Traits implementiert.
Embedded-hal umfasst zwar allgemeine Abstraktionen, kann aber auch angepasst werden. Wenn ein bestimmter Mikrocontroller oder eine bestimmte Plattform über einzigartige Merkmale oder Fähigkeiten verfügt, können Sie die embedded-hal-Traits für diese Merkmale implementieren, um eine einheitliche Schnittstelle zu schaffen.
Hier ein Beispiel, wie Sie embedded-hal in Rust-Code verwenden können:
use embedded_hal::digital::v2::{OutputPin, InputPin};
use stm32f4xx_hal::{gpio::gpioa::PA5, stm32};
fn main() {
// Initialisiere den Mikrocontroller
let dp = stm32::Peripherals::take().unwrap();
let cp = cortex_m::peripheral::Peripherals::take().unwrap():
let mut rcc = dp.RCC.constrain();
let _clocks = rcc.cfgr.freeze();
// Konfiguriere einen GPIO-Pin mit embedded_hal
let gpioa = dp.GPIOA.split();
let mut led = gpioa.pa5.into_push_pull_output();
// Bringe die LED zum Blinken
loop {
led.set_high().unwrap();
cortex_m::asm::delay(1_000_000);
led.set_low().unwrap();
}
In diesem Beispiel verwenden wir embedded-hal-Eigenschaften wie OutputPin, um eine an einen GPIO-Pin angeschlossene LED zu steuern. Der Code ist so geschrieben, dass er auf einem anderen STM32-Mikrocontroller wiederverwendet werden kann. Zu diesem Zweck wird nur die zweite Zeile des Codes mit dem gewünschten Board geändert. Beachten Sie, dass dies nur gilt, solange die embedded-hal-Traits für GPIO-Pins unterstützt werden und die erforderlichen Peripheriegeräte vorhanden sind.
Rust wurde entwickelt, um Unzulänglichkeiten bei der Programmiersprache C zu beheben, insbesondere bei Embedded Systems. Mit Funktionen wie Paketverwaltung, besserer Speicherverwaltung, sicherer Gleichzeitigkeit und modernen Datenstrukturen bietet Rust erhebliche Verbesserungen gegenüber C. Durch die Interoperabilität von Rust mit C können Entwickler außerdem vorhandene C-Bibliotheken nutzen. Die Gründung der Embedded Rust Working Group und Tools wie die embedded-hal-Bibliothek unterstreichen, wie stark sich das Team hinter Rust für eine optimierte Entwicklung von Embedded Systems einsetzt. Dafür bietet Rust einen plattformunabhängigen und anpassbaren Ansatz, über den die Portabilität und Wiederverwendbarkeit von Code auf verschiedenen Mikrocontroller-Plattformen gefördert wird.
Michael Parks, P.E. ist der Eigentümer von Green Shoe Garage, einem Entwicklungsstudio für kundenspezifische Elektronik und Technologieberatung im Süden von Maryland. Er produziert den S.T.E.A.M. Power-Podcast (ein Podcast über MINT-Themen), mit dem er die Öffentlichkeit für technische und wissenschaftliche Fragen sensibilisieren möchte. Michael ist außerdem zugelassener Ingenieur im Bundesstaat Maryland und hat einen Master-Abschluss in Systemtechnik von der Johns Hopkins University.