MCU & FPGA RTOS Primeiros Passos com Zephyr RTOS: Guia Prático com STM32 NUCLEO-F411RE e NUCLEO-F429ZI

Primeiros Passos com Zephyr RTOS: Guia Prático com STM32 NUCLEO-F411RE e NUCLEO-F429ZI

O que é o Zephyr RTOS e por que utilizá-lo

O Zephyr RTOS é um sistema operacional de tempo real de código aberto, mantido pela Linux Foundation, projetado especificamente para sistemas embarcados modernos. Diferentemente de RTOS tradicionais focados apenas em microcontroladores simples, o Zephyr foi concebido desde o início para escalar desde MCUs pequenos até sistemas embarcados complexos, com forte ênfase em portabilidade, segurança, modularidade e padronização.

Um dos grandes diferenciais do Zephyr é sua arquitetura fortemente orientada a Kconfig, Device Tree e CMake, permitindo que o mesmo código-fonte seja recompilado para diferentes placas e arquiteturas apenas alterando parâmetros de build. Isso muda profundamente o fluxo de desenvolvimento quando comparado a abordagens tradicionais baseadas em IDEs proprietárias e projetos fortemente acoplados ao hardware.

Do ponto de vista prático, o Zephyr resolve problemas clássicos enfrentados em projetos embarcados de médio e grande porte, como:

  • crescimento descontrolado do código,
  • dificuldade de reutilização entre placas diferentes,
  • dependência excessiva de ferramentas específicas de fabricantes,
  • e ausência de um modelo claro de configuração de hardware e software.

Além disso, o Zephyr já nasce integrado a um ecossistema moderno, com suporte oficial a centenas de placas, arquiteturas como ARM Cortex-M, RISC-V, Xtensa, além de um conjunto robusto de drivers, stacks de comunicação, sistema de arquivos, rede, USB, Bluetooth, sensores e sincronização de threads.


Zephyr no contexto STM32

No caso específico da família STM32, o Zephyr se destaca por:

  • suportar diretamente placas NUCLEO e DISCOVERY,
  • abstrair completamente a dependência do STM32Cube HAL quando desejado,
  • permitir o uso de exemplos oficiais prontos (samples),
  • e oferecer um fluxo de build reproduzível e automatizado via linha de comando.

Neste tutorial, trabalharemos com duas placas bastante comuns em ambientes educacionais e profissionais:

  • NUCLEO-F411RE, usando um exemplo simples (blinky);
  • NUCLEO-F429ZI, usando um exemplo mais avançado (threads), explorando concorrência real.

A escolha desses dois exemplos não é arbitrária: ela permite observar claramente como o Zephyr escala de um firmware elementar para um sistema multitarefa sem alterar o fluxo básico de desenvolvimento.


O fluxo mental do Zephyr (antes de escrever código)

Antes de entrarmos em instalação e comandos, é importante compreender o modelo mental do Zephyr:

  1. O código da aplicação é apenas uma parte do sistema.
  2. A placa é descrita por Device Tree, não por arquivos .h específicos.
  3. As funcionalidades do sistema são habilitadas via Kconfig.
  4. O build é sempre feito fora da árvore da aplicação (out-of-tree build).
  5. O comando west orquestra todo o processo: fetch, build, flash e debug.

Esse modelo pode parecer estranho no início, especialmente para quem vem de ambientes como Arduino, STM32CubeIDE ou ESP-IDF, mas ele se mostra extremamente poderoso à medida que o projeto cresce.


Preparando o ambiente de desenvolvimento do Zephyr

Antes de compilar qualquer exemplo, é fundamental preparar corretamente o ambiente. O Zephyr adota um fluxo totalmente baseado em linha de comando, multiplataforma e reproduzível, o que é uma grande vantagem em ambientes profissionais, CI/CD e times distribuídos.

Nesta seção vamos entender o que precisa estar instalado, por que cada ferramenta existe e como elas se encaixam no fluxo de desenvolvimento.


2.1 Conceito central: o papel do west

O west é a ferramenta central do Zephyr. Ele não é apenas um “build tool”, mas sim um meta-ferramenta que gerencia:

  • repositórios Git (manifesto do Zephyr),
  • build (invocando CMake + Ninja),
  • flashing,
  • debugging,
  • e extensão de comandos específicos do ecossistema Zephyr.

Em termos práticos, pense no west como:

uma combinação de repo + cmake wrapper + flash/debug frontend.

Você não compila Zephyr sem o west.


2.2 Ferramentas necessárias

Para trabalhar com o Zephyr, você precisa de quatro camadas básicas de ferramentas:

