Electronics > Microcontrollers

Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.)

(1/76) > >>

Hi, the company I currently work for exclusively uses Rust for our product's embedded development, and I have been learning Rust and specifically embedded Rust lately. I thought I'd kickstart a thread discussing using embedded Rust, including learnings, successes and failures. I am still no expert in Rust, but I have gone through the "fighting the compiler" stage and am starting to see how Rust can be valuable in production. In fact, for a long time, I have been a Rust holdout and swore by C, but now I am starting to be a Rust convert.

My company (M-Labs HK) happens to open source everything we develop, so I thought I'd share a few examples of usage of Rust in "real world" shipping, money making products.

https://git.m-labs.hk/M-Labs/thermostat - Baremetal Rust on STM32F4, dual channel TEC controller capable of better than 1 milliKelvin control stability. Not quite stable release yet, but we have shipped systems to early beta participating customers.

https://git.m-labs.hk/M-Labs/kirdy - Baremetal Rust on STM32F4, precision laser driver with TEC controller and photodiode monitor. Under (my) development, very early stage, hardware not finalised.

https://github.com/m-labs/artiq - Baremetal Rust on softcore, Migen for FPGA fabric and softcore. Quantum physics control system. Very mature and production ready.

https://git.m-labs.hk/M-Labs/artiq-zynq - Baremetal Rust on Zynq 7000, Migen for FPGA fabric. Quantum physics control system. Reasonably mature and production ready.

This is by no means advertisement, but rather to demonstrate that "new-fangled" tools like Rust and Migen CAN be used in "real" products. I'd love to see more discussions and examples of Rust being used in products and projects! Show us your Rusty projects and discuss anything embedded Rust related!

Interested to get your thoughts on this.

Can you list the top five advantages of Rust over C, in an embedded environment like baremetal Cortex-M, as you see it?

Just off my head, somethings I like about embedded rust

1. Memory (and by extension memory mapped peripheral) safety. In baremetal C on systems without memory protection unit, there's nothing preventing you from dropping a HAL_GPIO_WritePin(port, pin) anywhere in your code, or changing a peripheral setting register anywhere in the code. There's no warning from the compiler nor any checks against this. This means if you have multiple processes (esp. when developed by multiple developers), you can't trust that the state of the memory (and memory mapped peripheral) is in the state you left it in, someone / some process could have changed it under the rug.

In Rust, unless you specifically wrap your code in an unsafe block, the compiler simply does not allow you to do that. Every bit of memory (and by extension memory mapped peripheral) has an owner, and only the owner of that bit of memory has write access to that bit of memory. Take for example a gpio pin, in Rust, the init code would take ownership of all the peripherals, break up the peripherals into individual objects (some SPI busses, some GPIO pins, some I2C busses etc), and pass the ownership these objects to various processes that now owns that bit of peripheral and has write access to it. The implication is your process can always trust that it has exclusive ownership of its memory objects, and can have confidence no other processes has altered its state. This is all done in COMPILE TIME, so there's no runtime overhead for having memory safety, even without a MPU.

This alone is very significant imo.

2. Modern tooling. In Rust there's Cargo, a build system + package manager that makes code building and reusing much nicer than C. If I want to add a library to my code, I just have to specify the name and version of the library I wish to use, and Cargo will integrate the library into my code properly and take care of all the dependencies and dependencies of dependencies. This is way better than C. Cross compiling is also a breeze, as Rustc uses LLVM, cross compiling means I just have to specify the architecture of the target and stuff just works. I don't need to maintain a version of GCC for linux, another version for windows, then arm-none-eabi-gcc for my cortex M stuff.

3. I don't usually allocate heap when programming cortex M, but when I do, it is so much safer in Rust. The compiler makes sure there's no memory leaks, no double freeing, no dangling pointers etc. all at compile time with minimal runtime overhead. This also means no garbage collector is needed.

4. Very strong, static, type system. Say you have a library function that implements sleep/delay. In Rust, properly written libraries will take a parameter of type time, instead of say a u32. In C, the programmer has to be cognizant of the physical meaning and unit of the number you pass to the sleep function. e.g. In stm32cube, HAL_Delay(x) takes a u32 and sleeps for x milliseconds. The programmer takes responsibility of making sure the number specified means milliseconds, not seconds, not microseconds, not ticks, not processor cycles. In Rust, the sleep function would take a generic parameter of time, and time can be a variable of type ms, or type us, or type second, or type ticks, and the sleep function would sleep according to the numeric value and type of the variable. So in Rust, your sleep function would look something like sleep(10_u32.millis()), or sleep(10000_u32.micros()), explicitly stating both the value and type, i.e.unit of the value. The compiler takes care of the part that translates the generic time type to the native type the sleep functions uses to count elapsed time, so no overhead again.

5. General attitude and mindset. In Rust, the programmer is not to be trusted, and the compiler does what it can to force you not to write certain types of bugs (e.g. memory leaks, out of bound array indexing), unless you explicitly wrap your code with unsafe. In C, the programmer is assumed to know its sh*t and trusted to do whatever he/she wishes to do. This different attitude takes some getting used to, and rubs some people the wrong way. Many of us would like to think we are super smart and never writes bugs, but coding in Rust means you have to admit that you do write stupid and buggy code sometimes, and for certain types of coding errors, the compiler is capable of knowing better than you on what's buggy and what's not. This is particularly valuable in two situations imo,
- You work solo with no one to review your code
- You oversee a group of programmers with different levels of aptitude.
In these situations, your code review process is much simpler and the resulting code is much less error prone, because
- Illegal memory (and by extension memory mapped peripheral) access is prohibited by the compiler (point 1, 3)
e.g. https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/
- Strong type system reduces the chances of passing the wrong type of data to the wrong function (point 4)
e.g. https://en.wikipedia.org/wiki/Mars_Climate_Orbiter
- You can focus your review effort to the handful of lines of code marked unsafe, instead of scrutinising every single line of code.

This is longer than I thought it would be, but I think it is good food for thought. I welcome counter arguments, but please don't turn this into a holy war between different languages.

If you separate the bare metal, peripheral control, program level, and user level into different project files, with minimal connections, then 99.99% of the problems of the entire project will be solved.
But the vast majority writes in the Arduino style, and this is not treated in any way. Even changing the programming language will not help.


--- Quote from: AVI-crak on November 07, 2022, 02:52:09 pm ---If you separate the bare metal, peripheral control, program level, and user level into different project files, with minimal connections, then 99.99% of the problems of the entire project will be solved.
But the vast majority writes in the Arduino style, and this is not treated in any way. Even changing the programming language will not help.

--- End quote ---

Sure, maybe you really know better than most people, and maybe 99.99% or you code is actually bug free, maybe. And maybe you are right that most people in the industry write crappy code. But what about your "arduino programming" colleagues? Wouldn't you want some kind of tooling (can be rust, can be something else) to force them to write better code?


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod