-
Create a new Rust project named
hello_microbit.Bare metal projects are created using the
cargo newcommand. This command creates a new Rust project with the specified name.cargo new hello_microbit
-
Change to the
hello_microbitdirectory.cd hello_microbit -
Add the following crates to the
Cargo.tomlfile under the[dependencies]section.cortex-m = "0.7.3" cortex-m-rt = "0.7.0" panic-halt = "0.2.0" rtt-target = { version = "0.3.1", features = ["cortex-m"] } panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] } microbit-v2 = "0.13.0"
cortex-mprovides low-level access to the ARM Cortex-M processor.cortex-m-rtprovides runtime support for Cortex-M microcontrollers.panic-haltprovides a panic handler that halts the program.rtt-targetprovides RTT logging support.panic-rtt-targetprovides a panic handler that logs messages to RTT.microbit-v2provides the API for the micro:bit.
-
In the root folder of the project, create a new file named
Embed.tomland add the following content to it.The
Embed.tomlfile specifies the default configuration for the project. Thechipfield specifies the target chip. This is required for thecargo embedcommand to know which chip to target.[default.general] chip = "nrf52833_xxAA" [default.rtt] enabled = true
The
rttsection specifies the RTT configuration. Theenabledfield specifies whether RTT logging is enabled. This is required for thecargo embedcommand to enable RTT logging. When theenabledfield is set totrue, RTT logging will be displayed in the terminal. -
In the root folder of the project, create a new file named
memory.xand add the following content to it.The
memory.xfile specifies the memory layout of the target device. TheFLASHsection specifies the flash memory region, and theRAMsection specifies the RAM memory region. This is required for the linker to know where to place the code and data. The configuration is specific to the target device.MEMORY { FLASH : ORIGIN = 0x00000000, LENGTH = 512K RAM : ORIGIN = 0x20000000, LENGTH = 128K } -
In the root folder of the project, create a new file named
build.rsand add the following Rust code to it.This will copy the
memory.xfile to the output directory and specify the output directory as the linker search path. In Rust, thebuild.rsfile in the project's root folder is a build script that is run before the build starts. This is useful for generating code, running external tools, or setting up environment variables.use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf; fn main() { let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("memory.x")) .unwrap() .write_all(include_bytes!("memory.x")) .unwrap(); println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=memory.x"); }
-
Create a new folder named
.cargoin the root folder of the project.mkdir .cargo
-
In the
.cargofolder, create a new file namedconfig.tomland add the following content to it.[build] target = "thumbv7em-none-eabihf" [target.thumbv7em-none-eabihf] runner = "probe-rs run --chip nRF52833_xxAA" rustflags = ["-C", "linker=rust-lld", "-C", "link-arg=-Tlink.x"]
buildsection specifies the build configuration, in this case, the target architecture.targetsection specifies the target architecture and therustflagssection specifies the linker arguments. This will target the ARM architecture and use thelink.xfile as the linker script.
-
Open the
src/main.rsfile and add the following Rust code to it.#![deny(unsafe_code)] #![no_main] #![no_std] // `entry` is the entry point of the program, `main` is not assumed because of `no_main` use cortex_m_rt::entry; // the `microbit` crate provides the API for the micro:bit // if this is omitted, the compile will fail use microbit as _; // `rtt_target` is used for RTT logging use rtt_target::{rtt_init_print,rprintln}; // `panic_rtt_target` is used for panic messages use panic_rtt_target as _; #[entry] fn main() -> ! { // initialize RTT logging rtt_init_print!(); loop { // print a message to the RTT log rprintln!("Hello from micro:bit!"); } }
- #![deny(unsafe_code)]: This attribute denies the use of unsafe code in the entire crate. If any unsafe code is present, the compiler will produce an error. This is used to enforce memory safety and other guarantees provided by Rust.
- #![no_main]: This attribute indicates that the crate does not use the standard main function entry point. This is typically used in embedded systems or operating system kernels where the entry point is defined differently.
- #![no_std]: This attribute tells the compiler that the crate will not use the Rust standard library (std). Instead, it will use the core library, which is a subset of the standard library that is suitable for environments without an operating system, such as embedded systems.
-
Build and flash the project to the Microbit.
The
--targetoption specifies the target architecture. This is required when building for a bare-metal target.cargo embed
The message
Hello from micro:bit!should be repeatedly displayed in the terminal.Note - if multiple devices are listed when running
probe-rs list, then the--probe VID:PIDis required. When runningprobe-rs listyou may get results similar to this (especially on Windows).The following debug probes were found: [0]: BBC micro:bit CMSIS-DAP -- 0d28:0204:9906360200052820E80868D4C568AC33000000006E052820 (CMSIS-DAP) [1]: CMSIS-DAP v1 -- 0d28:0204:9906360200052820e80868d4c568ac33000000006e052820 (CMSIS-DAP)The value
0d28is the VID, and0204is the PID. Using these values, run thecargo embedcommand like this.cargo embed --probe 0d28:0204
Run the embed command with your VID and PID values.