Why Rust is a great fit for embedded software - 2023 update

Henk
Embedded software engineer
Why Rust is a great fit for embedded software - 2023 update
A while ago, in 2020, I wrote a blog post similar to this one. Sure, it has a bit of a clickbait-y title, but it couldn't be more accurate. At the time I was full of amazement about the way Rust tackles embedded software development. I forsaw great things for Rust's future, even though Rust and its ecosystem were yet not quite mature. We're 3 years further down the road right now, which is like 300 Rust years as Rust is progressing fast. About time for an update!

In 2023, I'm even more thrilled about Rust's future in embedded. With this blog post, I want to give you a primer that you can use to decide whether Rust is for you.

What's the fuss about?

If you've heard of Rust, you've heard about it's memory safety features. Those features ensure that Rust eliminates a whole classes of bugs from your application. And it can do so at compile time, greatly shortening the feedback loop of the developer.

The memory safety bugs Rust prevents often cause Undefined Behavior (UB), and UB is no joke. UB can cause all sorts of unexpected behavior. It can even enable time travel! Undefined behaviour bugs are very hard to diagnose, as they often impact functionality that seemingly has nothing to do with the cause of the bug. Mankind has spent tons of time and headaches debugging UB. And on a device with restricted resources, debugging is already hard as it is.

Anyway, having been a spoiled Rust developer for about 4.5 years, Rust's memory safety story is starting to become a bit boring to me. Which is a good thing, because it means that Rust's guarantees are very, very strong. But I want to talk about other stuff Rust has to offer the embedded world.

Rust's toolbox

So one of the things developers dipping their toes into Rust are often stoked about, is the tools Rust has to offer. I'm talking trivially easy dependency management and cross compilation. That means, by using Rust, pulling in external libraries and making your firmware runnable on all kinds of platforms is a breeze. No need to spend hours on setting up a build script or making sure dependencies are available.

But this is not the whole story. Developing, running, and debugging Rust for embedded devices truly feels as if you're writing just another application that runs on your PC or a server. With the help of the probe-rs project, these things are much more enjoyable to do. Which in turn reduces the time spent on developing new features and debugging old ones.

Typically Rust

One of the seemingly paradoxal things about programming, is the idea that developers should not write code for machines. Yeah. Instead, they should write code for their future selves and colleagues. Readable code is maintainable and robust code. That means that while writing software, we should think well about the way we model the data and functionalities of our code. Modeling is all about semantics, giving meaning to the code we write. And Rust is very good at that.

With its extensive and very expressive type system, Rust allows you to embed meaning in your code. We call that 'Semantic Typing'. With a bit of experience, you are able to have the compiler reject things that do not make sense. And that makes onboarding new developers to existing projects, refactoring, and debugging just so much less time consuming.

Web of Rust

Many people working in embedded development know the pain of dependencies not working together nicely. Say you have settled on an RTOS to run your application code, but a driver for your sensor is only available for another RTOS. Or imagine that during product development, you conclude that your product can be so much better if you switch microcontrollers, but firmware development has already progressed significantly. Or what if you want to test parts of your firmware's business logic and communication functionality on CI?

What you need is fundamentally cross-platform code. You need code that is abstract from much of the ecosystem it will run in. Rust gives you just that. The Rust embedded ecosystem of runtimes, Hardware Abstraction Libraries (HALs), and drivers revolves around one library: embedded-hal.

Using Rust's delightful type system, embedded-hal has models (Rust developers would call them 'traits') for all kinds of peripherals, in terms of which drivers and HALs can be written. For instance, embedded-hal's model of SPI peripherals allows drivers to be written in terms of what we can expect from SPI peripherals to support. How these SPIs support those things, is defined in the microcontroller-specific HAL. The drivers specify what should be written to a sensor in order to configure it or read out its data, and the HALs specify how things can be written to sensors in general. And the cool thing is that the great majority of the HALs, runtimes, and drivers out there use embedded-hal to abstract code: a whole web of compatible libraries exists for Rust. This gives code precisely the flexiblity it needs to be truly portable.