1. Python (obrigatório)

O Zephyr utiliza Python para:

  • o west,
  • scripts de build,
  • geração de código,
  • e validações internas.

Versão recomendada:

  • Python 3.8 ou superior

Verifique:

python3 --version

2. Toolchain (compilador)

Para placas STM32 (ARM Cortex-M), o Zephyr utiliza:

  • GNU Arm Embedded Toolchain

Ela fornece:

  • arm-none-eabi-gcc
  • ld, objcopy, objdump
  • suporte completo a Cortex-M3/M4/M7

Verificação:

arm-none-eabi-gcc --version

Importante: o Zephyr não usa o compilador do STM32CubeIDE por padrão. Ele trabalha com toolchains independentes.


3. CMake e Ninja

O sistema de build do Zephyr é baseado em:

  • CMake → geração de build
  • Ninja → execução rápida do build

Verificação:

cmake --version
ninja --version

4. Ferramentas de flash/debug

Para placas NUCLEO, normalmente usamos:

  • OpenOCD (via ST-Link)

Verificação:

openocd --version

2.3 Criando o workspace do Zephyr

O Zephyr trabalha em um workspace, que é um diretório contendo:

  • o kernel Zephyr,
  • módulos externos,
  • aplicações,
  • e builds fora da árvore.

Fluxo típico:

zephyr-workspace/
├── zephyr/
├── modules/
├── bootloader/
├── tools/
└── applications/

Caso ainda não tenha o west instalado, execute o seguinte comando com o python.

python -m venv zephyr-workspace/.venv
source zephyr-workspace/.venv/bin/activate
pip install west

Então continue com a criação inicial:

west init zephyr-workspace
cd zephyr-workspace
west update
west zephyr-export

Esses comandos:

  1. Inicializam o manifesto,
  2. Baixam o kernel e módulos,
  3. Exportam variáveis de ambiente necessárias ao build.

Uma vez feito isso, você não precisa repetir para cada projeto.


2.4 Entendendo o conceito de build fora da árvore

No Zephyr, o diretório de build nunca fica misturado com o código-fonte.

Isso permite:

  • múltiplos builds para placas diferentes,
  • builds paralelos,
  • comparação entre configurações,
  • limpeza sem apagar código.

Por exemplo:

applications/
├── nucleof411re/
│   └── build/
├── nucleof429zi/
│   └── build/

Cada pasta representa um alvo de hardware específico.


2.5 Por que isso é importante na prática

Esse modelo resolve vários problemas clássicos:

  • você pode compilar o mesmo exemplo para várias placas sem conflitos;
  • o código original dos samples do Zephyr nunca é modificado;
  • o build fica totalmente reprodutível;
  • facilita automação e versionamento.

Isso será explorado explicitamente nas próximas seções, quando montarmos:

  • o build do blinky para a NUCLEO-F411RE;
  • e o build do threads para a NUCLEO-F429ZI.

Primeiro build prático: NUCLEO-F411RE com o exemplo blinky

Nesta seção faremos o primeiro contato prático com o Zephyr, compilando e gravando um firmware extremamente simples, porém fundamental: o blinky.
Apesar da simplicidade funcional (piscar um LED), esse exemplo permite entender todo o fluxo real de trabalho no Zephyr: organização de diretórios, comando de build, seleção de placa e gravação do firmware.


3.1 Por que começar com o blinky

O blinky é o “Hello World” dos sistemas embarcados. No contexto do Zephyr, ele é especialmente útil porque:

  • não depende de periféricos complexos,
  • usa apenas GPIO,
  • valida rapidamente se toolchain, placa e debug estão funcionando,
  • já utiliza Device Tree para mapear o LED da placa.

Ou seja: se o blinky funciona, todo o ambiente está corretamente configurado.


3.2 Organização do diretório para a NUCLEO-F411RE

Partimos do princípio que você já está no diretório raiz do workspace do Zephyr.

Agora criaremos um diretório dedicado exclusivamente a esta placa:

mkdir nucleof411re
cd nucleof411re

Esse diretório não contém código-fonte, apenas o resultado do build.
Essa prática é altamente recomendada em projetos reais, pois permite manter builds separados por hardware.


3.3 Comando de build do blinky

Com o diretório criado, execute exatamente o comando abaixo:

west build -p always -b nucleof411re ../zephyr/samples/blinky

Vamos destrinchar esse comando em detalhes.


3.4 Explicando o comando west build em profundidade

west build

É o comando responsável por:

  • configurar o CMake,
  • gerar os arquivos de build,
  • e compilar o firmware.

