Why Rust is a great fit for embedded software - 2023 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.
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.
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:
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.
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.
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.
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".
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!
Ready for embedded Rust?
We can help with:
- Knowledge-sharing presentations
- Rust workshops, Embedded Rust workshops
- Team augmentation
- Reducing first-project risk
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.