STM32-Firmware (CubeMX/HAL + PlatformIO, ST-Link)
Lade auch embedded-c-cpp für Codierungsstandards, Architektur, Unit-Tests und allgemeines Debugging. Dieses Skill enthält die STM32-spezifischen Teile.
Identifiziere zuerst das Projekt
Lies das Repository, bevor du Code schreibst. Diese Fakten ändern die Antwort:
| Finde | Wo |
|---|---|
| Exakter Bauteil (z.B. STM32G431KBT6) und Familie (F0/F1/F4/G0/G4/L4/H7/U5...) | .ioc (Mcu.UserName), platformio.ini board =, Startup-Dateiname |
| Projekttyp | .ioc + .project/.cproject → CubeIDE; .ioc + CMakeLists.txt/CMakePresets.json → CubeMX CMake; platformio.ini → PlatformIO |
| HAL vs. LL vs. Register | Drivers/STM32xx_HAL_Driver, #include "stm32xx_ll_*.h", CubeMX "Erweiterte Einstellungen" pro Peripherie |
| RTOS | Middlewares/Third_Party/FreeRTOS, cmsis_os.h |
| Taktgeber | SystemClock_Config() in main.c, .ioc RCC-Abschnitt; Nucleo-Boards liefern normalerweise HSE 8 MHz vom ST-Link (HSE Bypass) |
| Probe | ST-Link (on-board auf Nucleo/Discovery, oder ST-Link V2/V3 eigenständig) |
Die Familie ist sehr wichtig: Kerne (M0+/M3/M4F/M7/M33), FPU oder nicht, Flash-Schreibgranularität (Halbwort auf F1, Doppelwort auf G4/L4, Flash-Wort auf H7), DMA (DMAMUX auf G0/G4/L4+/H7), Caches (F7/H7). Wenn du dir bei einem Register- oder Peripheriedetail unsicher bist, sage lieber, was man im Referenzhandbuch (RM) nachschlagen soll, anstatt zu raten.
Die CubeMX-Regeln, die Arbeitsverlust verhindern
CubeMX generiert main.c, stm32xx_it.c, stm32xx_hal_msp.c und Initialisierungsdateien bei jeder Regeneration neu. Nur Text zwischen /* USER CODE BEGIN x */ und /* USER CODE END x */ bleibt erhalten.
- Lege die Anwendungslogik in eigenen Dateien ab (
App/app.c,App/app.hoderapp.cppfür C++) und rufeapp_init()/app_loop()ausUSER CODE BEGIN 2und demwhile (1)USER-CODE-Block auf. - Ändere Pins, Taktgeber, DMA, Interrupts und Peripherieparameter in der
.ioc-Datei, dann generiere neu – nicht, indem duMX_xxx_Init()bearbeitest (das wird überschrieben, und die.ioc-Datei passt nicht mehr zum Code). - Committe die
.ioc-Datei. Sie ist die Quelle der Wahrheit für die Hardwarekonfiguration. - Aktiviere "Generiere Peripherie-Initialisierung als Paar von .c/.h-Dateien pro Peripherie" unter Projektmanager → Code-Generator: kleinere
main.c, sauberere Diffs. - Details und C++-Integration:
references/cubemx-hal.md.
Bauen, Flashen, Debuggen
Wähle den Pfad, der zum Projekt passt; vollständige Befehle in references/build-flash-debug.md.
| Projekt | Bauen | Flashen (ST-Link) | Debuggen |
|---|---|---|---|
| CubeIDE | IDE, oder Headless stm32cubeide ... -build | IDE, oder STM32_Programmer_CLI -c port=SWD -w app.elf -v -rst | CubeIDE-Debugger (ST-LINK GDB-Server) |
| CubeMX CMake (VS Code) | cmake --preset Debug && cmake --build --preset Debug | STM32_Programmer_CLI oder OpenOCD | VS Code STM32-Erweiterung / OpenOCD + GDB |
| PlatformIO | pio run -e <env> | pio run -e <env> -t upload (upload_protocol = stlink) | pio debug / VS Code (debug_tool = stlink) |
Flashen verändert das Board: Bestätige mit dem Benutzer, welches Board/welcher Probe angeschlossen ist, bevor du einen Upload ausführst, und führe niemals Massenlöschung, Option-Byte- oder Leseschutzbefehle ohne explizite Bestätigung aus (RDP Level 2 ist permanent).
HAL-Nutzung – die Fehler, die am meisten Zeit kosten
- I2C-Adressen werden linksverschoben übergeben:
HAL_I2C_Master_Transmit(&hi2c1, 0x76 << 1, ...). - HAL-Callbacks laufen im Interrupt-Kontext (
HAL_UART_RxCpltCallback,HAL_GPIO_EXTI_Callback,HAL_TIM_PeriodElapsedCallback): halte sie kurz, keinHAL_Delay, keine blockierenden Sendevorgänge. HAL_Delay/HAL_GetTickbenötigen SysTick: Ein Aufruf aus einem höherprioren ISR oder bei deaktivierten Interrupts führt zu einem Stillstand. Verwende bei FreeRTOS in CubeMX für SYS → Timebase Source einen Basis-Timer (TIM6/TIM7).- UART-Empfang: Verwende
HAL_UARTEx_ReceiveToIdle_DMA(variable Rahmenlängen) oder Interrupt-Modus in einen Ringpuffer; starte den Empfang im Callback und inHAL_UART_ErrorCallbackneu (ein Überlauf stoppt den Empfang stillschweigend). - DMA-Puffer auf F7/H7 (Daten-Cache): Vor TX bereinigen, nach RX ungültig machen, 32-Byte-ausgerichtet und -groß; auf H7 können DMA1/2 nicht auf DTCM-RAM zugreifen – platziere Puffer im D2/AXI-SRAM.
- Überprüfe den Rückgabewert jedes HAL-Aufrufs (
HAL_OK,HAL_ERROR,HAL_BUSY,HAL_TIMEOUT); einHAL_BUSYbedeutet normalerweise, dass eine vorherige Übertragung nie beendet wurde. - Timeouts: Niemals
HAL_MAX_DELAYin Produktionspfaden. - Weitere Muster (UART DMA, ADC DMA, Timer/PWM, EXTI, Low Power, Flash-Schreibvorgänge, Watchdog, Reset-Ursache):
references/cubemx-hal.md.
Wenn es abstürzt oder nicht startet
- HardFault / MemManage / BusFault / UsageFault →
references/faults-and-recovery.md(CFSR/HFSR lesen, gestackten PC decodieren mitaddr2line). - ST-Link kann keine Verbindung herstellen ("No target found", "DEV_TARGET_HELD_UNDER_RESET") → Verbindung unter Reset herstellen; überprüfen, ob SWD-Pins in der
.ioc-Datei nicht als GPIO umkonfiguriert wurden; BOOT0; RDP-Level →references/faults-and-recovery.md. - Hängen in
SystemClock_Config→ HSE nicht vorhanden/Bypass-Fehlanpassung, falscher PLL, Flash-Latenz zu niedrig. - Peripherie stumm → Taktgeber aktiviert? Pin-AF korrekt?
MX_xxx_Inittatsächlich aufgerufen und in der richtigen Reihenfolge (DMA-Init vor der Peripherie, die es verwendet)?
Referenzdateien
| Datei | Lesen, wenn |
|---|---|
references/cubemx-hal.md | Code in einem CubeMX-Projekt schreiben/überprüfen, C++-Integration, Peripheriemuster, Low Power, Flash/EEPROM-Emulation, Watchdog, Reset-Ursache |
references/build-flash-debug.md | Toolchain-Installation, Build von der CLI, PlatformIO-Setup für STM32, Flashen, GDB/OpenOCD, printf/SWV-Logging, Größenanalyse |
references/faults-and-recovery.md | HardFault und andere Fehler, Board stellt keine Verbindung her, Option-Bytes und Leseschutz, Wiederherstellung eines scheinbar unbrauchbaren Boards |