Semihosting
Semihosting ist ein Mechanismus, der es eingebetteten Systemen ermöglicht, Ein-/Ausgabeoperationen über den eigenen Rechner (Host) durchzuführen; er wird hauptsächlich dazu genutzt, Meldungen auf der Host-Konsole zu protokollieren. Da Semihosting lediglich eine Debug-Sitzung und sonst so gut wie nichts (keine zusätzlichen Kabel!) erfordert, ist es äußerst komfortabel in der Anwendung. Der Nachteil ist jedoch die sehr geringe Geschwindigkeit: Je nach verwendetem Hardware-Debugger (z. B. ST-Link) kann jeder Schreibvorgang mehrere Millisekunden in Anspruch nehmen.
Das cortex-m-semihosting-Crate stellt eine API für Semihosting-Operationen auf Cortex-M-Geräten bereit. Das folgende Programm ist die Semihosting-Version von „Hello, world!“:
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
#[entry]
fn main() -> ! {
hprintln!("Hello, world!").unwrap();
loop {}
}Wenn Sie dieses Programm auf der Hardware ausführen, sehen Sie die Meldung „Hello, world!“ in den OpenOCD-Protokollen.
$ openocd
(..)
Hello, world!
(..)Sie müssen zunächst Semihosting in OpenOCD über GDB aktivieren:
(gdb) monitor arm semihosting enable
semihosting is enabledQEMU unterstützt Semihosting-Operationen, sodass das obige Programm auch mit qemu-system-arm funktioniert, ohne dass eine Debug-Sitzung gestartet werden muss. Beachten Sie, dass Sie QEMU die Option -semihosting-config übergeben müssen, um die Semihosting-Unterstützung zu aktivieren; diese Optionen sind bereits in der Datei .cargo/config.toml der Vorlage enthalten.
$ # Dieses Programm wird das Terminal blockieren.
$ cargo run
Running `qemu-system-arm (..)
Hello, world!
Es gibt auch eine exit-Semihosting-Operation, mit der sich der QEMU-Prozess beenden lässt. Wichtig: Verwenden Sie debug::exit nicht auf echter Hardware; diese Funktion kann Ihre OpenOCD-Sitzung beschädigen, sodass Sie keine weiteren Programme mehr debuggen können, bis Sie die Sitzung neu starten.
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::debug;
#[entry]
fn main() -> ! {
let roses = "blue";
if roses == "red" {
debug::exit(debug::EXIT_SUCCESS);
} else {
debug::exit(debug::EXIT_FAILURE);
}
loop {}
}$ cargo run
Running `qemu-system-arm (..)
$ echo $?
1Ein letzter Tipp: Du kannst das Verhalten bei einem Panic auf exit(EXIT_FAILURE) einstellen. Dadurch lassen sich no_std-Tests schreiben, die erfolgreich durchlaufen und unter QEMU ausgeführt werden können.
Praktischerweise bietet der panic-semihosting-Crate ein „exit“-Feature an; ist dieses aktiviert, wird exit(EXIT_FAILURE) aufgerufen, nachdem die Panic-Meldung auf dem stderr des Hosts ausgegeben wurde.
#![no_main]
#![no_std]
use panic_semihosting as _; // features = ["exit"]
use cortex_m_rt::entry;
use cortex_m_semihosting::debug;
#[entry]
fn main() -> ! {
let roses = "blue";
assert_eq!(roses, "red");
loop {}
}$ cargo run
Running `qemu-system-arm (..)
panicked at 'assertion failed: `(left == right)`
left: `"blue"`,
right: `"red"`', examples/hello.rs:15:5
$ echo $?
1HINWEIS: Um diese Funktion für panic-semihosting zu aktivieren, bearbeiten Sie den Abschnitt „dependencies“ in Ihrer Cargo.toml, in dem panic-semihosting wie folgt angegeben ist:
panic-semihosting = { version = "VERSION", features = ["exit"] }wobei VERSION für die gewünschte Version steht. Weitere Informationen zu Abhängigkeiten und Funktionen finden Sie im Abschnitt “specifying dependencies” des Cargo-Buchs.