August 31, 2026

by

Espen Albrektsen, Head of Software, Sonair

How we safety-certified the world's first Rust implementation – 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. Skip the marketing version. Here's what happened, in order, with the parts that were hard.

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 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.

ADAR One, our safety-certified product, is now rated SIL 2 (SafetyIntegrity Level 2) and PL d (Performance Level d), with a probability of dangerous failure (PFH) below 1.5×10⁻⁷ per hour. It was assessed as a human protection sensor against IEC61496, the standard for electrosensitive protection devices, and it also meetsIEC 61508 (functional safety for electronic safety systems) and ISO 13849(safety-related parts of control systems). exida, a notified body under the EUMachinery Directive 2006/42/EC, issued the EC type-examination certificate.

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

Why Rust, before safety was even the reason

We didn't choose Rust because of safety certification. When we started, certification was arguably a mark against Rust: libcore wasn't certified, and there was no certified compiler. We 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. You 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.

The physics problem

Sound moves at 343 meters per second, given the right circumstances, versus roughly 3×10⁸ m/s for light. Customers typically want detection ranges of several meters. Round trip at 5m is 29.4ms. Robots need to know about obstacles within 100ms, which gives us roughly 50ms to decide whether to stop. Subtract the 29.4ms time-of-flight and we had about 20.6 msleft for processing. Our signal processing algorithms are not simple.

Our approach was to not wait for the full recording window before starting to process. We start as soon as the first samples arrive viaDMA, which cut our effective start-of-processing time from ~30ms to ~3ms and left us a comfortable ~47ms for computation.

Finding compute, and losing the tooling that came with it

Our first hardware idea was a single STM32 dual-core M4+M7 with hardware math acceleration. That needed ~200ms to process, nowhere close. A triple-H7 system, digitizing in one step and analyzing in a parallel dual-core setup, still wasn't fast enough.

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.

TI doesn't support Rust. No peripheral access crate, no CMSIS-SVD files, and the reference manual runs 15,863 pages. TI does provide XML register descriptions, so we wrote tixml2svd to convert those to SVD, then ran svd2rust to generate a PAC, about 30MB of generated Rust for low-level register access. That got us unblocked, but "Rust support" for a chip is not evenly distributed. STM32 has a mature ecosystem (HAL, probe-rs, defmt). Sitara had none of that when we started.

Multicore without an OS

We looked at three options for an operating system. Linux wasn't certifiable. ThreadX would have meant certifying all the low-level assembly ourselves. Paying someone to port a certified OS was too expensive. We went bare metal and did the heavy lifting ourselves.

That meant writing our own scheduler for the quad-core A53. Our pipeline has three phases: data recording/pre-processing, analysis, and conclusion. The analysis phase is the compute-intensive one, so we split it across the three extra cores using divide-and-conquer.

The scheduler uses no locks or mutexes, only atomics. One core (core 0) orchestrates data acquisition and increments a "data ready" counter (write_idx). The other three cores sit in an active polling loop, incrementing a "data processed" counter (read_idx, done_count) as they finish chunks. The shared data structure looks roughly like this:

pub struct SharedChannelData<T: Copy + Default, const READ_SIZE: usize, const MAX_SIZE: usize> {
    lock: AtomicBool,
    read_idx: AtomicUsize,
    write_idx: AtomicUsize,
    done_count: AtomicUsize,
    active_size: AtomicUsize,
    data: *mut T,
}

The read side uses fetch_update with explicit Ordering::Release/Ordering::Acquire to claim a slice of work, process it, and mark it done. No blocking, no priority inversion, deterministic worst-case timing, which matters here because there's currently no accepted path to safety-certify anything AI-driven, so the behavior must be deterministic by construction.

The certification stack itself

Ferrocene, Ferrous Systems' certified Rust toolchain, is the compiler we build with. Ferrocene 25.11.00 has already been assessed by TÜV SÜD for IEC 61508 (SIL2), which answers half the "tool suitability" question every functional safety standard asks about your toolchain.

The other half is libcore. You can't write meaningful Rust without integers, arithmetic, and arrays, and libcore wasn't certified when we started. We've worked iteratively with Ferrous Systems to identify exactly which functionality we need 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.

For the math-heavy parts, FFT and signal processing, we initially planned to lean on ARM's CMSIS-DSP via FFI, but we didn't want an FFI boundary in our safety functions. We found rustfft, which was faster than CMSIS-DSP for our use case. That's not a universal result, it's specific to our data shapes and target, but it meant we didn't need FFI at all for that piece.

Third-party crates are headaches in safety-certified systems. Certification requires the crate to be developed to the same process rigor as our own code: requirements, design, architecture, and test coverage. We limit third-party dependencies in our safety-relevant code paths as much as we can. We modified our dependencies to make them certifiable. Ideally, we would like to contribute our work upstream, but this is an unsolved challenge.[EA1.1] If more of us do this, the ecosystem gets easier for the next team.

Compute platform partitioning, concretely

Because our chip isn't itself safety-certified as a whole, we split responsibilities across cores by trust level. Safety functions run on the four A53 cores, 100% Rust. The integrity function runs on the isolated M4, also 100% Rust. Everything non-safe runs on the R5: FreeRTOS, C, based on TI's sample code.

Each domain has its own memory management/protection hardware, plus a device firewall, since you can't trust the non-safe R5 core to configure its own MPU correctly. Freedom from interference is enforced by hardware there, not by convention.

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, know what you're signing up for. Your compiler needs to be certified (Ferrocene solves this now; it didn't exist when we started). Your libcore usage needs to fall inside a certified subset. 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.