-p always

Força o pristine build, ou seja:

  • apaga qualquer build anterior,
  • garante que nenhuma configuração antiga interfira no resultado.

Em ambientes profissionais, isso evita bugs difíceis de rastrear.


-b nucleof411re

Seleciona explicitamente a placa alvo.

Esse parâmetro faz com que o Zephyr:

  • carregue o Device Tree da NUCLEO-F411RE,
  • selecione o SoC STM32F411,
  • configure clock, GPIO, memória e periféricos corretamente.

../zephyr/samples/blinky

Indica o código-fonte da aplicação, que neste caso é:

  • um exemplo oficial do Zephyr,
  • localizado dentro da árvore do kernel.

Note que não copiamos o código, apenas o referenciamos.


3.5 O que acontece internamente durante o build

Ao executar o comando, o Zephyr:

  1. Lê o Device Tree da placa
  2. Processa as opções de Kconfig
  3. Gera código de inicialização
  4. Compila o kernel RTOS
  5. Compila a aplicação (blinky)
  6. Linka tudo em um único firmware

Ao final, você terá algo como:

nucleof411re/
└── build/
    ├── zephyr/
    │   ├── zephyr.elf
    │   ├── zephyr.hex
    │   └── zephyr.bin

Esses arquivos são os artefatos finais de firmware.


3.6 Gravando o firmware na NUCLEO-F411RE

Com a placa conectada via USB (ST-Link), execute:

west flash

O west irá:

  • detectar automaticamente o runner (OpenOCD),
  • identificar o ST-Link,
  • gravar o firmware,
  • e reiniciar a placa.

Se tudo estiver correto, o LED da NUCLEO-F411RE começará a piscar.


3.7 Cenários comuns e soluções

Placa não detectada

  • Verifique o cabo USB
  • Confirme permissões de acesso (Linux)
  • Teste:lsusb

Erro de OpenOCD

  • Confirme se o OpenOCD suporta o ST-Link da placa
  • Atualize a versão se necessário

Build falha

  • Verifique se o nome da placa está correto (nucleof411re)
  • Confirme se o workspace foi inicializado corretamente

3.8 O que você aprendeu até aqui

Neste ponto, você já domina:

  • o fluxo básico do Zephyr,
  • build fora da árvore,
  • seleção explícita de placa,
  • e gravação de firmware via west.

Na próxima seção, subiremos o nível e trabalharemos com:

  • NUCLEO-F429ZI,
  • exemplo threads,
  • e conceitos reais de concorrência no Zephyr.

Exemplo avançado: NUCLEO-F429ZI com o sample threads

Após validar o ambiente com o blinky, o próximo passo natural é entender como o Zephyr se comporta em um cenário multitarefa real. Para isso, utilizaremos o sample threads, que demonstra criação, escalonamento e execução concorrente de múltiplas threads.

Esse exemplo é extremamente importante porque ele já expõe o Zephyr como RTOS de fato, e não apenas como um firmware bare-metal com delays.


4.1 Por que usar o sample threads

O sample threads foi escolhido porque ele:

  • cria múltiplas threads com prioridades diferentes,
  • demonstra preempção,
  • utiliza delays baseados no kernel,
  • mostra claramente o papel do escalonador.

Na prática, ele permite observar:

  • como o Zephyr alterna tarefas,
  • como prioridades influenciam execução,
  • e como o kernel se comporta em tempo real.

Isso é especialmente relevante na NUCLEO-F429ZI, que possui:

  • Cortex-M4F mais potente,
  • maior quantidade de RAM e Flash,
  • e é típica de aplicações industriais e IoT mais complexas.

4.2 Organização do diretório para a NUCLEO-F429ZI

Agora vamos voltar para o diretório principal do projeto (workspace ou pasta onde você está organizando os builds) e criar um novo diretório específico para esta placa:

cd ..
mkdir nucleof429zi
cd nucleof429zi

Assim como no caso anterior, este diretório conterá apenas o build, mantendo os projetos totalmente isolados por hardware.


4.3 Comando de build do sample threads

Execute o comando exatamente como definido:

west build -p always -b nucleof429re ../zephyr/samples/threads

Observação importante:
Apesar do diretório se chamar nucleof429zi, o identificador da placa no Zephyr é nucleof429re, e é esse nome que deve ser usado no parâmetro -b.


4.4 Análise detalhada do comando

