September 1, 2026

by

Espen Albrektsen, Head of Software, Sonair

How we developed the world's first safety-certified product written in Rust – and why we went bare metal

We just certified it. ADAR One is the first safety-certified embedded system built in Rust. I want to share how we got here, for other Rust developers who are looking at safety-critical work and wondering if the language is ready for it.

Why did that choice matter?

Skip the marketing version. Here's what happened, in order, with the parts that were hard.

What we're building

Sonair makes ADAR, acoustic detection and ranging. It's a safety-certified 3D ultrasonic sensor for robots and machine safety applications. It sends an omnidirectional ultrasound pulse, records the reflection on multiple transducers, and turns that into a 3D point cloud. If anything shows up inside a defined protective zone, the sensor tells the robot or machinery to slow down or stop.

We started with a team of experienced C/C++ embedded developers. Nobody on the team had shipped anything serious in Rust before we started. We picked it anyway.

Why Rust, before safety was even the reason

We didn't choose Rust for its safety certification. When we started, certification was a mark against Rust. Although we knew Ferrous Systems was working on it, the compiler had not been certified yet, and we would be the first company to go through the certification process using Ferrocene. Being first is not always a good thing, so we had to take a leap of faith and gamble that we would land on our feet. And we did.

But we really love Rust and chose it because of the pain points we knew from C/C++: manual memory management, weak type systems, and compile-time guarantees you don't get for free. In Rust you can get a compile error if you try to use an input pin as an output.

The ecosystem sold us the rest of the way: crates, peripheral access crates generated from SVD files, hardware abstraction layers for common chips, cargo as a package manager. It gave us roughly a two-year head start compared to hand-rolling the equivalent in C, even after waving goodbye to a lot of it, due to the certification requirements and our compute platform.

Finding compute, and losing the tooling that came with it

Our signal processing algorithms are not simple, and they need to run fast enough that a robot or dangerous machinery is able to stop in time. Our first hardware idea was a single STM32 dual-core M4+M7 with hardware math acceleration. That was nowhere close to being fast enough. A triple-H7 system, digitizing in one step and analyzing in a parallel dual-core setup, still did not cut it.

We ended up on a Texas Instruments Sitara (AM62x): quad-core Cortex-A53, plus an isolated M4 MCU and an R5 core, designed with functional safety partitioning in mind. Safety functions are 100% Rust and run on the four A53 cores. The integrity function runs on the isolated M4, also 100% Rust. Everything non-safe (including Ethernet) runs on the R5, which runs FreeRTOS and is all C. We wanted to run this in Rust as well, but we simply did not have time to port everything we needed.

This gave us the computing power we needed at an acceptable price, but Rust support for TI devices was close to non-existent. No peripheral access crate (PAC), no CMSIS-SVD files, and the reference manual runs 15,863 pages. When we started, there weren’t even any cortex-a/aarch64-cpu crates, so we had to piece together the assembly required just to get it to boot. Luckily, TI does provide XML register descriptions, so we ran tixml2svd to convert those to SVD, then svd2rust to generate a PAC. The PAC ended up at about 30MB of generated Rust for low-level register access. The chip was also not supported by probe-rs, so we had to fall back to openocd and write some custom tooling for things like rtt logging which previously just worked out of the box.

The point is that "Rust support" in the embedded world is not evenly distributed. STM32 has a mature ecosystem (HAL, probe-rs, defmt), while Sitara had none of that when we started. Rust support for your platform is an important consideration when choosing to use Rust for your project.

Multicore without an OS

We looked at several options for an operating system. Among Rust alternatives, OxidOS was the most promising. They are targeting safety-critical automotive ECUs, but were not close enough to certification, so the timing did not align. We also considered mainstream operating systems, but Linux wasn't certifiable, ThreadX would have meant certifying all the low-level assembly ourselves, and paying someone to port a certified OS to our platform was too expensive.

