Introdução
O desenvolvimento de sistemas embarcados sempre foi dominado por C e, em menor grau, por C++. Mas em 2026, Rust consolidou-se como uma alternativa real e competitiva para programação de microcontroladores — e o framework Embassy é o grande protagonista dessa transformação. Com suporte a programação assíncrona (async/await) diretamente em ambientes no_std, o Embassy trouxe uma ergonomia inédita ao mundo embedded sem sacrificar performance.
Se você acompanhou as novidades do ecossistema Rust em 2026, já sabe que a linguagem tem avançado em múltiplas frentes. Neste artigo, vamos mergulhar no universo dos sistemas embarcados com Rust, explorando o Embassy desde a configuração inicial até exemplos práticos com STM32, ESP32 e nRF.
Por que Rust para Embarcados?
Antes de falar do Embassy, vale entender por que Rust é uma escolha cada vez mais popular para sistemas embarcados:
- Segurança de memória em tempo de compilação: o borrow checker elimina buffer overflows, use-after-free e data races — bugs que em C só aparecem em produção
- Zero-cost abstractions: traits, generics e iteradores compilam para código tão eficiente quanto C manual
- Ecossistema
no_stdmaduro: crates comoembedded-hal,defmteprobe-rsformam um toolchain robusto - Sem garbage collector: controle total sobre alocação de memória, ideal para microcontroladores com poucos KB de RAM
Rust vs C para Embarcados: Comparativo
| Aspecto | Rust com Embassy | C Tradicional |
|---|---|---|
| Segurança de memória | Garantida em compilação | Responsabilidade do dev |
| Programação assíncrona | Nativa com async/await | Callbacks ou RTOS |
| Abstrações de hardware | HAL traits padronizados | HAL vendor-specific |
| Debugging | probe-rs + defmt | OpenOCD + printf |
| Footprint binário | Comparável ao C | Referência |
| Curva de aprendizado | Moderada a alta | Moderada |
| Concorrência | Segura por design | Propensa a data races |
Se você já trabalha com C em embarcados e quer comparar com outra alternativa moderna, Zig para embarcados também oferece uma abordagem interessante com foco em simplicidade e interoperabilidade com C.
Embassy: O Framework Async para Embarcados
O Embassy é um framework de programação assíncrona para microcontroladores que funciona sem alocador de heap e sem runtime de sistema operacional. Ele implementa um executor de tarefas cooperativo que roda diretamente no bare metal, usando as interrupções do hardware para acordar futures.
Características Principais
- Executor async cooperativo otimizado para microcontroladores
- HALs prontos para famílias STM32, nRF52/nRF53/nRF91 e ESP32
- embassy-net: stack TCP/IP assíncrona completa
- embassy-usb: driver USB device assíncrono
- embassy-time: timers e delays baseados em hardware
- Sem heap: todas as tarefas são alocadas estaticamente
Configurando o Ambiente
Para começar com o Embassy, você precisa de probe-rs para flash e debugging:
# Instalar probe-rs
cargo install probe-rs-tools
# Criar projeto Embassy para STM32F4
cargo init --name meu-projeto-embassy
O Cargo.toml típico de um projeto Embassy para STM32:
[dependencies]
embassy-executor = { version = "0.7", features = ["arch-cortex-m"] }
embassy-time = { version = "0.4", features = ["tick-hz-32_768"] }
embassy-stm32 = { version = "0.3", features = ["stm32f411ce", "time-driver-any"] }
cortex-m = "0.7"
cortex-m-rt = "0.7"
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
Exemplos Práticos
LED Blink Assíncrono
O clássico “Hello World” dos embarcados, agora com async/await:
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::Timer;
use defmt::info;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let mut led = Output::new(p.PC13, Level::High, Speed::Low);
info!("LED blink iniciado!");
loop {
led.set_high();
Timer::after_millis(500).await;
led.set_low();
Timer::after_millis(500).await;
}
}
Note como o Timer::after_millis(500).await é elegante comparado a um HAL_Delay(500) em C — e o melhor: durante o await, o processador pode entrar em modo de baixo consumo automaticamente.
Comunicação UART Assíncrona
Enviar e receber dados via UART de forma assíncrona:
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::usart::{Config, Uart};
use embassy_stm32::bind_interrupts;
use defmt::info;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USART2 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART2>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let config = Config::default();
let mut usart = Uart::new(
p.USART2, p.PA3, p.PA2,
Irqs, p.DMA1_CH6, p.DMA1_CH5, config,
).unwrap();
let msg = b"Ola do Embassy!\r\n";
usart.write(msg).await.unwrap();
info!("Mensagem enviada via UART");
let mut buf = [0u8; 64];
loop {
match usart.read_until_idle(&mut buf).await {
Ok(n) => info!("Recebido {} bytes", n),
Err(e) => info!("Erro UART: {:?}", e),
}
}
}
Múltiplas Tarefas Concorrentes
A verdadeira força do Embassy está na concorrência. Veja como rodar múltiplas tarefas simultaneamente sem RTOS:
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::Timer;
use defmt::info;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task]
async fn tarefa_sensor() {
loop {
// Simula leitura de sensor
info!("Lendo sensor de temperatura...");
Timer::after_secs(2).await;
}
}
#[embassy_executor::task]
async fn tarefa_heartbeat(mut led: Output<'static>) {
loop {
led.toggle();
Timer::after_millis(1000).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let led = Output::new(p.PC13, Level::High, Speed::Low);
spawner.spawn(tarefa_sensor()).unwrap();
spawner.spawn(tarefa_heartbeat(led)).unwrap();
info!("Sistema iniciado com 2 tarefas concorrentes");
// A main task pode fazer outras coisas
loop {
Timer::after_secs(60).await;
info!("Sistema rodando normalmente");
}
}
Cada tarefa roda de forma cooperativa — quando uma está esperando um timer ou I/O, as outras podem executar. Tudo sem threads do sistema operacional, sem mutex, sem data races.
Debugging com probe-rs e defmt
O ecossistema de debugging para Rust embarcado evoluiu significativamente. O defmt (deferred formatting) é um framework de logging otimizado para microcontroladores que faz a formatação no host, não no dispositivo:
# Flash e monitoramento em tempo real
cargo run --release
# Ou com probe-rs diretamente
probe-rs run --chip STM32F411CE target/thumbv7em-none-eabihf/release/meu-projeto
O defmt reduz o uso de flash e RAM drasticamente comparado a printf em C, porque as strings de formato são armazenadas no host.
Plataformas Suportadas
O Embassy suporta uma variedade impressionante de microcontroladores em 2026:
- STM32: praticamente toda a família (F0, F1, F2, F3, F4, F7, G0, G4, H5, H7, L0, L1, L4, L5, U5, WB, WL)
- Nordic nRF: nRF52832, nRF52840, nRF5340, nRF9160 (com suporte a LTE)
- ESP32: via
esp-halcom integração Embassy (ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6) - RP2040/RP2350: Raspberry Pi Pico e Pico 2
IoT com Embassy: Conectando ao Mundo
Para projetos IoT, o Embassy oferece o embassy-net, uma stack de rede TCP/IP completa e assíncrona. Combinado com drivers Wi-Fi ou Ethernet, você pode criar dispositivos IoT conectados com facilidade. Para backends IoT que recebem dados desses dispositivos, Go é uma escolha popular pela sua simplicidade em criar serviços HTTP e MQTT.
Quando Usar Rust com Embassy
O Embassy é ideal para:
- Produtos que exigem confiabilidade: dispositivos médicos, industriais, automotivos
- Projetos com requisitos de baixo consumo: o executor cooperativo permite sleep modes agressivos
- Sistemas com múltiplas tarefas concorrentes: sensores, comunicação, display, tudo sem RTOS
- Prototipagem rápida: a ergonomia do Rust + Embassy acelera o desenvolvimento
Se você vem do mundo async Rust, vai se sentir em casa. As mesmas primitivas de async/await que funcionam com Tokio no servidor funcionam com Embassy no microcontrolador. E se está pensando em usar Rust em produção, veja nossos cases reais de Rust em produção.
Conclusão
O Embassy transformou o desenvolvimento embarcado com Rust de uma possibilidade teórica em uma realidade prática e produtiva. Com async/await no bare metal, HALs maduros para as principais famílias de microcontroladores e ferramentas de debugging de primeira classe, não há mais desculpa para não experimentar Rust no seu próximo projeto embarcado.
A combinação de segurança de memória, zero-cost abstractions e programação assíncrona ergonômica faz do Rust com Embassy uma escolha superior ao C para a maioria dos novos projetos de sistemas embarcados e IoT em 2026.