Using Rust Packages in a C Project on Nordic Devices

This example shows how to call a function from a Rust package from C on a nRF5340 DK and nRF52840 DK.
Source: https://www.rust-lang.org/

Why would you want to use Rust?

Rust is a pretty cool 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 definitely showing.

Rust is also safer. This is because it was designed around excellent memory management practices unlike C/C++ all while still maintaining a majority of their 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 nRF Connect SDK (NCS). While it wasn’t too difficult, there definitely were some challenges.

To demonstrate this, we’ll start from the most simple NCS example, which we will modify to blink each of four LEDs on the nRF5340 DK, one at a time. We will compute the delays between blinks with a Rust library.

Book a Call with Dojo Five Embedded Experts

Development

We started from the NCS blinky example as reference but modified it to blink all four LEDs on the Development Kit (DK) board. We then created a Rust library project. After writing a simple Rust function that squares its input, we modified the CMakeLists.txt from the NCS project to build the Rust portion and link it all together. Then, we call the square function from our main.c. At this point, we’ve got one CMakeLists.txt file that builds some Rust and some C, and the C program calls the Rust library and uses the output!

We’ve posted our example online

Trying it out

You’ll need the nRF Connect SDK extension for VS Code, Rust, and our repository.

Source: https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-DK

Install the nRF Connect SDK extension for VS Code by following the instructions in the link.

Next, go through the Rust development environment setup.

In order to be able to compile the Rust library to run on the nRF DK targets, you need to make sure to install the correct Rust target.In our case, for the nRF5340 DK, use thumbv8m.main-none-eabi target. Use the following command:

rustup target add thumbv8m.main-none-eabi

If you are using the nRF52840 DK, use thumbv7em-none-eabi target. Use the following command:

rustup target add thumbv7em-none-eabi

Next, download our example from GitLab.

Here is a summary of the relevant steps we took for this implementation:

  1. Created a new Rust library using Cargo in a new square_rust_lib directory
    1. mkdir square_rust_lib
    2. cd square_rust_lib
    3. cargo init --lib
  2. Added [lib] section in the Cargo.toml to specify this package is a static library
    1. Specified the name of the library – name = "square"
    2. Specified the type of crate being built – crate-type = ["staticlib"]
  3. Added .cargo/config.toml to specify a global configuration in Rust to specify the target during the build.
  4. The following were added to square_rust_lib/src/lib.rs
    1. #![no_std] – removes the Rust standard library to use the core library instead which does not depend on the underlying operating system.
    2. extern crate panic_semihosting – brings a crate to handle panics (unrecoverable errors) required by Rust. This is also added to Cargo.toml in [dependencies].
    3. #[unsafe(no_mangle)]no_mangle tells the Rust compiler not to mangle the name of the function since we are going to call this function from another language. The unsafe keyword indicates the block of code is potentially unsafe (since this is going to be called outside of Rust context).
  5. The CMakeLists.txt is updated to add a section for building the Rust library using ExternalProject_Add as a library dependency when the blinky example is built.

Next, from the nRF Connect SDK extension in VS Code, you can build and flash the project into your DK. You’ll know it’s working when you see something like this!

Wrapping Up

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.

Next Steps

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! 

Project leaders – you can book a call with us to start the conversation about your project that needs modern embedded expertise. 

Engineers – if you are looking for a better CI build platform, check out our EmbedOps product to increase your productivity. 

Discover why Dojo Five EmbedOps is the embedded enterprise choice for build tool and test management.

Sign up to receive a free account to the EmbedOps platform and start building with confidence..

  • Connect a repo
  • Use Dev Containers with your Continuous Integration (CI) provider
  • Analyze memory usage
  • Integrate and visualize static analysis results
  • Perform Hardware-in-the-Loop (HIL) tests
  • Install the Command Line Interface for a developer-friendly experience

Subscribe to our Monthly Newsletter

Subscribe to our monthly newsletter for development insights delivered straight to your inbox.

Interested in learning more?

Best-in-class embedded firmware content, resources and best practices

Dev Containers

Automating Reliability Engineering with Unit Testing, HIL Testing & EmbedOps – Part 1

A key challenge for embedded systems developers is ensuring high-reliability operation in products designed for years-long deployments, sometimes in remote locations. A prime example of such a device is a Bluetooth-enabled environmental sensor node that performs functions such as advertising over Bluetooth Low Energy (BLE), transmitting temperature and humidity data, and supporting over-the-air (OTA) firmware updates and diagnostics. In commercial markets, tens of thousands, hundreds of thousands, or more of these units ship over the course of the product lifecycle.

Read More »
HIL Raspberry Pi

Hardware-in-the-loop is hard! Sometimes.

By: Ander Galisteo, Ph.D.
The concept of hardware-in-the-loop (HIL) is not new in the embedded space. The basic idea is to automate the functional tests of your device under development to verify if your implementation does what it’s supposed to do.

Read More »