Rust para Sistemas Embarcados com Embassy em 2026

Aprenda a usar o framework Embassy para desenvolver sistemas embarcados em Rust com async/await, suporte a STM32, ESP32 e nRF, e exemplos práticos.

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_std maduro: crates como embedded-hal, defmt e probe-rs formam 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

AspectoRust com EmbassyC Tradicional
Segurança de memóriaGarantida em compilaçãoResponsabilidade do dev
Programação assíncronaNativa com async/awaitCallbacks ou RTOS
Abstrações de hardwareHAL traits padronizadosHAL vendor-specific
Debuggingprobe-rs + defmtOpenOCD + printf
Footprint binárioComparável ao CReferência
Curva de aprendizadoModerada a altaModerada
ConcorrênciaSegura por designPropensa 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

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

Veja Também