This example shows how to call a function from a Rust package from C on a NRF52840-DK.
Why would you want to use Rust?
Rust is a pretty cool new programming language that aims to make fast, safer executables. There has been a strong effort to get Rust working well on embedded devices, and it’s starting to show.
Rust is also safer. Rust was designed to provide safer memory management than C or C++ while still keep the majority of the speed advantages. In practice, this means fewer crashes and fewer vulnerabilities.
We recently had a request to call some Rust functions from inside an existing C program that uses the Nordic SDK. While it wasn’t too difficult, there definitely were some snags.
To demonstrate this, we’ll start from the most simple Nordic SDK example, which blinks each of four LEDs on the nrf52840-DK, one at a time. We will compute the delays between blinks in Rust.
We started from the Nordic SDK blinky example.
We then created a Rust library project, and brought in the nrf52-hal as a git submodule. After writing a simple Rust function that squares its input, we modified the Nordic SDK Makefile to build the Rust portion and link it all together. Then, we call the square function from our Nordic Blinky example, completing the chain—we’ve got one Makefile, that builds some Rust and some C, and the C calls into Rust and uses the output!
Trying it out
You’ll need the GNU Arm Embedded Toolchain, the Nordic SDK, Rust, and our repository.
Install the GNU Arm Embedded Toolchain. You can do this with instructions at https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm, but depending upon your OS and preferred package manager, there may be a different way you want to install it.
Install the Nordic SDK. You can do this through the nRF Connect for Desktop app, or manually.
Installing the nRF Connect SDK manually Configure the Nordic SDK, by editing the variables in
components/toolchain/gcc/Makefile.posix (on Linux and Mac) or
components/toolchains/gcc/Makefile.windows (on Windows) to point at the GNU Arm Embedded Toolchain
Next, go through the Rust development environment setup.
When we did this, we needed the nightly version of Rust, rather than the “stable” version. To get this:
rustup install nightly rustup component add llvm-tools-preview rustup target add thumbv7em-none-eabihf --toolchain nightly cargo install cargo-binutils
It has a submodule, so you’ll want to make sure you check out submodules when you clone with
git clone --recursive or run
git submodule update --init --checkout after it’s checked out.
Open the project’s Makefile in your favorite editor, and edit
SDK_ROOT to point at the root folder of your configured Nordic SDK.
make. If it looks like it worked, plug in your dev board, and run
make flash. You’ll know its working when you see something like this!
If you have some C or C++ that’s working fine, but you want to add some Rust to it, you can! You may not get 100% of the benefits of Rust in your whole system, but this hybrid approach can be fast and effective. By calling into Rust from C or C++, you can take advantage of embedded Rust while keeping your tried and true existing code.
And if you have questions about an embedded project you’re working on, Dojo Five can help you with all aspects of your devops for embedded journey! We are always happy to hear about cool projects or interesting problems to solve, so don’t hesitate to reach out and chat with us on LinkedIn or through email!