Blog

Tech blog on web, security & embedded

It is no secret that we at Tweede golf love Embedded Rust, you can read about it in our other blog posts. But we thought it'd be fun to hear from the community too!

Last September, at the start of my internship at Tweede Golf, my tutors gave me a LoRa-E5 Dev Board. My task was to do something that would make it easier to write applications for this device in Rust. Here's what I did.

Over the past months, we have worked with Scailable to optimize their neural network evaluation. Scailable runs neural networks on edge devices, taking a neural network specification and turning it into executable machine code.

It's time for another technical blog post about async Rust on embedded. This time we're going to pitch Embassy/Rust against FreeRTOS/C on an STM32F446 microcontroller.

Let me introduce myself, I'm Dion Dokter, 24 years old (as of writing) and the newest member at Tweede golf (TG). I've always been into computers and started writing desktop software and games in 2013, embedded software in 2015, and started with Rust in 2019.

In our last post, we've seen that async can help reduce power consumption in embedded programs. The async machinery is much more fine-grained at switching to a different task than we reasonably could be. Embassy schedules the work intelligently, which means the work is completed faster and we race to sleep. Our application actually gets more readable because we programmers mostly don't need to worry about breaking up our functions into tasks and switching between them. Any await is a possible switching point. Now, we want to actually start using async in our programs. Sadly there are currently some limitations. In this post, we'll look at the current workarounds, the tradeoffs, and how the limitations might be partially resolved in the near future.

Previously we talked about conserving energy using async. This time we'll take a look at performing power consumption measurements. Our goal is first to get a feel for how much power is consumed, and then to measure the difference between a standard synchronous and an async implementation of the same application.

To more effectively write Embedded Rust applications, we want a clearer picture of two aspects: how can we ergonomically perform multiple tasks concurrently, and how can we exploit low-power modes to save energy. In the coming weeks, we want to write a small but non-trivial application that communicates with 2 sensors, uses async, and uses the low-power modes to conserve energy.

In embedded systems, energy efficiency is crucial for practical applications. Usually devices run on a battery, so the less energy you use, the longer the power supply will last. In this post we'll look at the basics of going to sleep and waking back up, and build a proof of concept using the nRF52840 development kit.

Welcome to the age of communication. It's 2021 and technology has come a long way. People, large machines and small devices communicate more intensively than ever before, and many technologies to enable them to do so have been developed. Some of those technologies use physical pathways like fibreglass to reach their receivers, others use radio signals to send messages. It's these wireless communication technologies that spark the imagination the most.

Concurrency isn't easy and implementing its primitives is even harder. I found myself in need of some no-std, no-alloc Rust async concurrency primitives and decided to write some. I kept the scope small so even you and I can understand it. Even so, it still involved futures, wakers, atomics, drop and unsafe. I'll introduce each of those to you while building a simple primitive. At the end, you will be able to implement your own primitives!

Recently, we worked on an embedded (STM32) project in Rust and we got some hands-on experience with the abstractions commonly used for that. There's embedded-hal, which offers abstractions related to timing, GPIO pins and common communication peripherals like SPI and USART. There's also multiple stm32xxx-hal crates which offer abstractions over most of the peripherals of different STM32 CPU families. Although many of them were nice to use, we found some parts to be lacking and we'd like to propose some potential improvements to embedded-hal and its implementing crates.

First-up is Henk Dieter, backend developer at Tweede golf. He has been interested in Rust for quite some time. Actually, it’s how Henk Dieter found out about Tweede golf, as it was one of the first companies in the Netherlands to adopt Rust as their weapon of choice.

Typically embedded devices are developed using C++. At Tweede golf we have chosen to use Rust instead for implementing our embedded devices. This is controversial as the embedded hardware field is generally quite conservative. Convincing our clients to adopt Rust for their products can be a challenge.

Rust is nice for a lot of things. At Tweede golf we've been using the language primarily for high-performance web applications. But that's not all Rust can do. Rust can be used to write embedded applications as well.

Embedded software has an issue that most software doesn't: It can be very hard to get it patched. Sometimes a device hangs 5 meters high on a street light in the middle of a highway in another country. Sometimes a device is attached to a customer's heart. Sometimes strict validation requirements make changes to the software very expensive. In each case it is important to build software that doesn't fail, even in unpredictable conditions.