This repo contains some experiments to run Rust on the BBC Micro:bit. Much of the setup is based on the guide Embedded Rust setup explained. For other resources see below.
To build and download the binary to the target, use cargo embed --bin <binary-name>
,
where binary-name
is one of the workspace members (see Cargo.toml
for details).
cargo size -- -Ax
- Print size informationcargo objdump -- --disassemble
- Disassemble the binarycargo embed --chip <chip-name>
- Download the binary to the target. Use theprobe-rs chip list
command to find all supported chips.
Configuration for the cargo embed command is stored in the Embed.toml
file.
See cargo-binutils for
details.
probe-rs list
- List all connected debug probesprobe-rs chip list
- List all connected debug probesprobe-rs run --chip-erase
- Erase the chipprobe-rs info
- Gets info about the selected debug probe and connected target
Use rustup target add <target-name>
to add support for targets in the build
tool chain. Check the platform-support page for
details.
- Microbit: thumbv7em-none-eabihf
Install llvm-tools and cargo-binutils
rustup component add llvm-tools
cargo install cargo-binutils
Cargo binutils is a wrapper around llvm-tools for better ergonomics.
Cargo embed is now part of probe-rs and is installed using
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh
To list attached probes, use the command probe-rs list
See documentation at cargo-embed and probe-rs.
Real-Time Transfer (RTT) I/O protocol. Implements input and output via a debug probe using in-memory ring buffers and polling.
Target side implementation of the protocol: https://crates.io/crates/rtt-target
The implementation requires a platform specific critical section
implementation. For cortex-m, this can be accomplished using the cortex-m crate
optional feature critical-section-single-core
. Add this using:
cargo add cortex-m --features critical-section-single-core
See https://docs.rs/cortex-m/0.7.7/cortex_m/#critical-section-single-core
for
details.
Enable RTT by adding the following to the Embed.toml
file:
[default.rtt]
enabled = true
In order to connect to an ARM device using GDB, the arm-none-eabi-gdb
version
of GDB is needed. For Arch Linux, this is installed using sudo pacman -S arm-none-eabi-gdb qemu-system-arm openocd
. It is also possible to use the
gdb-multiarch GDB command if it is available for the host platform. See the
Rust Embedded
book
for details.
Enable GDB support by adding the below to the Embed.toml
file. Note that GDB
and RTT cannot be enabled at the same time.
[default.gdb]
enabled = true
[default.reset]
halt_afterwards = true
Download the binary to the target with the debug probe using cargo embed
and
then start gdb (using arm-none-eabi-gdb
or gdb-multiarch
) in another
terminal, providing the binary. Dump the errors to /dev/null.
arm-none-eabi-gdb ./target/thumbv7em-none-eabihf/debug/rust-microbit 2>/dev/null
Then connect to the target in gdb and try out some commands.
target remote:1337
info registers
disassemble
set print asm-demangle on
monitor reset
The PAC for the Microbit can be found on the Crates page. Search for nrf52833 and select the Pac. Use cargo add to use the crate in the build.
cargo add nrf52833-pac
To be able to use the pac, we need to import it. The command for that is as follows:
use nrf52833_pac::{p0::pin_cnf::W, Peripherals};
We include the Peripherals and the pin configuration type W
. This actually
seems to be optional in this case since the Rust compiler can deduce the type,
but we include it for clarity.
We create a variable called p that takes ownership of the Peripherals using the following command:
let p: Peripherals = Peripherals::take().unwrap();
We can now configure the pins as we want. The write function takes a closure as input. See pin_cnf write. We set pins 21 and 28 as output pins:
p.P0.pin_cnf[21].write(|w: &mut W| w.dir().output());
p.P0.pin_cnf[28].write(|w: &mut W| w.dir().output());
Now it is possible to use the write
function on P0.out
to write to the
pins. We toggle the output of pin 21:
p.P0.out.write(|w| w.pin21().bit(is_on));
Build and flash using cargo embed
.