A estrutura do comando é a mesma usada no blinky, o que reforça a consistência do fluxo de trabalho no Zephyr.

  • -p always
    Garante um build limpo, evitando resíduos de builds anteriores.
  • -b nucleof429re
    Seleciona o Device Tree e as configurações corretas da NUCLEO-F429ZI.
  • ../zephyr/samples/threads
    Aponta para um exemplo que já faz uso intensivo do kernel RTOS.

Essa repetição do padrão de build é proposital: uma vez entendido, ele não muda, independentemente da complexidade da aplicação.


4.5 O que o sample threads faz internamente

Sem entrar ainda no código linha a linha (faremos isso adiante), o comportamento geral é:

  • Criação de múltiplas threads via k_thread_create
  • Cada thread executa um loop infinito
  • Cada uma imprime mensagens periódicas
  • Delays são feitos com k_msleep()
  • O escalonador decide qual thread executa a cada instante

Em placas com saída serial ativa, você verá mensagens intercaladas no terminal, evidenciando o funcionamento do RTOS.


4.6 Gravando o firmware na NUCLEO-F429ZI

Com a placa conectada:

west flash

O processo é idêntico ao anterior:

  • detecção automática do ST-Link,
  • uso do OpenOCD,
  • gravação e reset da placa.

Se houver saída serial configurada, você poderá acompanhar a execução das threads via terminal.


4.7 Cenários práticos e problemas comuns

Nada aparece no terminal

  • Confirme a porta serial correta (/dev/ttyACM*)
  • Verifique baudrate configurado pelo sample
  • Use:minicom -D /dev/ttyACM0

Build demora mais

  • Normal: o kernel RTOS completo está sendo compilado
  • O sample threads ativa mais subsistemas do Zephyr

Diferença de comportamento entre placas

  • Esperado: clock, memória e Device Tree mudam
  • O código da aplicação permanece o mesmo

4.8 O que este exemplo consolida

Com este segundo projeto, você agora compreende:

  • como o Zephyr escala de simples para complexo,
  • como reutilizar o mesmo fluxo de build,
  • como separar builds por placa,
  • e como o Zephyr se comporta como RTOS real.

Na próxima seção, vamos comparar os dois cenários, discutir boas práticas de organização de projetos Zephyr e apresentar variações comuns de uso em projetos reais.

Excelente, vamos consolidar o aprendizado e elevar o nível de entendimento arquitetural.


Seção 5 – Comparando os dois cenários e boas práticas com Zephyr

Agora que você já executou dois builds reais, em duas placas diferentes, usando dois níveis distintos de complexidade, é o momento ideal para analisar o que muda, o que permanece igual e como isso se traduz em boas práticas para projetos reais com Zephyr.

Esta seção é essencial para transformar o “tutorial executado” em conhecimento estruturado.


5.1 O que NÃO muda entre os projetos

Independentemente da placa ou do exemplo utilizado, alguns pontos permanecem invariáveis:

  1. Fluxo de build
    • Sempre via west build
    • Sempre fora da árvore do código-fonte
    • Sempre com seleção explícita da placa (-b)
  2. Organização
    • Um diretório de build por placa
    • Código-fonte reutilizado sem modificação
    • Builds isolados e reproduzíveis
  3. Ferramentas
    • Mesma toolchain
    • Mesmo CMake
    • Mesmo Ninja
    • Mesmo OpenOCD / ST-Link

Isso é um dos maiores diferenciais do Zephyr:
👉 a complexidade da aplicação não altera o fluxo de trabalho.


5.2 O que MUDA entre o blinky e o threads

AspectoBlinky (F411RE)Threads (F429ZI)
Tipo de aplicaçãoFirmware simplesRTOS completo
Uso do kernelMínimoIntensivo
ConcorrênciaNãoSim
MemóriaBaixaModerada
Tempo de buildCurtoMaior
EscalonadorPraticamente ociosoAtivo constantemente

Essa comparação deixa claro que o Zephyr:

  • não “força” RTOS quando não é necessário,
  • mas escala naturalmente quando o sistema cresce.

5.3 Organização recomendada para projetos reais

Uma estrutura típica e bem organizada para projetos com Zephyr seria:

zephyr-workspace/
├── applications/
│   ├── app_sensor/
│   ├── app_gateway/
│   └── app_control/
├── builds/
│   ├── nucleof411re/
│   ├── nucleof429zi/
│   └── custom_board/
├── zephyr/
└── modules/

Nessa abordagem:

  • applications/ contém apenas código
  • builds/ contém apenas artefatos de compilação
  • cada placa tem seu próprio diretório
  • o mesmo aplicativo pode ser compilado para múltiplos hardwares

Esse modelo é altamente recomendado para:

  • produtos comerciais,
  • firmware industrial,
  • projetos acadêmicos reprodutíveis,
  • e pipelines de CI/CD.

