17 comments

[ 3.1 ms ] story [ 41.7 ms ] thread
Authors are from STMicro, polytechnic Turin, Freie universitat Berlin, and Inria. Examined writing firmware for an IOT sensor platform. From the abstract:

> 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.

One of the authors commented below that the “teams” were actually persons and the Rust person was an intern.

This is even less serious than the typical pattern of grabbing random students for experiments and then drawing conclusions about the general population.

One of the author's here, if there are any questions!
I'm a big fan of Rust on embedded (and think embassy in particular is awesome, haven't tried this Ariel OS.)

I would say however that there's still toolchain issues here. There all kinds of MCUs that simply don't/won't have a viable compiler toolchain that would support Rust.

e.g. I recently came from a job where they built their own camera board around an older platform because it offered a compelling bundle of features (USB peripheral support and MIPI interface mainly). We were stuck with C/C++ as the toolchain there, as there was no reasonable way to make this work with Rust as it was a much older ARM ISA

off topic question: why is there no source attached to this paper?
> It is concluded that Rust is a sound choice today for firmware development in this domain.

This conclusion was reached with a single experiment.

> Two teams concurrently developing the same functionality — one in C, one in Rust — are analyzed over a period of several months.

> 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.

> The authors thank Davide Aliprandi and Davide Sergi of the STAIoTCraft team, and the wider Ariel OS team.

So one team had Ariel OS developer support, and it's unclear what support the other team had. Seems fair.

In Figure 12, they simply stop optimizing the code once desired rate is reached. Just at the end of the project the Rust firmware gets over a third performance boost, most likely from their OS developers.

Additionally, there is a claim that "Ariel OS is shown to provide an efficient and portable system runtime" - but there are no real tests for portability are conducted. Worst still:

> Where C-based projects require a separate project setup and manual code copying per target, Rust on Ariel OS consolidates everything within a single project [..]

This claim is just not true. This sounds like somebody that is not as familiar with C.

We passed on Rust for Ada/SPARK2014 to write to bare metal on Cortex-M processor for real-time, high-integrity, and verifiable mission-critical software. Rust is making strides to be a future competitor, but it's new to the formal verification tooling and lacks any real world legacy in our domain. Ada's latest spec. is 2022. Other than AdaCore's verified Rust compiler, Rust still does not have a stable language specification like C/C++, Lisp, or Ada, SPARK 2014. I have no doubt that it will start rising to tick all the boxes that Ada/SPARK do right now with their decades of legacy in high-intetrity, mission-critical applications. The mandate to use memory-safe software put into effect this past Jan 1 2026 puts some wind in Rust's sails, but it's more than memory-safety in this domain. Plus, I do not enjoy Rust, but Cargo is nice. We're looking at Lean for further assistance in verifying our work. I think there was and is lot of Rust evangelism that will also carry it forward and boost even more Rust popularity,
I've read (from one from one of the people that contribute to Rust afair), that they were involved building formal verification for Rust, and found that the control flow is just so complex that its very hard to use the language like this.
Really strange the the C JSON parser has to use malloc where the RUST version does not. As if it is not possible to write a JSON parser in C that does use malloc. I presume that the syntax of the commands that the device will accept is known, and than there is no reason why you have to build a DOM of the JSON before you can process it. Apparently, the RUST version can do it. I really begin to question the abilities of two teams if the one team failed to implement a JSON parser solution without using memory allocations.
Good article! I will give you my 2c, as someone in this space mostly for hobbies, but with one active work project:

Rust is fantastic for embedded. There are no hard obstacles. The reason to do it IMO is not memory safety, but because holistically the language and tools are (to me) nicer. Enums, namespacing, no headers, `cargo run --release` "just works". (I have found, at least in OSS, compiling C embedded project is a mess. Linker errors, you need to have a certain OS with certain dependencies, there are many scripts etc). Good error messages, easy to structure your programs in a reliable way etc. Overall, I just find it to be a better designed language.

I have found the most fundamental tooling for rust on Espressif's RiscV, and Cortex-M ARM for various STM-32 variants to be great. The cortex-m crate, defmt, and probe-rs, and the PAC project is fantastic.