It can't all be great, right?

Ok, so why hasn't the embedded software field moved to Rust yet? Especially if you're invested in C or C++, you'll probably have concerns about introducing Rust. That's valid, of course. I want to highlight a couple of important things that stand in the way of Rust becoming the new mainstream programming language in embedded, and how I think these things can be overcome.

Vendor support

One concern often expressed by people with whom I talk about Rust, is support from hardware vendors. If you're doing C or C++, you can count on vendors providing HALs, drivers, and usage examples. More importantly, you can contact a vendor if something is wrong with the provided code. Most chip vendors support just C or C++, and as Rust is a newcomer with a relatively small user base, why would they take on the work of supporting Rust? And if your company relies on vendor support and guarantees, this is a real problem.

The Rust embedded ecosystem consists mostly of community-written, open source software. If you're relying heavily on vendor support, you may find that support by a community calls for a change of attitude. Yes, open source has its flaws, but it can greatly improve your overall development speed. For instance, it allows you to add any missing features yourself, the way you want it.

Vendor support for Rust is slowly getting there, though. In the last couple of years, both Infineon and Espressif have started working on software development kits and tools for Rust.

Chip support

This hurdle stems from the previous one. The Rust embedded ecosystem greatly varies in completeness or even availability of support for certain chips. Rust does not have C's advantage that virtually any architecture is supported, but even if Rust supports the architecture of a microcontroller, there may not be a HAL available for it, or it may be incomplete. Especially newer chips suffer from this problem. Where to start? I won't deny that contributing HALs and drivers yourself is a sizable investment. I will say, however, that it gets better and better. At Tweede golf, we've gotten pretty good at giving back to the open-source community. And once you see the design patterns going on in many of Rust's HALs and drivers, writing or contributing to them becomes quite easy. And of course, you can look at vendor-provided code as an example.

Chicken-and-egg

The way I see it, Rust has a bit of a circular problem going on. See, many companies foresee trouble finding developers that are good at Rust if they were to migrate to the language, so they are putting it off. And this is a real problem, because why should developers invest lots of time in learning Rust if almost all embedded development jobs are for C or C++ developers?

I believe this is yet one of the major blockers of Rust making it big. To do our part in breaking this cycle, Tweede golf organizes workshops introducing Rust as a language, as well as how to use Rust to write embedded software. On top of that, we are working on Rust 101, a modular, reusable Rust course for universities.

I firmly believe that getting developers to be fully productive with Rust is not that hard. And by fully productive, I don't mean just being able to write functionality, but writing high-quality, low-bug, readable, maintainable software. A recent article from Google supports this: "more than 2/3 of respondents are confident in contributing to a Rust codebase within two months or less when learning Rust".

Time until confident in Rust Image taken from this blog by Lars Bergstrom and Kathy Brennan

Impressive! I also believe that once companies realize this, Rust is ready for take off. It is well worth the fight!

(our services)

Ready for embedded Rust?

We can help with:

  • Knowledge-sharing presentations
  • Rust workshops, Embedded Rust workshops
  • Team augmentation
  • Reducing first-project risk

> Rust services

If you'd like to know whether Rust is a good fit for your company or you'd like some help getting your team started, don't hesitate to contact Hugo or take a look our Rust services page.

Stay up-to-date

Stay up-to-date with our work and blog posts?

Related articles

At Tweede golf we're big fans of creating applications on embedded devices with Rust and we've written a lot about it.

But if you're a hardware vendor (be it chips or full devices/systems), should you give your users Rust support in addition to your C support?

In this blog I argue that the answer to the question is yes.

NLR, Royal Netherlands Aerospace Centre, invited embedded lead Dion to explain the benefits of programming in Rust to the company.

Pioneering Rust in the high-tech industry!

Together with High Tech Software Cluster, we organized an event to showcase Rust’s strengths and safety features to tech companies in the Brainport region in the Netherlands.