probe-run

Runs embedded programs just like native ones

probe-run is a custom Cargo runner that transparently runs Rust firmware on a remote device.

probe-run is powered by [probe-rs] and thus supports as many devices and probes as probe-rs does.

Features

Installation

To install probe-run, use cargo install probe-run.

On Linux, you might have to install libudev and libusb from your package manager before installing probe-run.

Setup

  1. Set the Cargo runner

The recommend way to use probe-run is to set as the Cargo runner of your application. Add this line to your Cargo configuration (.cargo/config) file:

toml [target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "probe-run --chip ${PROBE_RUN_CHIP}"

Instead of ${PROBE_RUN_CHIP} you can write the name of your microcontroller. For example, one would use nRF52840_xxAA for the nRF52840 microcontroller. To list all supported chips run probe-run --list-chips.

To support multiple devices, or permit overriding default behavior, you may prefer to set the ${PROBE_RUN_CHIP} environment variable, and set runner (or CARGO_TARGET_${TARGET_ARCH}_RUNNER) to probe-run.

If you have several probes connected, you can specify which one to use by adding the --probe option to the runner or setting the ${PROBE_RUN_PROBE} environment variable with a value containing either ${VID}:${PID} or ${VID}:${PID}:${SERIAL}:

console probe-run --probe '0483:3748' --chip ${PROBE_RUN_CHIP} PROBE_RUN_PROBE='1366:0101:123456' cargo run

To list all connected probes, run probe-run --list-probes.

  1. Enable debug info

Next check that debug info is enabled for all profiles. If you are using the cortex-m-quickstart template then this is already the case. If not check or add these lines to Cargo.toml.

``` toml

Cargo.toml

[profile.dev] debug = 1 # default is true; not needed if not already overridden

[profile.release] debug = 1 # default is false; using true is also OK ```

  1. Look out for old dependencies

The cortex-m dependency must be version 0.6.3 or newer. Older versions are not supported. Check your Cargo.lock for old versions. Run cargo update to update the cortex-m dependency if an older one appears in Cargo.lock.

  1. Run

You are all set. You can now run your firmware using cargo run. For example,

``` rust use cortexm::asm; use cortexmrt::entry; use rtttarget::rprintln;

[entry]

fn main() -> ! { // omitted: rtt initialization rprintln!("Hello, world!"); loop { asm::bkpt() } } ```

console $ cargo run --bin hello Running `probe-run target/thumbv7em-none-eabi/debug/hello` flashing program .. DONE resetting device Hello, world! stack backtrace: 0: 0x0000031e - __bkpt 1: 0x000001d2 - hello::__cortex_m_rt_main 2: 0x00000108 - main 3: 0x000002fa - Reset

Stack backtraces

When the firmware reaches a BKPT instruction the device halts. The probe-run tool treats this halted state as the "end" of the application and exits with exit-code = 0. Before exiting, probe-run prints the stack backtrace of the halted program.

This backtrace follows the format of the std backtraces you get from std::panic! but includes <exception entry> lines to indicate where an exception/interrupt occurred.

``` rust use cortexm::asm; use rtttarget::rprintln;

[entry]

fn main() -> ! { // omitted: rtt initialization rprintln!("main"); SCB::set_pendsv(); rprintln!("after PendSV"); loop { asm::bkpt() } }

[exception]

fn PendSV() { rprintln!("PendSV"); asm::bkpt() } ```

console $ cargo run --bin exception --release main PendSV stack backtrace: 0: 0x00000902 - __bkpt <exception entry> 1: 0x000004de - nrf52::__cortex_m_rt_main 2: 0x00000408 - main 3: 0x000005ee - Reset

Non-zero exit code

When the device raises a hard fault exception probe-run will print a backtrace and exit with non-zero exit code.

You can trigger a hard fault exception with the UDF instruction.

``` rust use cortex_m::asm;

[entry]

fn main() -> ! { asm::udf() } ```

``` console $ cargo run --bin hard-fault stack backtrace: 0: 0x000003e0 - HardFaultTrampoline 1: 0x00000140 - udf 2: 0x00000118 - cortexm::asm::udf 3: 0x0000012c - hardfault::cortexmrt_main 4: 0x00000122 - main 5: 0x000000fa - Reset

$ echo $? 134 ```

NOTE when you run your application with probe-run the HardFault handler, default or user-defined one, will NOT be executed.

Troubleshooting

probe-run --list-probes says "No devices were found."

Apart from a faulty connection between your computer and the target device, this could be caused by several things:

[Linux only] udev rules haven't been set

In order for probe-run to find the device you'd like to run your code on, your system needs permission to access the device as a non-root user.

In order to grant these permissions, you'll need to add a new set of udev rules.

To learn how to do this for the nRF52840 Development Kit, check out the installation instructions in our embedded training materials.

No external or on-board debugger present

To use probe-run you need a "probe" (also known as "debugger") that sits between your PC and the microcontroller.

Most development boards, especially the bigger ones, have a probe "on-board": If the product description of your board mentions something like a J-Link or ST-Link on-board debugger you're good to go. With these boards, all you need to do is connect your PC to the dev board using a USB cable you are all set to use probe-run!

If this is not the case for your board, check in the datasheet if it exposes exposes SWD or JTAG pins. If they are exposed, you can connect a "stand alone" probe device to the microcontroller and then connect the probe to your PC via USB. Some examples of stand alone probes are: the ST-Link and the J-Link.

Note that this may involve some soldering if your board does not come with a pre-attached header to plug your debugger into.

Support Us

probe-run is part of the [Knurling] project, [Ferrous Systems]' effort at improving tooling used to develop for embedded systems.

If you think that our work is useful, consider sponsoring it via [GitHub Sponsors].

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.