STM32 韌體 (CubeMX/HAL + PlatformIO, ST-Link)
同時載入 embedded-c-cpp 以獲取編碼標準、架構、單元測試與通用除錯。此技能負責 STM32 相關的特定部分。
首先,識別專案
在撰寫程式碼之前,請先閱讀儲存庫。以下事實會改變答案:
| 尋找內容 | 位置 |
|---|---|
| 確切零件編號 (例如 STM32G431KBT6) 與系列 (F0/F1/F4/G0/G4/L4/H7/U5...) | .ioc (Mcu.UserName), platformio.ini board =, 啟動檔案名稱 |
| 專案類型 | .ioc + .project/.cproject → CubeIDE; .ioc + CMakeLists.txt/CMakePresets.json → CubeMX CMake; platformio.ini → PlatformIO |
| HAL vs LL vs 暫存器 | Drivers/STM32xx_HAL_Driver, #include "stm32xx_ll_*.h", CubeMX 每個周邊設備的「進階設定」 |
| RTOS | Middlewares/Third_Party/FreeRTOS, cmsis_os.h |
| 時脈 | main.c 中的 SystemClock_Config(), .ioc 的 RCC 章節;Nucleo 板通常從 ST-Link 饋入 8 MHz HSE (HSE 繞接模式) |
| 探針 | ST-Link (在 Nucleo/Discovery 上為內建,或獨立式 ST-Link V2/V3) |
系列非常重要:核心 (M0+/M3/M4F/M7/M33)、是否有 FPU、快閃記憶體寫入粒度 (F1 為半字、G4/L4 為雙字、H7 為快閃字)、DMA (G0/G4/L4+/H7 有 DMAMUX)、快取 (F7/H7)。當不確定暫存器或周邊設備的細節時,請說明應在參考手冊 (RM) 中檢查的項目,而不是猜測。
防止工作遺失的 CubeMX 規則
CubeMX 每次都會重新產生 main.c、stm32xx_it.c、stm32xx_hal_msp.c 與初始化檔案。只有介於 /* USER CODE BEGIN x */ 與 /* USER CODE END x */ 之間的文字會被保留。
- 將應用邏輯放在您自己的檔案 (
App/app.c、App/app.h或 C++ 使用app.cpp) 中,並從USER CODE BEGIN 2以及while (1)的 USER CODE 區塊呼叫app_init()/app_loop()。 - 在
.ioc檔案中修改腳位、時脈、DMA、中斷與周邊設備參數,然後重新產生——而不是直接編輯MX_xxx_Init()(它會被覆寫,且.ioc檔案會與程式碼不一致)。 - 提交
.ioc檔案。它是硬體配置的唯一真實來源。 - 在「專案管理員」→「程式碼產生器」中啟用「每個周邊設備的初始化產生為一對 .c/.h 檔案」:可縮小
main.c,並使差異比較更清晰。 - 詳細資訊與 C++ 整合:請參閱
references/cubemx-hal.md。
建置、燒錄、除錯
選擇符合專案的路徑;完整的指令請參閱 references/build-flash-debug.md。
| 專案 | 建置 | 燒錄 (ST-Link) | 除錯 |
|---|---|---|---|
| CubeIDE | IDE,或無頭模式 stm32cubeide ... -build | IDE,或 STM32_Programmer_CLI -c port=SWD -w app.elf -v -rst | CubeIDE 除錯器 (ST-LINK GDB server) |
| CubeMX CMake (VS Code) | cmake --preset Debug && cmake --build --preset Debug | STM32_Programmer_CLI 或 OpenOCD | VS Code STM32 擴充功能 / OpenOCD + GDB |
| PlatformIO | pio run -e <env> | pio run -e <env> -t upload (upload_protocol = stlink) | pio debug / VS Code (debug_tool = stlink) |
燒錄會改變開發板狀態:在執行上傳前,請與使用者確認連接的是哪個開發板/探針,並且絕不能在未經明確確認的情況下執行大量抹除、選項位元組或讀取保護指令 (RDP level 2 是永久性的)。
HAL 使用方式 — 最耗時常見錯誤
- I2C 位址需左移傳遞:
HAL_I2C_Master_Transmit(&hi2c1, 0x76 << 1, ...)。 - HAL 回呼函式在中斷上下文中執行 (
HAL_UART_RxCpltCallback、HAL_GPIO_EXTI_Callback、HAL_TIM_PeriodElapsedCallback):請保持簡短,不要使用HAL_Delay,不要進行阻塞式傳輸。 HAL_Delay/HAL_GetTick需要 SysTick:從更高優先級的中斷服務常式中呼叫它們,或在中斷停用時呼叫它們,會導致系統掛起。使用 FreeRTOS 時,請在 CubeMX 中將 SYS → Timebase Source 設定為基本計時器 (TIM6/TIM7)。- UART 接收:使用
HAL_UARTEx_ReceiveToIdle_DMA(可變長度幀) 或中斷模式搭配環形緩衝區;在回呼函式以及HAL_UART_ErrorCallback中重新啟動接收 (溢位會無聲地停止接收)。 - F7/H7 上的 DMA 緩衝區 (資料快取):傳送前清除,接收後無效化,需 32 位元組對齊與大小;在 H7 上,DMA1/2 無法存取 DTCM RAM — 請將緩衝區放置在 D2/AXI SRAM 中。
- 檢查每個 HAL 函式的回傳值 (
HAL_OK、HAL_ERROR、HAL_BUSY、HAL_TIMEOUT);HAL_BUSY通常表示先前的傳輸從未完成。 - 逾時設定:在生產路徑中絕不使用
HAL_MAX_DELAY。 - 更多模式 (UART DMA、ADC DMA、計時器/PWM、EXTI、低功耗、快閃記憶體寫入、看門狗、重置原因):請參閱
references/cubemx-hal.md。
當系統崩潰或無法啟動時
- HardFault / MemManage / BusFault / UsageFault → 請參閱
references/faults-and-recovery.md(讀取 CFSR/HFSR、堆疊的程式計數器、用addr2line解碼)。 - ST-Link 無法連接 ("No target found"、"DEV_TARGET_HELD_UNDER_RESET") → 在重置狀態下連接;檢查
.ioc中是否將 SWD 腳位重新配置為 GPIO;檢查 BOOT0 腳位;檢查 RDP 等級 → 請參閱references/faults-and-recovery.md。 - 在
SystemClock_Config中掛起 → HSE 不存在/繞接模式不符、PLL 設定錯誤、快閃記憶體延遲設定過低。 - 周邊設備無反應 → 時脈已啟用?腳位替代功能 (AF) 正確?
MX_xxx_Init是否已被呼叫且順序正確 (先初始化 DMA,再初始化使用它的周邊設備)?
參考檔案
| 檔案 | 閱讀時機 |
|---|---|
references/cubemx-hal.md | 在 CubeMX 專案中撰寫/審查程式碼、C++ 整合、周邊設備模式、低功耗、快閃記憶體/EEPROM 模擬、看門狗、重置原因 |
references/build-flash-debug.md | 工具鏈安裝、從命令列建置、STM32 的 PlatformIO 設定、燒錄、GDB/OpenOCD、printf/SWV 紀錄、大小分析 |
references/faults-and-recovery.md | HardFault 與其他錯誤、開發板無法連接、選項位元組與讀取保護、救援看似變磚的開發板 |