getting started: add semihosting section

This commit is contained in:
Jorge Aparicio
2018-11-10 00:33:38 +01:00
parent 0d3f69dacf
commit 483bf24abd
2 changed files with 129 additions and 0 deletions

View File

@@ -22,6 +22,7 @@ more information and coordination
- [QEMU](./start/qemu.md)
- [Hardware](./start/hardware.md)
- [Memory-mapped Registers](./start/registers.md)
- [Semihosting](./start/semihosting.md)
- [Panicking](./start/panicking.md)
- [Exceptions](./start/exceptions.md)
- [IO](./start/io.md)

128
src/start/semihosting.md Normal file
View File

@@ -0,0 +1,128 @@
# Semihosting
Semihosting is a mechanism that lets embedded devices do I/O on the host and is
mainly used to log messages to the host console. Semihosting requires a debug
session and pretty much nothing else (no extra wires!) so it's super convenient
to use. The downside is that it's super slow: each write operation can take
several milliseconds depending on the hardware debugger (e.g. ST-Link) you use.
The [`cortex-m-semihosting`] crate provides an API to do semihosting operations
on Cortex-M devices. The program below is the semihosting version of "Hello,
world!":
[`cortex-m-semihosting`]: https://crates.io/crates/cortex-m-semihosting
``` rust
#![no_main]
#![no_std]
extern crate panic_halt;
use core::fmt::Write;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
#[entry]
fn main() -> ! {
hprintln!("Hello, world!").unwrap();
loop {}
}
```
If you run this program on hardware you'll see the "Hello, world!" message
within the OpenOCD logs.
``` console
$ openocd
(..)
Hello, world!
(..)
```
QEMU understands semihosting operations so the above program will also work with
`qemu-system-arm` without having to start a debug session. Note that you'll
need to pass the `-semihosting-config` flag to QEMU to enable semihosting
support; these flags are already included in the `.cargo/config` file of the
template.
``` console
$ # this program will block the terminal
$ cargo run
Running `qemu-system-arm (..)
Hello, world!
```
There's also an `exit` semihosting operation that can be used to terminate the
QEMU process. Important: do **not** use `debug::exit` on hardware; this function
can corrupt your OpenOCD session and you will not be able to debug more programs
until you restart it.
``` rust
#![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 {}
}
```
``` console
$ cargo run
Running `qemu-system-arm (..)
$ echo $?
1
```
One last tip: you can set the panicking behavior to `exit(EXIT_FAILURE)`. This
will let you write `no_std` run-pass tests that you can run on QEMU.
For convenience, the `panic-semihosting` crate has an "exit" feature that when
enabled invokes `exit(EXIT_FAILURE)` after logging the panic message to the host
stderr.
``` rust
#![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 {}
}
```
``` console
$ cargo run
Running `qemu-system-arm (..)
panicked at 'assertion failed: `(left == right)`
left: `"blue"`,
right: `"red"`', examples/hello.rs:15:5
$ echo $?
1
```