半主机
半主机是一种机制,它允许嵌入式设备在主机上执行 I/O 操作,主要用于将消息记录到主机控制台。半主机需要一个调试会话,几乎不需要其他任何东西(无需额外的电线!),因此使用起来非常方便。缺点是速度非常慢:每次写入操作可能需要几毫秒,具体取决于你使用的硬件调试器(例如 ST-Link)。
cortex-m-semihosting
crate 提供了在 Cortex-M 设备上执行半主机操作的 API。下面的程序是 "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 {}
}
如果在硬件上运行此程序,你将在 OpenOCD 日志中看到 "Hello, world!" 消息。
$ openocd
(..)
Hello, world!
(..)
你首先需要在 GDB 中启用 OpenOCD 中的半主机功能
(gdb) monitor arm semihosting enable
semihosting is enabled
QEMU 理解半主机操作,因此上面的程序也可以在 qemu-system-arm
上运行,而无需启动调试会话。 请注意,你需要将 -semihosting-config
标志传递给 QEMU 以启用半主机支持;这些标志已包含在模板的 .cargo/config.toml
文件中。
$ # this program will block the terminal
$ cargo run
Running `qemu-system-arm (..)
Hello, world!
还有一个 exit
半主机操作可用于终止 QEMU 进程。 重要提示:请 不要 在硬件上使用 debug::exit
;此函数会破坏你的 OpenOCD 会话,并且在你重新启动它之前,你将无法调试更多程序。
#![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 $?
1
最后一个提示:你可以将 panic 行为设置为 exit(EXIT_FAILURE)
。这将允许你编写可以在 QEMU 上运行的 no_std
run-pass 测试。
为了方便起见,panic-semihosting
crate 有一个 "exit" 功能,启用后,它会在将 panic 消息记录到主机 stderr 后调用 exit(EXIT_FAILURE)
。
#![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 $?
1
注意:要在 panic-semihosting
上启用此功能,请编辑你的 Cargo.toml
依赖项部分,其中指定了 panic-semihosting
,并使用
panic-semihosting = { version = "VERSION", features = ["exit"] }
其中 VERSION
是所需的版本。有关依赖项功能的更多信息,请查看 Cargo 书的 指定依赖项
部分。