probe-rs 2026: Debug de Rust Embarcado | Rust Brasil

Aprenda a usar probe-rs em 2026 para gravar, executar e depurar firmware Rust em STM32, nRF, RP2040 e RISC-V, com RTT, defmt e VS Code.

O probe-rs é a opção mais direta para gravar, executar e depurar firmware Rust em muitos microcontroladores ARM e RISC-V. Ele conversa com probes como ST-Link, J-Link e CMSIS-DAP, entende os metadados do binário Rust e reúne flash, controle de execução, RTT e integração com defmt em uma única stack. Para começar, instale as ferramentas, confirme que o probe USB aparece, selecione o chip correto e configure o runner do Cargo.

Este guia apresenta um fluxo reproduzível para debug de Rust embarcado em 2026, do primeiro probe-rs list até breakpoints no VS Code. O foco é entender as camadas para não cair no ciclo de reinstalar tudo quando o problema real está em permissões USB, alimentação da placa, target de compilação ou identificação incorreta do microcontrolador.

Se você ainda está montando a stack, leia primeiro o panorama de Rust para sistemas embarcados e o tutorial de Embassy para IoT. Para instalar compilador, Cargo e componentes, use o guia do rustup.

O que o probe-rs faz

Em uma sessão de desenvolvimento embarcado existem quatro elementos diferentes:

  1. o computador, onde Cargo compila o firmware;
  2. o probe de depuração, conectado por USB ao computador;
  3. a interface física, normalmente SWD ou JTAG;
  4. o microcontrolador, onde o programa é gravado e executado.

O probe-rs é o software que coordena essa conversa. Ele pode:

  • enumerar probes conectados;
  • identificar e anexar-se a um target compatível;
  • apagar e programar a memória flash;
  • resetar, iniciar, pausar e continuar o processador;
  • ler memória, registradores e estado dos cores;
  • executar um ELF e exibir mensagens RTT;
  • decodificar logs compactos gerados pelo defmt;
  • servir como backend de debug para editores compatíveis com DAP;
  • gerar um arquivo de diagnóstico quando uma sessão falha.

A vantagem para projetos Rust é a integração natural com Cargo e com o formato ELF produzido pelo toolchain. Você não precisa transformar toda execução em uma sequência manual de objcopy, servidor GDB, porta TCP e cliente separado. Essas peças continuam úteis em situações específicas, mas deixam de ser obrigatórias no caminho mais comum.

probe-rs, OpenOCD, cargo-embed e cargo-flash

As ferramentas se sobrepõem, mas não são sinônimos:

FerramentaPapel principalQuando faz sentido
probe-rsComunicação, flash, execução e debugPonto de partida para projetos Rust modernos
OpenOCDServidor de debug tradicional e altamente configurávelTargets, scripts de placa ou fluxos legados já consolidados
cargo-embedExecução configurada por Embed.toml sobre probe-rsProjeto quer padronizar reset, RTT e opções de flash
cargo-flashGravação de firmware pela linha de comandoAutomação que precisa somente programar a flash
GDBCliente de debug clássicoEquipe depende do fluxo GDB ou de integrações específicas

Em um projeto novo, comece com probe-rs run e probe-rs download. Adicione cargo-embed quando um arquivo declarativo reduzir repetição para a equipe. Mantenha OpenOCD se a placa ou o processo de homologação depende de scripts já testados — trocar ferramenta sem resolver uma dor concreta só aumenta a superfície de configuração.

Como instalar o probe-rs

Quem já usa Rust pode instalar a suíte pela própria toolchain:

cargo install probe-rs-tools --locked
probe-rs --version

A opção --locked pede ao Cargo que respeite o lockfile publicado pelo pacote, o que tende a tornar a instalação mais reproduzível. A compilação pode demorar porque inclui dependências de USB, protocolos de debug e suporte a vários targets.

O projeto também distribui binários para plataformas suportadas. Em uma equipe, escolha um método e documente a versão esperada. Evite deixar cada pessoa com uma versão desconhecida quando o firmware depende de um chip recém-adicionado ou de um comportamento específico do debugger.

Depois da instalação, conecte a placa e liste os probes:

probe-rs list

Se nenhum dispositivo aparecer, ainda não adianta investigar o código Rust. Primeiro resolva a camada USB.

Linux: permissões e regras udev

