---
title: "Rust Embarcados: IoT, ESP32 e ARM Cortex-M | Rust Brasil"
url: "https://rustlang.com.br/artigos/rust-para-embarcados/"
markdown_url: "https://rustlang.com.br/artigos/rust-para-embarcados.MD"
description: "Guia de Rust para sistemas embarcados: no_std, embedded-hal, probe-rs, RTIC, ESP32 com esp-rs e ARM Cortex-M em 2026."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Rust Embarcados: IoT, ESP32 e ARM Cortex-M | Rust Brasil

Guia de Rust para sistemas embarcados: no_std, embedded-hal, probe-rs, RTIC, ESP32 com esp-rs e ARM Cortex-M em 2026.


## Introdução

Programação de sistemas embarcados tradicionalmente é dominada por C e, em menor grau, C++. Mas Rust está mudando esse cenário rapidamente. A combinação de **segurança de memória sem garbage collector**, **abstrações zero-cost**, **suporte a `no_std`** (programação sem a biblioteca padrão) e um **ecossistema crescente de HALs (Hardware Abstraction Layers)** torna Rust uma alternativa real e cada vez mais adotada para microcontroladores e dispositivos IoT.

Ao contrário de C, onde buffer overflows, dangling pointers e data races são bugs comuns e frequentemente explorados em dispositivos conectados, Rust elimina essas classes inteiras de vulnerabilidades em tempo de compilação. Para dispositivos IoT que operam em ambientes hostis e raramente recebem atualizações de segurança, essa garantia é especialmente valiosa.

## O Ecossistema Embedded Rust

### Conceitos Fundamentais

- **`no_std`**: Permite compilar Rust sem a biblioteca padrão (std), necessário para microcontroladores sem sistema operacional. Você ainda tem acesso ao `core` (tipos primitivos, iteradores, Option/Result) e opcionalmente ao `alloc` (alocação dinâmica)
- **`embedded-hal`**: Traits que definem interfaces genéricas para GPIO, SPI, I2C, UART, PWM, etc. Permite escrever drivers portáteis entre diferentes microcontroladores
- **PAC (Peripheral Access Crate)**: Gerado automaticamente a partir de arquivos SVD, fornece acesso de baixo nível aos registradores do chip
- **HAL (Hardware Abstraction Layer)**: Implementa os traits de `embedded-hal` para um chip específico, oferecendo uma API segura e idiomática

### Plataformas Suportadas

| Plataforma | Crate Principal | Exemplos de Chips |
|---|---|---|
| ARM Cortex-M | `cortex-m`, `cortex-m-rt` | STM32, nRF52, RP2040 |
| ESP32 | `esp-hal`, `esp-idf-hal` | ESP32, ESP32-S3, ESP32-C3 |
| RISC-V | `riscv`, `riscv-rt` | ESP32-C3, GD32V |
| AVR | `avr-device` | ATmega328P (Arduino) |
| Raspberry Pi Pico | `rp-hal` | RP2040 |

### Ferramentas de Desenvolvimento

| Ferramenta | Função |
|---|---|
| **probe-rs** | Flash, debug e RTT logging para ARM e RISC-V |
| **cargo-embed** | Integração probe-rs com Cargo (flash + monitor) |
| **espflash** | Flash para chips ESP32 |
| **defmt** | Framework de logging ultra-eficiente para embarcados |

### Cargo.toml para um Projeto Embarcado (STM32)

```toml
[package]
name = "sensor-iot"
version = "0.1.0"
edition = "2021"

[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "1.0"
stm32f4xx-hal = { version = "0.22", features = ["stm32f411"] }
embedded-hal = "1.0"
defmt = "0.3"
defmt-rtt = "0.4"

[profile.release]
opt-level = "z"     # Otimizar para tamanho
lto = true
codegen-units = 1
debug = true        # Manter debug info para probe-rs
```

