半主机模式

半主机模式是一种可以让嵌入式设备在主机上进行I/O操作的的机制,主要被用来记录信息到主机控制台上。半主机模式需要一个debug会话,除此之外几乎没有其它要求了,因此它非常易于使用。缺点是它非常慢:每个写操作需要几毫秒的时间,其取决于你的硬件调试器(e.g. ST-LINK)。

cortex-m-semihosting crate 提供了一个API去在Cortex-M设备上执行半主机操作。下面的程序是”Hello, world!”的半主机版本。

  1. #![no_main]
  2. #![no_std]
  3. use panic_halt as _;
  4. use cortex_m_rt::entry;
  5. use cortex_m_semihosting::hprintln;
  6. #[entry]
  7. fn main() -> ! {
  8. hprintln!("Hello, world!").unwrap();
  9. loop {}
  10. }

如果你在硬件上运行这个程序,你将会在OpenOCD的logs中看到”Hello, world!”信息。

  1. $ openocd
  2. (..)
  3. Hello, world!
  4. (..)

你首先需要从GDB使能OpenOCD中的半主机模式。

  1. (gdb) monitor arm semihosting enable
  2. semihosting is enabled

QEMU理解半主机操作,因此上面的程序不需要启动一个debug会话,也能在qemu-system-arm中工作。注意你需要传递-semihosting-config标志给QEMU去使能支持半主机模式;这些标识已经被包括在模板的.cargo/config.toml文件中了。

  1. $ # this program will block the terminal
  2. $ cargo run
  3. Running `qemu-system-arm (..)
  4. Hello, world!

exit半主机操作也能被用于终止QEMU进程。重要:不要在硬件上使用debug::exit;这个函数会关闭你的OpenOCD对话,这样你将不能执行其它程序调试操作,除了重启它。

  1. #![no_main]
  2. #![no_std]
  3. use panic_halt as _;
  4. use cortex_m_rt::entry;
  5. use cortex_m_semihosting::debug;
  6. #[entry]
  7. fn main() -> ! {
  8. let roses = "blue";
  9. if roses == "red" {
  10. debug::exit(debug::EXIT_SUCCESS);
  11. } else {
  12. debug::exit(debug::EXIT_FAILURE);
  13. }
  14. loop {}
  15. }
  1. $ cargo run
  2. Running `qemu-system-arm (..)
  3. $ echo $?
  4. 1

最后一个提示:你可以将运行时恐慌(panicking)的行为设置成 exit(EXIT_FAILURE)。这将允许你编写可以在QEMU上运行通过的 no_std 测试。

为了方便,panic-semihosting crate有一个 “exit” 特性。当它使能的时候,在主机stderr上打印恐慌(painc)信息后会调用 exit(EXIT_FAILURE)

  1. #![no_main]
  2. #![no_std]
  3. use panic_semihosting as _; // features = ["exit"]
  4. use cortex_m_rt::entry;
  5. use cortex_m_semihosting::debug;
  6. #[entry]
  7. fn main() -> ! {
  8. let roses = "blue";
  9. assert_eq!(roses, "red");
  10. loop {}
  11. }
  1. $ cargo run
  2. Running `qemu-system-arm (..)
  3. panicked at 'assertion failed: `(left == right)`
  4. left: `"blue"`,
  5. right: `"red"`', examples/hello.rs:15:5
  6. $ echo $?
  7. 1

注意: 为了在panic-semihosting上使能这个特性,编辑你的Cargo.toml依赖,panic-semihosting改写成:

  1. panic-semihosting = { version = "VERSION", features = ["exit"] }

VERSION是想要的版本。关于依赖features的更多信息查看Cargo book的specifying dependencies部分。