No Linux, o dispositivo pode aparecer no lsusb, mas continuar inacessível ao usuário comum. Instale as regras udev recomendadas pelo projeto ou pela distribuição e recarregue-as. Dependendo do sistema, também será necessário reconectar o probe, reiniciar a sessão ou ajustar o grupo que possui acesso ao dispositivo.

Use este diagnóstico inicial:

lsusb
probe-rs list

Executar tudo com sudo pode mascarar a falta de permissões, além de criar artefatos do Cargo pertencentes ao usuário root. Corrija a regra do dispositivo em vez de transformar privilégio elevado em rotina.

Windows e macOS

No Windows, confira se o probe está usando o driver esperado. Ferramentas do fabricante podem instalar um driver incompatível com acesso genérico via USB, dependendo do modelo e do modo. No macOS, confirme também cabos, hubs e permissões do ambiente de desenvolvimento.

Em qualquer sistema, teste um cabo USB conhecido por transportar dados. Cabos destinados somente a carga são uma causa surpreendentemente frequente de “probe não encontrado”.

Descobrindo o chip correto

O probe e o target são coisas diferentes. Um ST-Link pode ser detectado corretamente, mas o probe-rs ainda precisa saber qual microcontrolador está conectado.

Pesquise a lista de chips suportados:

probe-rs chip list | grep -i stm32f411
probe-rs chip list | grep -i rp2040

Use o identificador exato retornado pela ferramenta. A marca impressa na placa nem sempre basta: placas da mesma família podem usar variantes com flash, RAM, encapsulamento ou revisão diferentes.

Para anexar explicitamente:

probe-rs attach --chip STM32F411CEUx

O nome acima é apenas um exemplo. Substitua-o pelo target real da sua placa. Se a conexão falhar, confira:

  • alimentação e terra comum;
  • fios SWDIO, SWCLK, GND e, quando necessário, RESET;
  • tensão lógica compatível;
  • firmware atualizado do probe;
  • chip selecionado;
  • velocidade de comunicação;
  • estado de proteção da flash.

Configurando o target de compilação

O probe-rs não corrige um firmware compilado para a arquitetura errada. Um STM32F411, por exemplo, usa Cortex-M4F e normalmente recebe código para thumbv7em-none-eabihf.

Instale o target:

rustup target add thumbv7em-none-eabihf

No projeto, crie .cargo/config.toml:

[build]
target = "thumbv7em-none-eabihf"

[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F411CEUx"

[env]
DEFMT_LOG = "info"

Com isso, cargo run --release compila o ELF e chama o probe-rs automaticamente:

cargo run --release

Não copie o target acima para ESP32, RP2040, nRF ou RISC-V sem verificar a arquitetura. O rustup permite instalar vários targets lado a lado, mas o projeto deve escolher o correto.

Gravar, executar e apagar

Para compilar e executar pelo runner:

cargo run --release

Para trabalhar diretamente com o binário:

cargo build --release
probe-rs run --chip STM32F411CEUx \
  target/thumbv7em-none-eabihf/release/meu-firmware

Quando você quer apenas programar a flash sem manter uma sessão de execução:

probe-rs download --chip STM32F411CEUx \
  target/thumbv7em-none-eabihf/release/meu-firmware

Também existe operação de apagamento. Use-a com intenção, especialmente em dispositivos que armazenam calibração, bootloader, credenciais provisionadas ou dados persistentes em regiões da flash. Em hardware de desenvolvimento, um erase completo pode resolver proteção ou conteúdo inconsistente; em produto provisionado, pode destruir informação importante.

Logging eficiente com defmt e RTT

println! não está disponível da mesma maneira em um ambiente #![no_std], e enviar strings formatadas por UART consome flash, RAM, CPU e largura de banda. O defmt reduz esse custo ao deixar boa parte da formatação no computador.

Dependências típicas:

[dependencies]
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }

No firmware:

#![no_std]
#![no_main]

use defmt::info;
use {defmt_rtt as _, panic_probe as _};

#[cortex_m_rt::entry]
fn main() -> ! {
    let versao = 1_u8;
    info!("firmware iniciado, versao={=u8}", versao);

    loop {
        cortex_m::asm::wfi();
    }
}

Ao executar o ELF com probe-rs run, a ferramenta encontra o canal RTT e usa os metadados do binário para reconstruir as mensagens no host. Preserve informações de debug no perfil release:

[profile.release]
debug = 2
lto = true
opt-level = "s"
codegen-units = 1