5.4 Cenários comuns no dia a dia com Zephyr

Cenário 1 – Uma aplicação, várias placas

Você pode compilar a mesma aplicação para:

  • NUCLEO-F411RE
  • NUCLEO-F429ZI
  • uma placa customizada

Sem alterar uma linha do código da aplicação.


Cenário 2 – Evolução progressiva

Um projeto pode começar como:

  • blinky → validação de hardware
  • depois virar um threads → multitarefa
  • depois incluir drivers, rede, sensores, etc.

Tudo isso sem “reiniciar” o projeto.


Cenário 3 – Debug e validação

Como os builds são separados:

  • você pode manter builds antigos,
  • comparar binários,
  • validar regressões,
  • e depurar problemas específicos de hardware.

5.5 Erros comuns de iniciantes (e como evitar)

❌ Criar um único diretório de build para todas as placas
✅ Um diretório por placa

❌ Copiar samples para dentro do projeto
✅ Referenciar samples diretamente

❌ Alterar código do kernel
✅ Configurar via Kconfig e Device Tree

❌ Depender de IDE proprietária
✅ Usar linha de comando como base


5.6 O que vem depois dos “primeiros passos”

Após dominar o que foi apresentado até aqui, os próximos passos naturais no Zephyr são:

  • criação de aplicações próprias (fora de samples)
  • entendimento profundo de Kconfig
  • uso de Device Tree overlays
  • configuração de drivers
  • integração com FreeRTOS-like concepts (mutex, semáforos, filas)
  • debug avançado com west debug

Esses temas já entram no nível intermediário a avançado e podem ser explorados em tutoriais específicos.


Conclusão, resumo prático e material SEO

Chegamos ao final deste tutorial de primeiros passos com o Zephyr RTOS, percorrendo desde a preparação do ambiente até a execução de exemplos reais em duas placas STM32 amplamente utilizadas. O objetivo não foi apenas “fazer funcionar”, mas construir entendimento técnico sólido sobre o fluxo de trabalho do Zephyr.


6.1 Resumo prático do que foi aprendido

Ao longo do tutorial, você aprendeu de forma progressiva:

  • O que é o Zephyr RTOS e por que ele se diferencia de abordagens tradicionais
  • Como preparar corretamente o ambiente de desenvolvimento
  • O papel central da ferramenta west
  • O conceito de build fora da árvore
  • Como organizar builds por placa
  • Como compilar e gravar firmware para:
    • NUCLEO-F411RE usando o sample blinky
    • NUCLEO-F429ZI usando o sample threads
  • Como o Zephyr escala naturalmente de aplicações simples para sistemas multitarefa
  • Boas práticas de organização aplicáveis a projetos reais, acadêmicos e industriais

Mais importante: você percebeu que o fluxo de desenvolvimento não muda à medida que a aplicação cresce. Essa estabilidade é um dos maiores ganhos do Zephyr em projetos de médio e grande porte.


6.2 Comparação implícita com outros ecossistemas

Sem entrar em disputas diretas, fica claro que o Zephyr:

  • evita o acoplamento excessivo a fabricantes,
  • promove reutilização real de código,
  • facilita automação e CI/CD,
  • e força o desenvolvedor a pensar em arquitetura desde cedo.

Para quem já trabalha com FreeRTOS, o Zephyr não substitui conceitos — ele os organiza de forma mais sistemática, integrando kernel, drivers e configuração de hardware em um único modelo coerente.


6.3 Quando o Zephyr é a escolha certa

O Zephyr é especialmente indicado quando:

  • o projeto precisa escalar para múltiplas placas,
  • há preocupação com manutenção a longo prazo,
  • o sistema exige multitarefa real,
  • existe interesse em portabilidade e padronização,
  • ou o projeto evoluirá para IoT, conectividade ou segurança.

Para projetos muito simples, ele pode parecer “grande demais”. Para projetos médios e grandes, ele rapidamente se paga.

0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

Debug, Tracing e Análise Temporal no FreeRTOS: Monitoramento Avançado de Tasks, Watermark e Confiabilidade em Tempo RealDebug, Tracing e Análise Temporal no FreeRTOS: Monitoramento Avançado de Tasks, Watermark e Confiabilidade em Tempo Real

Aprenda como aplicar debug estruturado, tracing, análise temporal e watermark no FreeRTOS para monitorar tasks, medir WCET, detectar jitter, prevenir stack overflow e aumentar a confiabilidade de sistemas embarcados em

0
Adoraria saber sua opinião, comente.x