Firmware STM32 (CubeMX/HAL + PlatformIO, ST-Link)
Carregue também embedded-c-cpp para padrões de codificação, arquitetura, testes unitários e depuração geral. Esta skill contém as partes específicas para STM32.
Primeiro, identifique o projeto
Leia o repositório antes de escrever código. Esses fatos alteram a resposta:
| Encontre | Onde |
|---|---|
| Peça exata (ex.: STM32G431KBT6) e família (F0/F1/F4/G0/G4/L4/H7/U5...) | .ioc (Mcu.UserName), platformio.ini board =, nome do arquivo de startup |
| Tipo de projeto | .ioc + .project/.cproject → CubeIDE; .ioc + CMakeLists.txt/CMakePresets.json → CubeMX CMake; platformio.ini → PlatformIO |
| HAL vs LL vs registradores | Drivers/STM32xx_HAL_Driver, #include "stm32xx_ll_*.h", "Configurações avançadas" do CubeMX por periférico |
| RTOS | Middlewares/Third_Party/FreeRTOS, cmsis_os.h |
| Clocks | SystemClock_Config() em main.c, seção RCC do .ioc; placas Nucleo geralmente alimentam HSE de 8 MHz a partir do ST-Link (HSE bypass) |
| Sonda | ST-Link (embarcado nas Nucleo/Discovery, ou ST-Link V2/V3 autônomo) |
A família é muito importante: núcleos (M0+/M3/M4F/M7/M33), FPU ou não, granularidade de gravação flash (half-word no F1, double-word no G4/L4, flash-word no H7), DMA (DMAMUX no G0/G4/L4+/H7), caches (F7/H7). Quando não tiver certeza sobre um registrador ou detalhe de periférico, diga o que verificar no manual de referência (RM) em vez de adivinhar.
As regras do CubeMX que evitam perda de trabalho
O CubeMX regenera main.c, stm32xx_it.c, stm32xx_hal_msp.c e arquivos de inicialização toda vez. Somente o texto entre /* USER CODE BEGIN x */ e /* USER CODE END x */ sobrevive.
- Coloque a lógica da aplicação em seus próprios arquivos (
App/app.c,App/app.houapp.cpppara C++) e chameapp_init()/app_loop()a partir deUSER CODE BEGIN 2e do blocoUSER CODEdentro dowhile (1). - Altere pinos, clocks, DMA, interrupções e parâmetros de periféricos no
.ioc, depois regenere — não edite as funçõesMX_xxx_Init()(elas serão sobrescritas, e o.iocdeixará de corresponder ao código). - Faça commit do arquivo
.ioc. Ele é a fonte da verdade para a configuração de hardware. - Ative "Generate peripheral initialization as a pair of .c/.h files per peripheral" em Project Manager → Code Generator:
main.cmenor, diffs mais limpos. - Detalhes e integração com C++:
references/cubemx-hal.md.
Compilação, gravação, depuração
Escolha o caminho correspondente ao projeto; comandos completos em references/build-flash-debug.md.
| Projeto | Compilar | Gravar (ST-Link) | Depurar |
|---|---|---|---|
| CubeIDE | IDE, ou headless stm32cubeide ... -build | IDE, ou STM32_Programmer_CLI -c port=SWD -w app.elf -v -rst | Depurador do CubeIDE (servidor GDB ST-LINK) |
| CubeMX CMake (VS Code) | cmake --preset Debug && cmake --build --preset Debug | STM32_Programmer_CLI ou OpenOCD | Extensão STM32 do VS Code / OpenOCD + GDB |
| PlatformIO | pio run -e <env> | pio run -e <env> -t upload (upload_protocol = stlink) | pio debug / VS Code (debug_tool = stlink) |
Gravar altera a placa: confirme com o usuário qual placa/sonda está conectada antes de executar um upload, e nunca execute apagamento em massa, option bytes ou comandos de proteção contra leitura sem confirmação explícita (nível RDP 2 é permanente).
Uso de HAL — os erros que mais custam tempo
- Endereços I2C são passados deslocados à esquerda:
HAL_I2C_Master_Transmit(&hi2c1, 0x76 << 1, ...). - Callbacks HAL executam em contexto de interrupção (
HAL_UART_RxCpltCallback,HAL_GPIO_EXTI_Callback,HAL_TIM_PeriodElapsedCallback): mantenha-as curtas, semHAL_Delay, sem transmissores bloqueantes. HAL_Delay/HAL_GetTickprecisam do SysTick: chamá-las de uma ISR de prioridade mais alta ou com interrupções desabilitadas trava o sistema. Com FreeRTOS, configure a Fonte de Timebase do SYS para um timer básico (TIM6/TIM7) no CubeMX.- Recepção UART: use
HAL_UARTEx_ReceiveToIdle_DMA(quadros de tamanho variável) ou modo de interrupção com buffer circular; reinicie a recepção no callback e emHAL_UART_ErrorCallback(um estouro de recepção para a recepção silenciosamente). - Buffers DMA no F7/H7 (cache de dados): limpe antes de TX, invalide após RX, alinhados e com tamanho múltiplo de 32 bytes; no H7, DMA1/2 não alcançam a DTCM RAM — coloque buffers na D2/AXI SRAM.
- Verifique o valor de retorno de toda chamada HAL (
HAL_OK,HAL_ERROR,HAL_BUSY,HAL_TIMEOUT); umHAL_BUSYgeralmente significa que uma transferência anterior nunca terminou. - Timeouts: nunca use
HAL_MAX_DELAYem caminhos de produção. - Mais padrões (UART DMA, ADC DMA, timers/PWM, EXTI, baixo consumo, gravação flash, watchdog, causa de reset):
references/cubemx-hal.md.
Quando trava ou não inicia
- HardFault / MemManage / BusFault / UsageFault →
references/faults-and-recovery.md(leia CFSR/HFSR, PC empilhado, decodifique comaddr2line). - ST-Link não consegue conectar ("No target found", "DEV_TARGET_HELD_UNDER_RESET") → conecte sob reset; verifique se os pinos SWD não foram reconfigurados como GPIO no
.ioc; BOOT0; nível RDP →references/faults-and-recovery.md. - Trava em
SystemClock_Config→ HSE ausente/incompatibilidade de bypass, PLL errado, latência flash muito baixa. - Periférico silencioso → clock habilitado? AF do pino correta?
MX_xxx_Initfoi realmente chamada e na ordem correta (inicialização do DMA antes do periférico que o utiliza)?
Arquivos de referência
| Arquivo | Leia quando |
|---|---|
references/cubemx-hal.md | Escrevendo/revisando código em um projeto CubeMX, integração C++, padrões de periféricos, baixo consumo, emulação flash/EEPROM, watchdog, causa de reset |
references/build-flash-debug.md | Instalação da toolchain, compilação via CLI, configuração do PlatformIO para STM32, gravação, GDB/OpenOCD, registro printf/SWV, análise de tamanho |
references/faults-and-recovery.md | HardFault e outras falhas, placa não conecta, option bytes e proteção contra leitura, recuperação de placa aparentemente brickada |