debug = 2 aumenta o tamanho do arquivo ELF no computador, mas não significa que todas essas informações serão gravadas na flash. O arquivo usado pelo debugger precisa conter símbolos suficientes para backtraces, nomes de funções e decodificação correta.

Quando usar cargo-embed

O cargo-embed é útil quando o time quer guardar opções de execução em um arquivo Embed.toml. Um exemplo conceitual:

[default.general]
chip = "STM32F411CEUx"

[default.reset]
enabled = true
halt_afterwards = false

[default.rtt]
enabled = true

A configuração aceita depende da versão instalada. Valide os campos na documentação correspondente à sua versão em vez de copiar um Embed.toml antigo sem revisão.

Depois, o fluxo costuma ser:

cargo embed --release

A vantagem não é “ser mais poderoso” que a base probe-rs, e sim transformar opções repetidas em configuração versionada. Para um exemplo rápido ou uma CI de flash, a CLI direta pode ser mais clara.

Debug com breakpoints no VS Code

O probe-rs oferece integração com o Debug Adapter Protocol (DAP), usado por editores como VS Code. Na prática, uma extensão compatível inicia uma sessão, carrega o ELF, conecta-se ao probe e traduz ações do editor — breakpoint, step over, step into, continue e inspeção — para o backend.

O fluxo geral é:

  1. compile o firmware com símbolos de debug;
  2. instale uma extensão de debug compatível com probe-rs;
  3. informe o chip e o caminho do ELF;
  4. selecione o core quando o dispositivo tiver mais de um;
  5. inicie a sessão com a placa conectada;
  6. coloque breakpoints em código executável, não em trecho otimizado para fora.

Um arquivo de configuração varia conforme a extensão e sua versão. Não trate um launch.json encontrado em tutorial antigo como API permanente. Os dados essenciais, porém, permanecem os mesmos: chip, ELF, core, comportamento de reset e modo de conexão.

O rust-analyzer continua responsável por autocompletar, navegação e diagnósticos do código. O adaptador do probe-rs cuida da execução no hardware. São ferramentas complementares.

Por que o breakpoint não para

Em firmware otimizado, uma linha do arquivo-fonte pode não corresponder a uma instrução exclusiva. O compilador pode:

  • remover código sem efeito observável;
  • embutir uma função no chamador;
  • fundir ou reordenar instruções;
  • manter valores somente em registradores;
  • transformar várias linhas em um único bloco.

Para investigar, compare um build de desenvolvimento com um release que preserve símbolos:

cargo build
cargo build --release

O build sem otimização costuma oferecer stepping mais previsível, mas pode mudar timing, consumo de flash e comportamento de concorrência. Bugs dependentes de tempo precisam ser analisados também em condições próximas da produção.

Problemas comuns e como diagnosticar

Nenhum probe encontrado

  1. confirme o cabo de dados;
  2. teste outra porta USB e evite hubs no primeiro diagnóstico;
  3. rode lsusb ou o gerenciador de dispositivos;
  4. instale regras udev ou driver adequado;
  5. atualize o firmware do probe quando aplicável;
  6. rode probe-rs list novamente.

Probe aparece, mas não conecta ao chip

Confira pinagem SWD/JTAG, GND compartilhado, alimentação, reset e chip selecionado. Reduza a velocidade de debug se o sinal estiver ruim ou se o target estiver usando clock incomum. Algumas placas exigem conexão durante reset quando o firmware reconfigura rapidamente os pinos de debug ou entra em baixo consumo.

Flash falha ou verificação não confere

Possíveis causas incluem proteção de leitura/escrita, região incorreta, target errado, queda de alimentação e bootloader ocupando a mesma área. Leia o mapa de memória e o linker script antes de apagar tudo.

defmt não mostra mensagens

Confirme que:

  • defmt-rtt foi vinculado ao firmware;
  • existe um panic handler compatível;
  • o ELF executado é exatamente o binário gravado;
  • informações de debug não foram removidas;
  • o código realmente alcança a chamada de log;
  • o nível definido por DEFMT_LOG permite a mensagem.

A sessão trava após um panic

Isso pode ser o comportamento esperado do panic handler. Use panic-probe com saída defmt, preserve símbolos e examine o backtrace. Em firmware, “travar” em um loop após panic é frequentemente preferível a continuar com estado inválido.

Fluxo recomendado para equipes