On the down side, I have have to build my own tooling. I wrote and maintain my own HAL for STM32, and have had to write my own libraries for every piece of hardware. This comes with the territory of a new language, and suspect this will gradually improve this time - especially with vendor support. Because the fundamental libraries are around, this is just reading datasheets and making rust functions/structs etc that do the MMIO as described in the datasheets. Can be tedious (Especially if building a complete library instead of implementing what you need for a given project), but is not an obstacle.

My most complicated rust embedded firmware was a FPV-style UAS. I did it without an RTOS, using interrupt-based control flow.

I'll start of by saying I really hate C (also love it), and welcome improvements; but I have a few criticisms:

- Sensor agent is such a rancid name for a remote sensor that I feel a need to public say so. Please don't use marketing names for things that already have more descriptive names.

- Rust uses a full RTOS and C uses the mediocre ST HAL (vendor specific). Immediately apples to oranges. Also I've never heard of the C JSON library and it looks sketchy at a glance so that will also hurt the comparison.

- Streaming slow sensor data with a 160MHz 786KB/2MB MCU is not a good test in the slightest. You could probably use something like micro python here and be done. No one is reaching for bare metal C here. Also no one serious about performance is using JSON serdes. If you're using bare metal C, you're likely trying to push the limits of your hardware or doing something so simple that you won't be tempted to reach for terrible third party libraries.

- Does the Rust code base use the 'unsafe' keyword anywhere, including the RTOS? If so, it's not memory safe without additional formal verification.

Overall I'd say this paper has approximately zero value wrt its stated goal of comparison.

Lots of handwaving about fear of rust changing too often and even MORE downvoting of this as if there is no concern whatever. Neither of these extremes are valid.

For me it comes down to the old standby: just vendor the .cargo build chain into your repo and be done with it. There you go. Lock in the year edition, the version, the features, the quirks, and the bugs. Just like game devs did with game engines or OpenGL or Direct X versions.

Do linker scripts look the same in the rust tool chain? (E.g. for implementing a bootloader?)
Yes. It uses the same linker as a C/llvm toolchain, by the time you link the object files from Rust are in the same format as the object files from C would be. You use the exact same linker script format too.
Hhaving worked on quite complex embedded projects, my 2 cents is that dynamic allocation should be avoided as much as possible (and its been possible to avoid it 100% of the time for me).

Memory layouts are often pre planned, with hand-written linker files, which are sometimes even necessary, as there are quirks like DMA only being able to access certain addresses etc.

In embedded, engineers often want hard real time guarantees, very high (essentially unfailing) reliablity, at the lowest possible price points.

Dynamic memory allocation is often no good - embedded allocators either waste RAM, have large code sizes, have worse runtimes than their desktop-grade cousins - something like jemalloc generates 10x as much code as the rest of your app, and assumes your heap is at least megabytes in size.

On the other hand, embedded-grade allocators often use algorithms that are prone to fragmentation, unpredictable runtimes, and tend to be less tested in general, while still wasting RAM and Flash.

Having an allocator that has a bad runtime behavior can basically ruin your hard runtime guarantees, and if you prealloc all you memory you will never run out - on the other hand, even the paper states they measured not calculated the max memory usage, meaning we have no knowledge of what the actual max is.

My biggest gripe with Rust, which certainly reflects my own shortcomings, is that when I go back and revisit simple Rust programs I wrote more than a year ago, it takes me a long time to understand what I was even doing in a particular part of the program. This is my weakness ... I'm not great with Rust and I don't use it enough to get better. But it is what it is.

In contrast, when I go back and read Go or C code I wrote years ago, I have no trouble at all quickly figuring out what I was doing in the small programs I write.

The way these issues manifest themselves, as it recently did, was I went back to add a simple addition to a CLI tool I wrote for myself a year ago, and I was having trouble doing it because I couldn't quickly understand what I had been doing a year ago ... so I just had an AI agent do it for me. This was the kind of change that if it was a Go program, I would've done manually myself in about 5 or 10 mins.