Study compares Rust and C languages for embedded firmware development

There’s a lot of hype around the Rust programming language, and I’m seeing it being adopted by various projects, not least the Linux kernel. However, so far it was unclear to me whether it was suitable for embedded firmware development since the hardware resources are limited on microcontrollers. A low memory and storage footprint is required, and optimal performance may also be important, for example, to lower the power consumption of battery-powered devices.

A research paper by STMicroelectronics, Inria, and the Freie Universität Berlin, entitled “Lessons from an Industrial Microcontroller Use Case with Ariel OS” published on ArXiv hosted by Cornell University, attempts to answer this question using embedded C and Rust, and the conclusion is that Rust is a viable option:

As Rust gains traction for developing safer systems software, a reality check for the microcontroller hardware segment becomes necessary. How ready is the Rust ecosystem for this segment? Can Rust compete with C in practice?

This paper reports on an IoT industrial case study that contributes to answering these questions. Two teams concurrently developing the same functionality (one in C, one in Rust) are analyzed over a period of several months. A comparative analysis of their approaches, results, and iterative efforts is provided. The analysis and measurements on hardware indicate no strong reason to prefer C over Rust for microcontroller firmware on the basis of memory footprint or execution speed.

Furthermore, Ariel OS is shown to provide an efficient and portable system runtime in Rust whose footprint is smaller than that of the state-of-the-art bare-metal C stack traditionally used in this context. It is concluded that Rust is a sound choice today for firmware development in this domain.

But let’s not take the conclusion for granted, and check out the research (PDF) to understand the method and results better.

SensorTIle.Box PRO

The hardware used was the SensorTile.box Pro devkit with an STMicro STM32U585AI Arm Cortex-M33 microcontroller, BLE and NFC connectivity (not used here), and a 6-axis LSM6DSV16X IMU3, and the ST AIoT Craft Edge AI Suite enabled AI processing of the captured sensor data.

The devkit runs the Vanilla Data Logger (VDL) firmware written in C or Rust and communicates with a PC running a GUI over the Vanilla Datalog Protocol (VDP) through a UART interface.
VDL firmware ST AIoT Craft PC communication

Each team worked independently for six weeks during Phase 1 of the implementation of the VDL firmware in C and Rust, and then collaborated for four more weeks to optimize each other’s work. The C implementation relies on STM32CubeMX, a Finite State Machine (FSM) written in bare-metal C, and the open-source Parson library for JSON de/serialization (note: uses dynamic memory allocation).

VDL App C language
C implementation

The Rust firmware relies on Ariel OS Rust RTOS for microcontrollers, and implements JSON serialization/deserialization using the serde crate, offering a serialization/deserialization framework, and the heapless crate for static memory allocation.

VDL App Rust language
Rust implementation

Since the architectures are fairly different, it’s not going to be a direct C vs Rust comparison, but here are the final results when it comes to memory and storage footprints.

Metric (bytes)VDL-C VDL-RustΔ (Rust − C)
.text66,24069,7643,524
Total ROM76,74484,1007,356
Stack RAM2,04810,2408,192
Static RAM14,96014,400-560
Heap RAM25,6000-25,600
Total RAM44,65624,640-20,016

Both VDL firmware binaries are quite small, but the C firmware is still smaller than the Rust firmware. It does not matter much here since the STM32U585AI comes with 2MB flash, but it may matter if we get close to the storage limit on even more resource-constrained MCUs, and either more optimization is required or switching to a different part may be needed. The RAM comparison is more complex due to dynamic memory allocation, which requires heap RAM for the C implementation.  The number shown is the max measured peak of heap. They also note that “there are less memory heavy options that do not require a heap at all” compared to the Parson library, since memory optimization was not the main goal.

C vs Rust firmware breakdown
C vs Rust firmware breakdown

Both Rust and C firmware ended up running at the same level of performance as measured by the Output Data Rate (ODR): 7,468 Hz. The chart below shows that whether you select C or Rust for your next embedded project, firmware won’t automagically be optimized for size and/or performance without serious work.

C vs Rust performance
C vs Rust performance

The Rust implementation was twice as fast as the C implementation during the first test, and C and Rust traded the top spot in turns following optimizations, which included trivial changes such as disabling logging (for debugging) and enabling I-Cache and flash prefetch to lower I2C latency. You’ll learn more about caveats and pitfalls in the full PDF.

What I found interesting is that in the second phase, each team helped the other build a better firmware by comparing C and Rust firmware. In theory, the best is to select both C and Rust for your next product, but in practice, it’s unlikely to work due to budget constraints. The source code for the project will eventually be published on STM32 Hotspot.

Via Adafruit.

Share this:

Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress. We also use affiliate links in articles to earn commissions if you make a purchase after clicking on those links.

Radxa Orion O6 Armv9 mini-ITX motherboard
Subscribe
Notify of
guest
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
6 Comments
oldest
newest
Boardcon MINI1126B-P AI vision system-on-module wit Rockchip RV1126B-P SoC