## Exemplo Prático: Sensor de Temperatura IoT com STM32

Vamos construir um dispositivo que lê temperatura de um sensor DHT22 via GPIO e envia os dados por UART.

```rust
#![no_std]
#![no_main]

use cortex_m_rt::entry;
use panic_halt as _;
use stm32f4xx_hal::{
    gpio::{Output, PushPull, Pin},
    pac,
    prelude::*,
    serial::{config::Config, Serial},
    timer::SysTimerExt,
};
use core::fmt::Write;

/// Estrutura para armazenar leitura do sensor
struct Leitura {
    temperatura: f32,
    umidade: f32,
}

/// Lê dados de um sensor DHT22 conectado ao pino especificado.
/// Simplificado para demonstração — em produção use a crate `dht-sensor`.
fn ler_sensor_simulado(contador: u32) -> Leitura {
    // Em um projeto real, você usaria a crate `dht-sensor`
    // com o embedded-hal para comunicação com o sensor
    Leitura {
        temperatura: 22.5 + (contador % 10) as f32 * 0.3,
        umidade: 65.0 + (contador % 5) as f32 * 1.2,
    }
}

#[entry]
fn main() -> ! {
    // Obter periféricos do chip
    let dp = pac::Peripherals::take().unwrap();
    let cp = cortex_m::Peripherals::take().unwrap();

    // Configurar clocks
    let rcc = dp.RCC.constrain();
    let clocks = rcc.cfgr
        .use_hse(8.MHz())
        .sysclk(84.MHz())
        .freeze();

    // Configurar delay
    let mut delay = cp.SYST.delay(&clocks);

    // Configurar GPIO
    let gpioa = dp.GPIOA.split();
    let gpioc = dp.GPIOC.split();

    // LED de status (PC13 na maioria das placas STM32)
    let mut led: Pin<'C', 13, Output<PushPull>> = gpioc.pc13.into_push_pull_output();

    // Configurar UART (PA2 = TX, PA3 = RX)
    let tx_pin = gpioa.pa2;
    let rx_pin = gpioa.pa3;

    let mut serial = Serial::new(
        dp.USART2,
        (tx_pin, rx_pin),
        Config::default().baudrate(115200.bps()),
        &clocks,
    )
    .unwrap();

    writeln!(serial, "Sensor IoT iniciado - Rust Embedded").unwrap();
    writeln!(serial, "Lendo temperatura a cada 2 segundos...").unwrap();

    let mut contador: u32 = 0;

    // Loop principal
    loop {
        // Piscar LED para indicar leitura
        led.set_low();
        delay.delay_ms(100u32);
        led.set_high();

        // Ler sensor
        let leitura = ler_sensor_simulado(contador);

        // Enviar dados via UART
        writeln!(
            serial,
            "[{}] Temp: {:.1}°C | Umidade: {:.1}%",
            contador,
            leitura.temperatura,
            leitura.umidade
        )
        .unwrap();

        // Alerta se temperatura ultrapassar limiar
        if leitura.temperatura > 30.0 {
            writeln!(serial, "⚠ ALERTA: Temperatura elevada!").unwrap();
        }

        contador = contador.wrapping_add(1);
        delay.delay_ms(2000u32);
    }
}
```

## Exemplo com ESP32 (usando esp-rs)

O ecossistema `esp-rs` permite programar chips ESP32 em Rust, tanto em modo `no_std` quanto com a framework ESP-IDF (que inclui Wi-Fi, Bluetooth, etc.).

```toml
[package]
name = "esp32-sensor"
version = "0.1.0"
edition = "2021"

[dependencies]
esp-idf-hal = "0.44"
esp-idf-svc = "0.50"
esp-idf-sys = { version = "0.36", features = ["binstart"] }
embedded-svc = "0.28"
anyhow = "1"
log = "0.4"
```

