Embedded Rust: CTOs’ Favourite, But Why?
By: Sho Kaneko
Tags: IoT, Startup, Rust, Tech, DevOps

You are probably reading this because either you are an awesome geek who keeps learning new stuff, or simply because your CTO told you to build firmware in Rust. This article is aimed to give you some idea on why Rust has become a thing among tech firms, its pros/cons from engineer’s perspective compared to traditional firmware development, and some tips for getting your piece of hardware (Cortex M) running on embedded rust.

C as a common “textbook” firmware language, and why people still love it

Having joined countless robotics hackathons during my time at University of Hong Kong plus a fortunate overseas exposure in Silicon Valley as intern, I thought I was pretty familiar about firmware. Me and most of embedded people at my age started doing embedded projects with Arduino (or 51 MCU if you are Chinese), then NodeMCU for some Wi-Fi projects in personal time. More enthusiastic guys would go STM32, and usually they are the one who are so determined that it became their career.

Writing such firmware meant writing .c and .h files, and the rest is spending 70% of the time testing and debugging with real hardware. While working on these projects, embedded guys naturally become more familiar with UART/I2C/SPI drivers, and some more advanced stuff like flash, bootloader, display and internet connectivity. You are pretty good already if you have used RTOS. Awersome embedded guy should have enough project experience so you can spot the cause of issue right away.

Everything based on C, and what you do is to go GitHub (CSDN if in China), type peripheral name, and see if you have a chance to get a sample code to work from. If things didn’t work well, download its datasheet, and follow its instruction. Thats like the daily routine. Indeed this is exactly how I love being an embedded software engineer, because unlike being a web developer, I didnt really have to learn new Javascript front-end framework every 3 months. I can focus on solving real-world problems than abstract software compatibility issues, amd I get to feel that the all these experience accumulates into some sort of debugging capability in the future projects.

Why do CTOs love Embedded Rust

When I just hopped to a Swedish tech firm after quitting my first job in 3 months because of its stressful culture in 2019, I was confused about my new CTO’s decision of working on a new embedded project using Embedded Rust. I didnt really know about Rust back then. When I googled it, all it gave me was some terminologies like memory-safety, zero-cost abtraction, concurrency.

To be honest, these terminologies were very intimidating to me, since I never really had to care about these in my previous embedded projects. All I had been doing was to test the firmware with real-device. Without a clear idea of these jargons, and I tried directly writing some code in my Nordic NRF52832 for some Hello World or LED blink. For those who tried Rust before, you guessed it, it was terrible. It gave me some compilation error about ownership and mutability which I had no idea what is it all about.

However, I learnt afterwards that these compilation error messages are exactly the whole point of writing software in Rust. You let the compiler do some code review, and everyone follows the rule and write code in the single “proper manner”. Eventually the whole team follow its coding style. I would never recommend embedded rust to any beginner, it will only scare them off. But for embedded engineers, writing Rust will eventually equip yourself with a even higher level of “common language” than in C, the language of writing in a proper way. This means ensuring everyone in the team shares the awareness of low-level error and standardising coding style. This is expecially powerful when the software team is growing.

Pros/Cons of Embedded Rust from Engineer’s perspective

Pros #1: No pointer hassle with mutability

Pointers are the top 1 bug cause for C programming. It will haunt you geometrically when more people’s involved. Rust’s take on this issue is to not allow direct control of pointers. Instead it uses Reference and Mutable Reference. For details check here. Its might be difficult to understand at first, but the whole idea is to use mutable borrow when you make some changes to the object, and remeber to return to original place as you borrowed. More like a real-world analogy of borrowing a pen. This ensures that the code itself won’t have any pointer issues during runtime.

Pros #2: There’s only one proper way, everyone follows it

Because Rust compiler checks the mutability and doesnt allow quick hacky solutions, coders are left with writing code in a proper manner from the beginning. This is hard to elaborate, but the best example is that once I found a guy on GitHub who wrote the driver for same motion sensor I used, and his code resembled like 90% to my code.

Pros #3: Sweet library management with Crates, Cargo.toml

It’s 2021, unless you are in national defence authorities, you should code together with Github. We share codes, we use shared codes. In Rust we have crates, which is bascially a registry of libraries you can use in your projects. Instead of copy/pasting .c/.h into your project file, you just include it in Cargo.toml and you can just use the library. Think of it as Arduino libraries, but millions times better. You specify the versions, so when you load the projects in another computer, it should work right away with normal internet. My colleagues also got their public repo for some driver codes. Awesome-Embedded-Rust is the to-go place for checking latest juicy crates.

Pros #4: Awesome integration with VS Code (rust-analyser)

We all love VS Code. Lightweight, Nice extensions, works on all OSes (even RPi). Rust works perfect in VSCode. Other than linting and auto-formatting, my favourite feature is indexing, which you just Ctrl+Click the code, and you can check there the variable or struct type was defined. There is also one click check for trait implementation, which comes very handy when debugging and reviewing code. For C programming, there is PlatformIO which does sweet job, but PlatformIO always seems quite heavy for me.