Um projeto embarcado reproduzível deve versionar mais do que o src/main.rs:

  • rust-toolchain.toml com canal e targets necessários;
  • .cargo/config.toml com target e runner;
  • linker script e arquivo de memória;
  • identificação exata da placa e do chip;
  • versão ou método de instalação do probe-rs;
  • diagrama dos pinos de debug;
  • comandos de build, flash, teste e recuperação;
  • política para apagar flash e preservar dados provisionados.

Na CI, compile e execute testes que não dependem de hardware. Para validação real, uma bancada hardware-in-the-loop pode conectar placas a runners controlados, gravar o firmware, coletar RTT e validar periféricos. Esse tipo de experiência também é valorizado em carreiras de Rust embarcado e ajuda a construir um portfólio mais convincente do que somente um LED piscando.

probe-rs por plataforma

STM32 e nRF

São famílias muito comuns no ecossistema ARM Cortex-M. ST-Link, J-Link e probes CMSIS-DAP aparecem bastante em placas de desenvolvimento. Confirme o part number completo e o core correto.

RP2040 e RP2350

A Raspberry Pi Debug Probe e outros dispositivos CMSIS-DAP oferecem um caminho acessível para SWD. O UF2 continua prático para o primeiro flash, mas uma conexão de debug permite breakpoints, inspeção e ciclos mais rápidos.

ESP32 e RISC-V

A família ESP32 possui variantes Xtensa e RISC-V, com toolchains e mecanismos de flash diferentes. Não presuma que um comando válido para ESP32-C3 serve para um ESP32 clássico. Em vários projetos, espflash e ferramentas do ecossistema esp-rs complementam ou substituem partes do fluxo, conforme o chip e a interface.

Para uma comparação com outra linguagem voltada a sistemas e interoperabilidade com C, o guia de Zig para embarcados mostra uma abordagem diferente para firmware e cross-compilation.

Checklist rápido

Antes de abrir o debugger, confirme:

  • o probe aparece em probe-rs list;
  • o chip exato existe em probe-rs chip list;
  • a placa está alimentada e compartilha GND com o probe;
  • SWDIO/SWCLK ou JTAG estão ligados corretamente;
  • o target do Rust corresponde à arquitetura do chip;
  • o linker script corresponde à memória real;
  • o runner aponta para o chip correto;
  • o ELF preserva símbolos de debug;
  • defmt-rtt e o panic handler estão vinculados;
  • o firmware gravado é o mesmo ELF aberto no debugger.

Conclusão

O probe-rs reduz bastante o atrito entre “o firmware compilou” e “eu entendo o que está acontecendo no microcontrolador”. Com uma única stack você pode detectar o probe, gravar a flash, executar o ELF, coletar logs compactos com defmt e iniciar uma sessão gráfica de debug.

A parte mais importante é diagnosticar por camadas. Primeiro USB e permissões; depois probe e fiação; em seguida chip, target e mapa de memória; somente então firmware, símbolos e breakpoints. Essa ordem evita perder horas alterando código quando o computador nem consegue conversar com a placa.

Para continuar, pratique com o guia de Rust embarcado, experimente tarefas assíncronas no Embassy e conheça o cenário de Linux embarcado e IoT industrial. Se o objetivo é carreira, veja também as faixas salariais de firmware e sistemas embarcados.

Perguntas frequentes

O que é o probe-rs?

É uma suíte aberta para flash e debug de microcontroladores ARM e RISC-V. Ela conecta o computador a probes compatíveis, controla o target e integra o fluxo com binários e ferramentas do ecossistema Rust.

Como instalar o probe-rs em 2026?

Uma opção é executar cargo install probe-rs-tools --locked. Depois confirme a instalação com probe-rs --version e a comunicação USB com probe-rs list. No Linux, instale também as regras udev necessárias.

Qual é a diferença entre probe-rs, cargo-embed e cargo-flash?

probe-rs é a base de comunicação e debug. cargo-embed organiza flash, reset e RTT por meio de configuração versionada. cargo-flash é voltado principalmente à gravação. Para começar, a CLI probe-rs costuma ser suficiente.

Ele suporta várias versões de ST-Link, J-Link e CMSIS-DAP, categoria que inclui diversos probes acessíveis. Verifique o modelo local com probe-rs list e confirme também o suporte ao microcontrolador de destino.

Como ver logs defmt com probe-rs?

Vincule defmt, defmt-rtt e um panic handler compatível, preserve símbolos no ELF e execute o firmware com probe-rs run --chip .... A ferramenta lê o RTT e formata as mensagens no computador.