cortex_m_semihosting - Rust (original) (raw)
Crate cortex_m_semihosting
Expand description
Semihosting for ARM Cortex-M processors
§What is semihosting?
“Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.” - ARM
§Interface
This crate provides implementations ofcore::fmt::Write, so you can use it, in conjunction withcore::format_args! or the write! macro, for user-friendly construction and printing of formatted strings.
Since semihosting operations are modeled as system calls, this crate exposes an untypedsyscall!
interface just like the sc crate does.
§Forewarning
Semihosting operations are very slow. Like, each WRITE operation can take hundreds of milliseconds.
§Example
§Using hio::hstdout
This example will demonstrate how to print formatted strings.
use cortex_m_semihosting::hio;
use core::fmt::Write;
// This function will be called by the application
fn print() -> Result<(), core::fmt::Error> {
let mut stdout = hio::hstdout().map_err(|_| core::fmt::Error)?;
let language = "Rust";
let ranking = 1;
write!(stdout, "{} on embedded is #{}!", language, ranking)?;
Ok(())
}
On the host side:
$ openocd -f <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mi>N</mi><mi>T</mi><mi>E</mi><mi>R</mi><mi>F</mi><mi>A</mi><mi>C</mi><mi>E</mi><mo>−</mo><mi>f</mi></mrow><annotation encoding="application/x-tex">INTERFACE -f </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">NTERF</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.05764em;">CE</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span></span></span></span>TARGET -l /tmp/openocd.log
Open On-Chip Debugger 0.9.0 (2016-04-27-23:18)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
# the command will block at this point
The OpenOCD logs will be redirected to /tmp/openocd.log
. You can view those logs in “real time” using tail
$ tail -f /tmp/openocd.log
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v1 JTAG v11 API v2 SWIM v0 VID 0x0483 PID 0x3744
Info : using stlink api v2
Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
Alternatively you could omit the -l
flag from the openocd
call, and the tail -f
command but the OpenOCD output will have intermingled in it logs from its normal operation.
Then, we run the program:
$ arm-none-eabi-gdb hello-world
(gdb) # Connect to OpenOCD
(gdb) target remote :3333
(gdb) # Enable OpenOCD's semihosting support
(gdb) monitor arm semihosting enable
(gdb) # Flash the program
(gdb) load
(gdb) # Run the program
(gdb) continue
And you’ll see the output under OpenOCD’s terminal
# openocd -f <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mi>N</mi><mi>T</mi><mi>E</mi><mi>R</mi><mi>F</mi><mi>A</mi><mi>C</mi><mi>E</mi><mo>−</mo><mi>f</mi></mrow><annotation encoding="application/x-tex">INTERFACE -f </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">NTERF</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.05764em;">CE</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span></span></span></span>TARGET -l /tmp/openocd.log
(..)
Rust on embedded is #1!
§Using the syscall interface
This example will show how to print “Hello, world!” on the host.
Target program:
use cortex_m_semihosting::syscall;
// This function will be called by the application
fn print() {
// File descriptor (on the host)
const STDOUT: usize = 1; // NOTE the host stdout may not always be fd 1
static MSG: &'static [u8] = b"Hello, world!\n";
// Signature: fn write(fd: usize, ptr: *const u8, len: usize) -> usize
let r = unsafe { syscall!(WRITE, STDOUT, MSG.as_ptr(), MSG.len()) };
}
Output and monitoring proceed as in the above example.
§The dbg!
macro
Analogous to std::dbg the macrodbg!
returns a given expression and prints it using heprintln!
including context for quick and dirty debugging.
Panics if heprintln!
returns an error.
Example:
const UUID: *mut u32 = 0x0009_FC70 as *mut u32;
dbg!(UUID);
let mut uuid: [u32; 4] = [0; 4];
for i in 0..4 {
dbg!(i);
uuid[i] = unsafe { dbg!(UUID.offset(i as isize).read_volatile()) };
}
outputs
[examples/semihosting.rs:37] UUID = 0x0009fc70
[examples/semihosting.rs:40] i = 0
[examples/semihosting.rs:41] UUID.offset(i as isize).read_volatile() = 3370045464
[examples/semihosting.rs:40] i = 1
[examples/semihosting.rs:41] UUID.offset(i as isize).read_volatile() = 1426218275
[examples/semihosting.rs:40] i = 2
[examples/semihosting.rs:41] UUID.offset(i as isize).read_volatile() = 2422621116
[examples/semihosting.rs:40] i = 3
[examples/semihosting.rs:41] UUID.offset(i as isize).read_volatile() = 1044138593
§Optional features
§jlink-quirks
When this feature is enabled, return values above 0xfffffff0
from semihosting operationSYS_WRITE
(0x05) are interpreted as if the entire buffer had been written. The current latest version 6.48b of J-Link exhibits such behaviour, causing a panic if this feature is not enabled.
§no-semihosting
When this feature is enabled, the underlying system calls to bkpt
are patched out.
§Reference
For documentation about the semihosting operations, check:
‘Chapter 8 - Semihosting’ of the ‘ARM Compiler toolchain Version 5.0’manual.
Interacting with debugging agent
Host I/O
Semihosting operations
Macro that prints and returns the value of a given expression for quick and dirty debugging.
Macro for printing to the HOST standard error.
Macro for printing to the HOST standard error, with a newline.
Macro for printing to the HOST standard output.
Macro for printing to the HOST standard output, with a newline.
Variable argument version of syscall
Macro version of syscall1
.
Performs a semihosting operation, takes a pointer to an argument block
Performs a semihosting operation, takes one integer as an argument