半主机

半主机是这样一种机制,它允许嵌入式设备在主机上执行I/O操作,主要用于将消息记录输出到主机控制台。半主机除了需要调试会话之外,几乎不需要其他任何操作(不需要额外的接线!),因此使用起来超级方便。缺点是它非常慢:根据您使用的硬件调试器不同(例如ST-Link),每个写入操作可能要花费几毫秒。

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

#![no_main]
#![no_std]

extern crate panic_halt;

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文件中。

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

还有一个exit半主机操作可用于终止QEMU进程。重要提示:不要在硬件上使用debug::exit;此功能可能会破坏您的OpenOCD会话,并且只有重新启动它才能调试更多程序。

#![no_main]
#![no_std]

extern crate panic_halt;

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

最后一个提示:您可以将恐慌行为设置为exit(EXIT_FAILURE)。这将使您编写可以在QEMU上运行的no_std测试案例。

为方便起见,panic-semihostingcrate具有“退出”功能,启用后,会将panic消息记录到主机stderr后调用exit(EXIT_FAILURE)

#![no_main]
#![no_std]

extern crate panic_semihosting; // 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手册》中的specifying dependencies部分。