Learning Rust For Embedded Systems
The Motivational Portion
Based on recommendations from Kevin Nause, the VolksEEG project is considering using Rust as the embedded system programming language. So I've been off on a tear skimming books and e-books and watching videos at 2x to evaluate it.
My conclusion? Do it!
Most of the rest of us participants are primarily C/C++ embedded developers. I had previously been sensitized to Rust for embedded systems by this presentation from Feabhas, and had bought but not yet read a book on beginning Rust.
One of the risks in switching to a new language is the learning curve, and in particular the mistake curve. You know that any time you pick up a new programming language, you have to get through a bunch of newbie mistakes. It's just part of the learning process, and they're very educational. It takes time.
But here's the thing. After plowing through lots of material at high speed, I've come to the conclusion that the Rust team looked at all the programming mistakes of the past 70 years (like Tony Hoare's "billion dollar mistake", smashing the stack for fun and profit, and the Mars Pathfinder bug) and actually learned the lessons, and made it so you couldn't make those mistakes in Rust.
That's a very bold assertion. I've proven empirically that all possible types of bugs will eventually occur. When I mentioned that to the VolksEEG team, someone commented that they've been able to replicate my work. If the language and the development environment allow it, it will happen.
What if the language doesn't allow it? What if the language and the compiler enforce a set of rules that prevent those things from happening? Yes, it's a change in mindset and programming discipline, but I can immediately see the value.
It embodies Edsger Dijkstra's magnificent aspiration: "If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with."
Can you still make mistakes in Rust? Of course. But whole classes of problems have been eliminated. That makes it inherently safer and more reliable. Without sacrificing performance (yes, I hear you assembly-language-or-the-highway folks grumbling).
Another concern is that the language might be difficult to learn. My assessment is that there's enough familiar DNA that most experienced developers should be able to pick it up easily enough. Design and abstraction are language-agnostic. The rest is just syntax.
Yes, there are some new rules and a few syntactic oddities. They mean some adjustment. But the benefit has the potential to be huge. All that banging your head against the wall when you step in one of the usual open manholes? Gone. The manholes have been sealed up. Think of the time saved, the time-to-market gained, the customer nightmares avoided.
So take the time for the learning curve. It looks like a worthwhile investment.
While at first glance there are a lot of new concepts to digest in Rust, in many cases they're familiar from other languages, just with a different approach and terminology. The Rust team did make a few explicit design choices that have ripple effects, but they still fit in with familiar concepts.
A quick list of the top items:
- Ownership and borrowing: these are first-class concepts in Rust, critical to the safety it offers. This includes explicit lifetime annotations to override compiler defaults. But they're familiar to anyone who knows C++ smart pointers, references, and move semantics.
- Traits: these are like interfaces, abstract classes, and virtual functions in object-oriented languages. They provide polymorphism, meeting the Open-Closed Principle.
- No inheritance, only composition: What?!? Yes, a different design choice, yet still offers polymorphism.
- RAII: Resource Acquisition Is Initialization means when a variable goes out of scope, its destructor is called and its resources are freed. That's built-in directly. You can implement the drop trait to call code when that happens; Kevin uses this to serialize/deserialize memory to/from disk to implement persistent variables without having to think about it.
- Generics: C++ templates.
- No exceptions: instead, error handling and unwrapping.
- Attributes: these are similar to compiler and preprocessor directives.
- Unsafe: it's possible to call code in other languages, but this is by definition unsafe, since the compiler can't enforce its rules. So unsafe annotations make that explicit, and allow bypassing compiler protections.
- Cargo: the package manager and build system.
- Build types: release, debug, and test builds are all first-class concepts. No awkward fidgeting with the build system to get the desired build.
The Learning Resources
Kevin directed me to a number of good resources, and there are lots more out there once you go looking. I offer the following as a loosely-curated directed path to streamline the on-ramp.
What's been useful for me is to alternate videos and written material (watching at 2x speed and skimming for the sake of depth and breadth at this point). The videos lead you through specific topics to familiarize you with them, and then the books provide additional tutorial and reference material. Once you've made a large-scale summary pass through them all, you know where to go back for more focus.
I always like learning from multiple resources, because each one has a different perspective, emphasis, and coverage.
I'm very impressed with the quality of information available from the Rust community. That's consistent with the overall quality of the entire Rust software development ecosystem and tooling. Like the language safety aspects, they've done a thorough job.
This list starts with language basics (think Kernighan and Ritchie's The C Programming Language and Stroustrup's A Tour of C++), then moves specifically to embedded systems development (think Barr's Programming Embedded Systems in C and C++ and White' Making Embedded Systems).
- Video: Rust Crash Course, by Brad Traversy. This is a fantastic quick tour, a la K&R, that introduces a number of concepts to the absolute beginner.
- Video series: Rust Tutorial, by Doug Milford. This is the longer tour, a great follow up, that goes through in more detail.
- Book: Beginning Rust: From Novice to Professional, by Carlo Milanesi. I picked this at random from the many books I found listed after seeing the Feabhas presentation I mentioned at the beginning, and was quite happy with it. It's also in the spirit of K&R, but more verbose, explicitly breaking things down line by line. That verbosity is especially helpful when elaborating some of the new concepts.
- Online book: The Rust Programming Language, by Steve Klabnik and Carol Nichols. This is excellent, taking a slightly different emphasis from Beginning Rust, and covering some additional topics.
- Online book: Rust by Example (RBE). A collection of runnable examples that illustrate various Rust concepts and standard libraries. Run them!
- Video: Rust Testing and TDD - An Intro to Testing and Test Driven Development, by Tensor. This expands the testing introduced in The Rust Programming Language to TDD usage.
- Video: An Overview of the Embedded Rust Ecosystem, by Frans Skarman. This is a fantastic introduction to Rust for embedded systems, including system package architecture.
- Online book: The Embedded Rust Book. I haven't actually started this one yet, but a quick flip through it leads me to believe it's as good as The Rust Programming Language. I've ordered the STM32 Discovery kit that it uses so I can follow along hands-on.
- Video: RTIC: Real Time Interrupt driven Concurrency, by Emil Fresk. RTIC is a simple scheduling executive, like a cross between lightweight RTOS and bare-metal-superloop-with-interrupts.
- Online book: RTIC: Real-Time Interrupt-driven Concurrency. I haven't started this one either, but again a quick flip through looks good.
- Video: Rust in Safety Critical Systems Panel, led by James Munns of Ferrous Systems GmbH (the Rust ecosystem is full of puns!). This is more of a bonus video, and a little long, but it discusses many pertinent issues for embedded and safety-critical systems, with some interesting tidbits.
- Video: James Munns, interview by Nathan Aschbacher. This is another bonus video with interesting discussion of Rust in embedded systems.
- Blog post: What we’ve got here is a failure to communicate, by Trevor Jim. Another motivational view in favor of Rust. He has a number of additional relevant safety/security posts.
Here's another bonus. Have you ever used OpenOCD with your ST-Link, J-Link, or CMSIS-DAP based probes for debugging your embedded system? Works great...once you get it configured. That can be a major impediment. Now try probe-rs for Rust. Like all the rest of the Rust tooling, the goal is to make it easy.
There are several references to Ferrous Systems above. They're an excellent overall resource, at https://ferrous-systems.com/, as well as the Embedded devices Working Group, where The Embedded Rust Book comes from.
That's enough to keep you busy for a few days, especially if you do the hands-on exercises. Which of course, you should. The only way to truly develop these skills is to try them. You'll make the inevitable newbie mistakes (or see where the stricter Rust compiler doesn't let you), work through the necessary mental adjustments, and build the cognitive muscle memory.
Finally, a huge thank you to Kevin for pointing us in this direction, and to the Rust team for creating something that will truly change the world!
To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.
Registering will allow you to participate to the forums on ALL the related sites and give you access to all pdf downloads.