We also briefly considered async alternatives and RTIC, but we were worried that the extra certification risk was not worth it. Since our scheduling needs were minimal and we could use FreeRTOS for non-safety tasks like Ethernet communication on a separate processor, we went bare metal and did the heavy lifting ourselves.

The certification stack itself

Ferrocene, the quality-managed, safety-qualified Rust toolchain, is the compiler we build with. Ferrocene 25.11.0 has already been assessed by TÜV SÜD, fitting our target level IEC 61508 (SIL2), which answers half the "tool suitability" question every functional safety standard asks about your toolchain.

The other half is libcore. Without libcore, even fundamental operations like standard integer arithmetic become hard, and libcore wasn't certified when we started. Certifying all of libcore is a big undertaking, so getting everything certified in time was not possible. We worked iteratively with Ferrous Systems, the original developer and lead provider of Ferrocene, to identify exactly which functionality we needed and to test beta releases against our firmware. The certification model is feature-flagged: only certified functions are exposed. If a function in libcore isn't certified, it doesn't exist in the crate you're compiling against, and your build fails. The Rust documentation functions as the spec for what "correct" means.

Even though the certified subset of libcore contained enough functionality to compile our crates at the time of release, there were still some parts missing requiring various workarounds, most notably core::fmt which handles string formatting. That might not sound so bad until you realize that any usage of #[derive(Debug)] must be feature-gated out in all your code, and in any external crate you use (and its dependencies). Not being able to use the log crate at all is also quite painful, so we ended up writing a small replacement that allowed use of error! and friends with some basic formatting. We are happy to see that certified core::fmt now has made it into the latest Ferrocene release 26.05.0.

Third party crates

Third-party crates are headaches in safety-certified systems. Certification requires the crate (and all its dependencies) to be developed to the same process rigor as our own code: requirements, design, architecture, review and test coverage.

We still ended up using a few third-party crates, mostly low-level crates like cortex-m, because it was still faster than rolling our own. Typically, we first stripped away any code we did not need (to reduce the documentation effort), modified it so that it compiled with certified libcore (remember those #[derive(Debug)]), added missing unit tests where required and of course documented everything required by our process. Then repeat for all the sub-dependencies of the crate. In the end, quite a bit of work, but not as bad as we might have feared and entirely doable. Ideally, we would like to contribute our work upstream, but we need to figure out how best to do this in collaboration with the Rust community. If all of us do this, the ecosystem gets easier for the next team.

Where we are

ADAR One is in series production and shipping on deployed industrial robots. Since we introduced the beta version, more than 90 global robotics companies have evaluated it through our test program. beRobox, a palletizing and de-palletizing automation company, has agreed to deploy the certified sensor in future solutions. Ferrocene is qualified for all three of our targets: A53, M7, and M4.

What's certified is ADAR One as a complete system, assessed and type-approved by exida against IEC 61496, IEC 61508, and ISO 13849. Rust is the language the safety functions are written in, compiled with Ferrocene, and that combination is what's now independently verified.

What I'd tell another team considering this

Rust doesn't need safety certification to be worth using in embedded systems. We chose it for the type system and the tooling, years before certification was a factor. But if you do need certification, we believe Rust is a fully viable option. Ferrocene is now available and the certified subset of libcore should certify most needs. You have to check if your target is supported by Ferrocene. New targets are added with each release, but if yours isn't on the list yet, reach out to Ferrous Systems directly. Of course, certified Rust is still in its infancy, so expect some surprises and bumps in the road, and every third-party crate you touch needs to be lifted to your process standard or reimplemented. That last part is real work.

We'd rather more of the ecosystem got there with us than have this stay a one-company effort. If you're doing anything adjacent, safety-certified Rust, embedded Rust on chips without vendor tooling, non-blocking multicore scheduling in no_std, reach out: hello@sonair.com.

*********

I'll be on stage talking about Rust at the following conferences:
Oxidize (Berlin, Germany), 14-16 September, 2026. Link
NDC TechTown (Kongsberg, Norway), 21-24 September, 2026. Link