```rust
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::PinDriver;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_svc::wifi::{EspWifi, BlockingWifi, ClientConfiguration, Configuration};
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::nvs::EspDefaultNvsPartition;
use esp_idf_svc::http::client::EspHttpConnection;
use embedded_svc::http::client::Client;
use anyhow::Result;
use log::info;

fn conectar_wifi(
    wifi: &mut BlockingWifi<EspWifi<'static>>,
    ssid: &str,
    senha: &str,
) -> Result<()> {
    wifi.set_configuration(&Configuration::Client(ClientConfiguration {
        ssid: ssid.try_into().unwrap(),
        password: senha.try_into().unwrap(),
        ..Default::default()
    }))?;

    wifi.start()?;
    wifi.connect()?;
    wifi.wait_netif_up()?;

    info!("Conectado ao Wi-Fi! IP: {:?}", wifi.wifi().sta_netif().get_ip_info()?);
    Ok(())
}

fn enviar_dados(temperatura: f32, umidade: f32) -> Result<()> {
    let mut cliente = Client::wrap(EspHttpConnection::new(&Default::default())?);

    let url = format!(
        "http://meu-servidor.com/api/sensor?temp={:.1}&umid={:.1}",
        temperatura, umidade
    );

    let resposta = cliente.get(&url)?.submit()?;
    info!("Dados enviados. Status: {}", resposta.status());
    Ok(())
}

fn main() -> Result<()> {
    esp_idf_svc::sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;
    let sysloop = EspSystemEventLoop::take()?;
    let nvs = EspDefaultNvsPartition::take()?;

    // Configurar LED
    let mut led = PinDriver::output(peripherals.pins.gpio2)?;

    // Configurar Wi-Fi
    let mut wifi = BlockingWifi::wrap(
        EspWifi::new(peripherals.modem, sysloop.clone(), Some(nvs))?,
        sysloop,
    )?;

    conectar_wifi(&mut wifi, "MinhaRede", "MinhaSenha123")?;

    // Loop principal
    loop {
        led.set_high()?;
        FreeRtos::delay_ms(100);
        led.set_low()?;

        // Simular leitura de sensor
        let temperatura = 25.3;
        let umidade = 68.0;

        info!("Temperatura: {:.1}°C, Umidade: {:.1}%", temperatura, umidade);

        if let Err(e) = enviar_dados(temperatura, umidade) {
            log::error!("Erro ao enviar dados: {:?}", e);
        }

        FreeRtos::delay_ms(5000);
    }
}
```

## RTIC: Framework de Concorrência em Tempo Real

RTIC (Real-Time Interrupt-driven Concurrency) é um framework que utiliza o sistema de prioridades de interrupção do hardware para garantir concorrência segura sem overhead de runtime:

```rust
#![no_std]
#![no_main]

use panic_halt as _;

#[rtic::app(device = stm32f4xx_hal::pac, dispatchers = [EXTI0])]
mod app {
    use stm32f4xx_hal::{
        gpio::{Output, PushPull, Pin},
        prelude::*,
        timer::MonoTimerUs,
    };

    #[shared]
    struct Shared {
        temperatura: f32,
    }

    #[local]
    struct Local {
        led: Pin<'C', 13, Output<PushPull>>,
    }

    #[init]
    fn init(ctx: init::Context) -> (Shared, Local) {
        let rcc = ctx.device.RCC.constrain();
        let clocks = rcc.cfgr.sysclk(84.MHz()).freeze();
        let gpioc = ctx.device.GPIOC.split();
        let led = gpioc.pc13.into_push_pull_output();

        // Agendar primeira leitura
        ler_sensor::spawn().unwrap();

        (
            Shared { temperatura: 0.0 },
            Local { led },
        )
    }

    #[task(shared = [temperatura], priority = 2)]
    async fn ler_sensor(mut ctx: ler_sensor::Context) {
        loop {
            // Ler sensor (simplificado)
            let temp = 23.5;
            ctx.shared.temperatura.lock(|t| *t = temp);

            // Reagendar para daqui a 1 segundo
            // Em produção, use monotonic timer
        }
    }

    #[task(local = [led], shared = [temperatura], priority = 1)]
    async fn piscar_led(ctx: piscar_led::Context) {
        loop {
            ctx.local.led.toggle();
        }
    }
}
```

