Semihosting is a feature which allows targets without I/O support to use the I/O of the host. When the special BKPT instruction is reached, the host reads the characters directly from the micro:bit's memory.

Semihosting is slow

The most important thing to remember about semihosting is that it is slow. The processor halts entirely for each operation, making each operation take 107 milliseconds. This means that if you are doing any time sensitive work, you should not use it for logging. Check out this blog post for more information.


The first thing to do is to enable semihosting in GDB. As before, we will add this to .gdbinit to avoid typing it every time.


target remote :3333
monitor arm semihosting enable


You may have incorrectly assumed at this point that the outpust would appear in GDB. Remember that GDB simply connects to OpenOCD to interface with the micro:bit. OpenOCD is very loud currently, so it will be quite hard to see the output of our micro:bit in the noise. Fix this by stopping and restarting it with logging dumped to a file.

openocd -f interface/cmsis-dap.cfg -f target/nrf51.cfg -l /tmp/openocd.log


The easiest way to use semihosting is to use it for the panic! macro.


panic-semihosting = ""

You can then see what happens if you add a panic! to your code:

fn main() -> ! {
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
panicked at 'test-panic', src/hello-world/src/


Finally, this is how to write to stdout.

# #![allow(unused_variables)]
#fn main() {
extern crate cortex_m_semihosting as sh;
use core::fmt::Write;
use sh::hio;
// -- snip --
    let mut stdout = hio::hstdout().unwrap();
    // or
    writeln!(hio::hstdout().unwrap(), "Init").unwrap();

Writing to stderr is just as easy.