Pros #5: Cleaner repo

Because of Rust modern compiler, you dont need the extra header files actually, just .rs files. In our team there is a CI/CD (like a little program that does code review) running on out repo that checks autoformatting on git push, and makes out repo clean as well. Everyone builds the habit of cargo fmt before git push. Cargo.toml lists the versioning of the used libraries. I am amazed how we can keep clean repo even with growing team.

To sum up the pros, using Rust lets compiler involve into code check and modern tools, so the team codes with better communication and less stress. Of couse, such benefits come at costs.

Cons #1: Learning time cost

Every Rust programmer can code in C, but not every C programmer can code in Rust. Unlike other languages, Rust’s core values lies in the compiler, which is going to throw lots of errors that you need to tackle with. These errors are technically not a con, since they are actual logical flaw that engineers should be aware of even with C. However, some projects are Proof of Concept not meant for productions. Fot the case when the project agileness is valued over reliability plus it is a one-off prototype, you should simply avoid Rust.

Cons #2: Electronic Engineers are frustrated

Rust is a coding language properly reinvented by software engineers to fit low level programming into modern trends. But in real scenario, product development team consists not only CS background, but also electronics engineer. Especially in a small startup environment where core-members get to involve a bit into eachother’s work, electronics engineers who design the PCB would wanna do slight coding as well. Most of them can actually code a bit of 30 year old C, but Rust can be too intimidting to these hardware engineers who just wanna blink a LED. For such case, at least a simple C code that controls basic peripherals has to be prepared.

Cons #3: Lack of reliable GDB debugger

As of 2021, we still havent figured out what is the best GDB tool for embedded Rust that works stably with VS Code. There is JLink CLI which can send commands to step into/over/out but its impractical. You have to be well prepared to lose some of the features you have been using in traditional embedded IDEs like CubeIDE/IAR/Keil/SES.

Cons #4: No FreeRTOS

I love FreeRTOS, its simple, and you get to add hardware features modularly without affecting eachother. There are FreeRTOS C bindings to Rust, but that loses the point of using Rust since the code safety is not ensured anymore. I am a big fan of embassy.rs (Embedded Async framework) due to its simplicity, but it is still in the unstable nightly version of Rust which might not be the best idea to put in commercial product. Its async functions got restrictions on mutable resources which makes it less agile than RTOS. All you left is RTIC (Real Time Interrupt Concurrency) which is to me make the code pretty hard to read actually. Also apparently I have to put all the tasks in a single rs file. I personally think the RTIC isn’t mature enough for scalability as well. We have a in-house task scheduler written based on RTIC but simpler, so get prepared to build some wheels.

To sum the cons, small team with electronics background who just wanna test simple features should keep a copy of C test code. Rust makes sense only when building long-term, sustainable applications, and might as well be prepared for some frustration of lack of traditional embedded software tools.

3 Tips for firmware development with Rust

Tip #1: Don’t place unstable HW with unstable SW

If you are in a product development firm, always start with simple low level C code for hardware testing. Take Rust as a language meant for developing high level, sustainable application code with complex logic, and not for low level hardware prototyping. It is okay if you build a functional PCBA testing firmware in Rust after C code, but the procedure of having a C code at the beginning will just save you lots of troubles.

Tip #2: Take time to look for new crates

The best thing about Rust is that its new language software engineers love it. GitHub is full of new rust tools and crates like every month. By the time you are reading this article, the issues I mentioned above might already have been solved:)

Tip #3: Keep a scientific mindset

This is my tip as a software developer in general, especially in Rust. 70% of the time is spent testing and debugging in embedded projects, and for sure Rust is a new language that adds up risks compared to the 30 year old C. We need to maintain a scientific mindset, or otherwise it is easy to get stuck being hopeless for a bug.

One useful technique I learnt recently is “First Principle Reasoning”, practiced by Elon Musk. It mean we better boil down fundamental truths and reason bottom up, than reasoning by analogy. For example, we had issues having the IoT connectivity devices consuming lots of power. Instead of keep running the field test and find the tendancy in different scenario, we have divided the low power analysis into 3 different parts:

Logical state machine transition between normal and low power mode

Modem enable hardware status

Power consumption at different states

By dividing into these three parts, we were able to find that the issue was led by the modemenable pin’s active-highness being flipped. This conclusion would have virtually been impossible to deduce with months of field testing. Your project manager might come to you with cosmic ray conspiracy, but you should remember to chill out and be scientific.

Conclusion

Rust is awesome language and can be adopted by growing team looking for modern way of embedded programming. It definitely has hindrances for teams with existing mature embedded tools to adopt especially for hardware engineers, but the long-term benefits does outweights.

Working with embedded rust has definitely been a rewarding experience, and I hope more people get involved into it even if it got some drawbacks like lack of embedded traditional tools. This is my first post on Medium, if you liked it, hit the like button. If you got some requests, feel free to PM me;)