## Empresas Usando Rust em Embarcados

- **Espressif**: Fabricante dos chips ESP32, mantém oficialmente o projeto `esp-rs` com suporte completo a Rust
- **Oxide Computer**: Computadores para data center com firmware inteiro escrito em Rust (projeto Hubris OS)
- **Arm**: Investindo em suporte a Rust para a plataforma Cortex-M e colaborando com o Embedded Working Group
- **Infineon**: Suporte a Rust para microcontroladores PSoC e XMC
- **Volvo**: Experimentando Rust para software automotivo embarcado
- **Framework (laptop)**: Componentes de firmware com Rust
- **System76**: Firmware de laptops e teclados (projeto ec, firmware de embedded controller)

## Como Começar

1. **Aprenda Rust primeiro**: Domine ownership e borrowing com [nosso tutorial de primeiros passos](/tutoriais/primeiros-passos/)
2. **Configure cross-compilation**: Siga nosso [guia de cross-compilation](/instalacao/cross-compilation/) para instalar toolchains para ARM e RISC-V
3. **Comece com Raspberry Pi Pico**: O RP2040 é o chip mais acessível para aprender Rust embarcado, com documentação excelente
4. **Explore ESP32**: Se precisa de Wi-Fi/Bluetooth, o ESP32 com `esp-rs` é a porta de entrada mais prática
5. **Pratique `no_std`**: Comece escrevendo código sem a biblioteca padrão, entenda `core` e `alloc`
6. **Estude o Embedded Rust Book**: Recurso oficial da comunidade Rust para desenvolvimento embarcado

### Hardware Recomendado para Iniciantes

| Placa | Preço Aprox. | Destaques |
|---|---|---|
| **Raspberry Pi Pico** | R$ 30 | RP2040, excelente documentação Rust |
| **ESP32-C3 DevKit** | R$ 40 | RISC-V, Wi-Fi, Bluetooth, esp-rs |
| **STM32 Nucleo-F411RE** | R$ 80 | ARM Cortex-M4, ST-Link integrado |
| **BBC micro:bit v2** | R$ 120 | Sensores integrados, LED matrix, BLE |
| **nRF52840 DK** | R$ 200 | BLE 5.0, USB, excelente para IoT |

## Conclusão

Rust está se estabelecendo como uma alternativa séria ao C para desenvolvimento embarcado. A segurança de memória, o sistema de tipos e as abstrações zero-cost fazem de Rust uma escolha natural para dispositivos IoT que precisam ser seguros, confiáveis e eficientes. Com o suporte oficial da Espressif para ESP32 e o crescimento do ecossistema `embedded-hal`, nunca houve um momento melhor para começar com Rust embarcado.

---

## Veja Também

- [Guia de Cross-Compilation](/instalacao/cross-compilation/) — Configure seu ambiente para compilar para diferentes arquiteturas
- [Rust para DevOps](/artigos/rust-para-devops/) — Infraestrutura e automação com Rust
- [Rust para Desenvolvimento Web](/artigos/rust-para-web/) — Conecte seus dispositivos IoT a APIs Rust
- [Tutorial: Primeiros Passos com Rust](/tutoriais/primeiros-passos/) — Fundamentos da linguagem
- [Tutorial: Tratamento de Erros](/tutoriais/tratamento-de-erros/) — Essencial para código embarcado robusto
- [Empresas que Usam Rust](/empresas/) — Veja quem usa Rust em embarcados e IoT
- [Zig Brasil](https://ziglang.com.br) — Zig também é forte em sistemas embarcados e interop com C — compare as opções
