Been using this to build a LoRa relay for the Bitchat app running on nrf52, it's actually very smooth for the most part. The only panics I seem to get are from the Nordic's SoftDevice, not for the ebasssy-rust code itself.
This is at the center of a friction point in embedded rust: most of the OSS ecosystem has shifted to this framework, and as a result, is incompatible with, or is high friction if you don't want to make your firmware and control flow Async. This is notable because Rust embedded is nascent and small, so I think splitting the ecosystem along with Async is not ideal. It's also confused some people new to embedded: I regularly hear this dichotomy: "Async vs blocking"; the assumption being if you are not using Embassy, your code blocks the CPU when waiting for I/O, etc.
If you enjoy Async PC rust programming, I think this will be a good starting point. I like how it has unified hardware access to different MCUs, and its hardware support for STM32, for example, is a step up from the initial generation of Trait-based HALs. I seem to be the odd one out as an embedded rust programmer (Personally and professionally) for whom Async is not my cup of tea.
As others have mentioned, ~all of the embassy HALs support nearly 1:1 parity of blocking interfaces for drivers next to the async ones. You really can avoid async entirely while still using embassy hals. The ecosystem is not tightly integrated/locked in.
Even data structure libraries, like embassy-sync, all have `try_` methods, which would allow for polling usage outside of async.
There's no mandate to use async - and helping folks that DO see value in it (which is a LOT of folks), isn't "splitting the ecosystem" - it's people doing things the way they like to do it. Embassy still works very hard to support folks who DON'T want to use async, to avoid duplicated work. There's nothing stopping you from preferring to write and maintain your own HALs, I know you have been for a while! But it's not something that people necessarily have to do, even if they aren't interested or don't prefer async!
It has literally split the ecosystem I’m not sure why people think it hasn’t. There’s basically embassy then everything else. Embassy has been quite successful in large part because its primary author took the time to make it good.
If you look at espressif and how they support rust they have to offer both blocking and non blocking options, they also offer using rust on their freertos and C library setup. It’s quite an undertaking to do all of this.
I had been using this to try to build a Spark modeling guitar amp pedal controller, controlling the amp via BLE. It seemed pretty promising, and they have their own fully OSS Rust BLE stack. It seemed a little early days with that though, it seemed like the APIs were changing quite a bit and it required pinning git revisions in Cargo. I'm excited to see where the project goes!
I am a big fan of the embassy project and it’s a great example of why async Rust is so great: Because this is possible. It works without a heap, is a really low cost abstraction and you can do stuff concurrently on a single core chip (where you can’t just spawn a new “thread”) and you don’t have the complexity of an RTOS. I believe there is a great future for embassy ahead and it’s so great how far the team has come.
Rust embedded was really never actually better then C or C++ but embassy for me is a big reason why I now make my buying decision based on how well I can use Rust on the MCU.
99% people in this thread have no idea what you mean. And that’s the reason projects like these make it to frontpage every other day and have hundreds of upvotes/comments.
You can get preemptive scheduling of async tasks with InterruptExecutor. You create one executor for each priority level, then spawn the tasks in the right one. The latency of the executor and the compiler-generated async state machines is predictable, so you can use Embassy for hard real-time work. See example: https://github.com/embassy-rs/embassy/blob/main/examples/nrf...
Additionally the executor has support for scheduling tasks by priority or deadline within a single priority level. (in latest git, will be in next crates.io release)
This channel contains videos of journey from setting up environment and busy wait embedded LED blinking, to basically re-inventing and then using Embassy. 4 oldest videos.
Probably off topic, but what's the best way to get started with embedded development? I've been a web developer for over a decade, but I'd really love to try something much lower level, and I'm currently making my way through the Rust book. I've got a Raspberry Pi on the way, but I assume that's not truly embedded development.
I would recommend getting a ST nucleo board over raspberry PICO or ESP32. The nucleo boards have integrated SWD programmer which makes flashing easier. You can also use it to debug your code. Try to get one with onboard USB port (like https://www.st.com/en/evaluation-tools/nucleo-f767zi.html) so that you can build USB projects.
I never learned any C based languages, so it's been a challenge, but I've enjoyed learning the basics of bare-metal no_std rust on the esp32c3, with esp-rs and its support for embassy to help me get started!
Coming from a lot of bare metal C and FreeRTOS it finally feels like embedded is getting a toolchain that is actually modern and better.
Some of that isn't just Embassy but the surrounding ecosystem, some highlights:
* probe-rs w/cargo run integration
* defmt logging (combined with probe-rs and rtt it's very nice)
* embedded_hal (and in my case stm32-rs)
I have also tried RTIC but I decided to keep going with Embassy because I like the async ergonomics more and the few times it's been a downside/missing functionality (no existing async driver for specific peripherals basically) it wasn't to hard to implement what I needed.
I was surprised it just works out of the box on OS X also, generally speaking I would always end up having to use Linux to develop for embedded. Being able to compile on fast Apple M hardware and then run immediately with zero friction is awesome.
It took a little bit to get my head around how to share access to peripherals etc but once I did it's been great and it's nice to know that locking semantics are essentially enforced at compile time so it's actually not possible to have 2 things stomping over the same bus etc which can sometimes be a very hard bug to track down when working with big and fast SOCs.
Other really big aspect Embassy has been good for is really high quality USB and networking stacks. I am using both the USB stack (for PLDM over USB) and Ethernet w/the TCP stack in embassy_net and both have been flawless.
Only real downsides I can think of are it can sometimes be hard to onboard folk that are used to copy/paste from vendor examples and sometimes communicating and debugging with vendors themselves when they aren't familar and won't engage unless you can reproduce on the vendor HAL.
So overall really happy with it and I highly recommend trying it out especially if you are in the STM ecosphere.
>it finally feels like embedded is getting a toolchain that is actually modern and better
Last time i tried embassy, it pulled over 100 dependencies just to build a blinky. Its great for hobbyist programming but i doubt its going to be used in any industrial application any time soon.
A lot of those dependencies are from the same project, though. It's just split into multiple crate so you don't need to pull in one mega-lump of code for everything.
(Also, I am currently using it for an industrial application)
I haven't had a chance to do embedded work but people damn near fall to their knees and weep when talking about how nice the experience is using embassy. Which makes me want to give it a try.
I’ve been enjoying Embassy most at the application pattern layer: long-lived device tasks that hide timing and coordination behind a small, typed async API. For example:
loop {
let btn = ir.wait_for_press().await;
// use btn
}
Meanwhile the compiler builds the state machine for you.
I think this style is an emergent property of async + no-std that hasn’t really been collected or named yet. A lot of discussion focuses on HALs, bring-up, or executors, but less on how people structure applications once those pieces are in place.
I'm rewriting glicol (https://glicol.org/) with no std, and embassy-rs + 2350 is my go-to choice. Highly recommand this stack if you're planning to start working with embedded systems in 2026.
36 comments
[ 2.8 ms ] story [ 72.6 ms ] threadIf you enjoy Async PC rust programming, I think this will be a good starting point. I like how it has unified hardware access to different MCUs, and its hardware support for STM32, for example, is a step up from the initial generation of Trait-based HALs. I seem to be the odd one out as an embedded rust programmer (Personally and professionally) for whom Async is not my cup of tea.
Even data structure libraries, like embassy-sync, all have `try_` methods, which would allow for polling usage outside of async.
There's no mandate to use async - and helping folks that DO see value in it (which is a LOT of folks), isn't "splitting the ecosystem" - it's people doing things the way they like to do it. Embassy still works very hard to support folks who DON'T want to use async, to avoid duplicated work. There's nothing stopping you from preferring to write and maintain your own HALs, I know you have been for a while! But it's not something that people necessarily have to do, even if they aren't interested or don't prefer async!
If you look at espressif and how they support rust they have to offer both blocking and non blocking options, they also offer using rust on their freertos and C library setup. It’s quite an undertaking to do all of this.
I also want to give a shoutout to reqwless (https://github.com/drogue-iot/reqwless) which is a HTTP client for embassy-net that even supports HTTPS!
Rust embedded was really never actually better then C or C++ but embassy for me is a big reason why I now make my buying decision based on how well I can use Rust on the MCU.
never understood what a watchdog is tho...
"The hardware accelerated Rust RTOS" -- it can use your interrupt controller as a scheduler.
Isnt' that how schedulers always work?
Uh, what does async have to do with hard real-time guarantees?
You can get preemptive scheduling of async tasks with InterruptExecutor. You create one executor for each priority level, then spawn the tasks in the right one. The latency of the executor and the compiler-generated async state machines is predictable, so you can use Embassy for hard real-time work. See example: https://github.com/embassy-rs/embassy/blob/main/examples/nrf...
Additionally the executor has support for scheduling tasks by priority or deadline within a single priority level. (in latest git, will be in next crates.io release)
https://www.youtube.com/@therustybits/videos
My learning project -- using mqtt for HomeAssistant integration: <https://github.com/n8henrie/esp32c3-rust-mqtt>
Coming from a lot of bare metal C and FreeRTOS it finally feels like embedded is getting a toolchain that is actually modern and better.
Some of that isn't just Embassy but the surrounding ecosystem, some highlights:
* probe-rs w/cargo run integration
* defmt logging (combined with probe-rs and rtt it's very nice)
* embedded_hal (and in my case stm32-rs)
I have also tried RTIC but I decided to keep going with Embassy because I like the async ergonomics more and the few times it's been a downside/missing functionality (no existing async driver for specific peripherals basically) it wasn't to hard to implement what I needed.
I was surprised it just works out of the box on OS X also, generally speaking I would always end up having to use Linux to develop for embedded. Being able to compile on fast Apple M hardware and then run immediately with zero friction is awesome.
It took a little bit to get my head around how to share access to peripherals etc but once I did it's been great and it's nice to know that locking semantics are essentially enforced at compile time so it's actually not possible to have 2 things stomping over the same bus etc which can sometimes be a very hard bug to track down when working with big and fast SOCs.
Other really big aspect Embassy has been good for is really high quality USB and networking stacks. I am using both the USB stack (for PLDM over USB) and Ethernet w/the TCP stack in embassy_net and both have been flawless.
Only real downsides I can think of are it can sometimes be hard to onboard folk that are used to copy/paste from vendor examples and sometimes communicating and debugging with vendors themselves when they aren't familar and won't engage unless you can reproduce on the vendor HAL.
So overall really happy with it and I highly recommend trying it out especially if you are in the STM ecosphere.
Last time i tried embassy, it pulled over 100 dependencies just to build a blinky. Its great for hobbyist programming but i doubt its going to be used in any industrial application any time soon.
(Also, I am currently using it for an industrial application)
UPDATE: it seems so, using a second executor. There is "embassy_sync" to communicate.
Not that I mind correctness, but I want to play with this and maybe do some minor hobby projects with limited cognitive load.
Otherwise I'd just do FreeRTOS, which is also a good option.
But what's the overhead price with Embassy?
Sadly, I bought an nRF54L15 board to start my embedded journey, which isn't 100% supported yet :/
Now I have to wait. I'm not gonna go back to C :D
C RTOSes are conceptually nice, but such as pain to use in the real world, a lean framework like embassy is the natural evolution.
The best thing is that embassy can actually be considered as a real-time "OS" (you can read more here: https://kerkour.com/introduction-to-embedded-development-wit...).
loop { let btn = ir.wait_for_press().await; // use btn }
Meanwhile the compiler builds the state machine for you.
I think this style is an emergent property of async + no-std that hasn’t really been collected or named yet. A lot of discussion focuses on HALs, bring-up, or executors, but less on how people structure applications once those pieces are in place.
Brad Gibson and I talked about some of these ideas in this (free) article on how Embassy shines on embedded devices: https://medium.com/@carlmkadie/how-rust-embassy-shine-on-emb...
I’ve also started an open repo to experiment with and document these patterns: https://github.com/carlkcarlk/device-kit
Would love links to other repos that use Embassy at this higher, application-oriented level.