跳到正文

Wiki

外掛使用教程

約 31 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

1.CubeMX安裝FW

點選Help

選Manage embedded software packages,把STM32F1,F4,H7的第一個最新的韌體勾上。

點install

可以不用登入賬號選do not ask me again

然後等下載和安裝完

下載好就行了。

2.VScode安裝外掛

然後開啟VScode,在終端輸入下面的命令

code

然後可以配置一個環境單獨給CubeIDE外掛使用,避免和預設環境衝突。

alt text

進行一些設定,自己按習慣來,不懂的暫時按我的來也行

alt text

選中STM32

alt text

然後安裝一些外掛

找到下面這個STM32CubeIDE for Visual Studio Code外掛安裝

alt text

右邊彈這個提示要選擇安裝(要有良好的科學網路)

alt text

緊接著會進行一些環境的安裝

alt text

也可以再安裝一些其他的外掛,比如Codex等外掛 這些看你自己啦

alt text

3.OpenOCD使用事項

3.1.選擇debugger和mcu型號

OpenOCD 一般通過 .cfg 配置檔案確定:使用什麼偵錯程式 + 連線什麼 MCU

openocd -f interface/调试器.cfg -f target/芯片系列.cfg

第一個引數:看你用什麼偵錯程式

偵錯程式 OpenOCD 配置 說明
ST-Link V2 / V2-1 / V3 "interface/stlink.cfg" STM32 最常見
DAPLink "interface/cmsis-dap.cfg" DAPLink 實現 CMSIS-DAP
CMSIS-DAP "interface/cmsis-dap.cfg" 很多第三方偵錯程式使用
J-Link "interface/jlink.cfg" SEGGER J-Link
FTDI 類 JTAG/SWD "interface/ftdi/xxx.cfg" 根據具體硬體選擇

第二個引數:看 STM32 哪個系列

STM32 系列 常見型號示例 OpenOCD Target
STM32C0 C011、C031、C071 "target/stm32c0x.cfg"
STM32F0 F030、F072 "target/stm32f0x.cfg"
STM32F1 F103C8、F103RC "target/stm32f1x.cfg"
STM32F2 F205、F207 "target/stm32f2x.cfg"
STM32F3 F303、F334 "target/stm32f3x.cfg"
STM32F4 F405、F407、F429、F446 "target/stm32f4x.cfg"
STM32F7 F746、F767 "target/stm32f7x.cfg"
STM32G0 G030、G070、G0B1 "target/stm32g0x.cfg"
STM32G4 G431、G474 "target/stm32g4x.cfg"
STM32H5 H503、H563、H573 "target/stm32h5x.cfg"
STM32H7 H743、H750、H745、H747 "target/stm32h7x.cfg"
STM32H7RS H7R3、H7S3 "target/stm32h7rsx.cfg"
STM32L0 L031、L073 "target/stm32l0.cfg"
STM32L1 L151、L152 "target/stm32l1.cfg"
STM32L4 / L4+ L432、L476、L496、L4R5 "target/stm32l4x.cfg"
STM32L5 L552、L562 "target/stm32l5x.cfg"
STM32N6 N657 等 "target/stm32n6x.cfg"
STM32U0 U031、U073 "target/stm32u0x.cfg"
STM32U3 U385 等 "target/stm32u3x.cfg"
STM32U5 U575、U585、U5A5 "target/stm32u5x.cfg"
STM32WB WB55 等 "target/stm32wbx.cfg"
STM32WBA2 WBA2xx "target/stm32wba2x.cfg"
STM32WBA5 WBA5xx "target/stm32wba5x.cfg"
STM32WBA6 WBA6xx "target/stm32wba6x.cfg"
STM32WL WL55、WLE5 "target/stm32wlx.cfg"
STM32C5 C53、C54、C55、C56、C59、C5A 見下方說明

STM32C5 要特別注意:

現在不要把 C5 寫死成target/stm32c5x.cfg, 原因是 STM32C5 的 OpenOCD 支援非常新。2026 年 7 月才有 stm32c5x.cfg 支援補丁提交到 OpenOCD Gerrit;補丁里的檔名確實就是target/stm32c5x.cfg。 但是現在還沒完全發行到OpenOCD,需要等一段時間。

3.2.測試裝置連線

我們用的stm32f103c8和st-link:

所以用

openocd -f interface/stlink.cfg -f target/stm32f1x.cfg

可以插上之後測試一波:

照上圖所示,已經連線成功了。

幾個關鍵日誌分別說明:

Info : STLINK V2J48S7 ...
→ OpenOCD 正常识别 ST-Link。

Info : Target voltage: 3.150483
→ 目标板供电正常,约 3.15 V。

Info : SWD DPIDR 0x1ba01477
→ SWD 通信已经建立。

Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
→ 已经真正识别并连接 MCU 核心。

Info : target has 6 breakpoints, 4 watchpoints
→ Cortex-M3 的硬件断点/数据观察点正常。

Info : Examination succeed
→ Target 初始化成功。

最后:
Info : [stm32f1x.cpu] starting gdb server on 3333
Info : Listening on port 3333 for gdb connections
→ OpenOCD 的 GDB Server 已经正式启动,可以给 VS Code / STM32Cube 调试器连接了。

4.工程建立與測試

4.1.使用CubeMX建立工程

點選進入微控制器挑選的按鈕

搜尋對應晶片,並雙擊對應晶片選項。

進行一些配置,以下都是很基礎的東西,你在看這個影片前肯定都會了

隨便開一個IO用來測試,比如LED的GPIO

FreeRTOS也要配置一下。

本例在使用者目錄中實現 StartDefaultTask() 來替換預設任務函式,需要CubeMX生成的同名函式為弱定義。 可以在FreeRTOS的 Tasks and Queues 中,將 defaultTask 的 Code Generation Option 設為 As weak,重新生成後確認該函式帶有 __weak,避免兩個普通定義產生衝突。參考ST社群說明。

這些資料夾也要配置好,最後Toolchain選擇CMake,編譯器選擇GCC(6.14.1及之前沒有選擇編譯器這個選項很正常)

4.2.對工程進行配置與編譯

在工程資料夾開啟終端(或者直接在此處開啟VScode也行)

alt text

code .

開啟VScode後記得切到`STM32·的配置

alt text

選擇這裡的Yes進行配置CMake預設

alt text

一般選Debug即可

alt text

可能談一個很長的對話方塊,是這個STM32Cube Core提示的,你直接點yes開始下載(這是自動部署各種環境的)

反正右下角是STM32Cube Core提示讓你安裝的,你安就完了,每個版本提示可能不一樣,總之安裝就完了。

等上面的環境部署完畢後,

找個C語言的程式碼檔案開啟,然後右下角會提示安裝一個C/C++外掛,這個可以安裝也可以不安裝,他也帶程式碼提示,但是他的程式碼提示對比自帶的clangd簡直是弱爆了,如果你是新手,你不會設定程式碼提示,建議按我下面的操作來,直接別裝這個C/C++外掛。

預設用的是clangd程式碼提示

你可以測試一下程式碼提示,是不是很強。

alt text

編譯的話,圖中的這倆build都可以

alt text

4.3.移植作者tungchiahui的標準C/C++工程模板

用git clone命令克隆倉庫:https://github.com/tungchiahui/STM32HAL_CMake_CPP_Template

git clone https://github.com/tungchiahui/STM32HAL_CMake_CPP_Template.git

把倉庫裡的除了.git以外的東西都複製到我們的STM32工程根目錄。

alt text

模板中的使用者程式碼按功能模組組織,每個模組的 .cpp、.hpp(或 .c、.h)放在同一個資料夾裡。複製後的目錄結構如下:

STM32工程根目录/
├── applications/
│   └── main/
│       ├── cpp_interface.cpp
│       └── cpp_interface.h
├── bsp/
│   └── boards/
│       ├── common/
│       │   └── struct_typedef.h
│       └── delay/
│           ├── bsp_delay.cpp
│           └── bsp_delay.hpp
└── cmake/
    ├── stm32cubemx/            # CubeMX生成的配置
    └── user/
        └── CMakeLists.txt     # 用户代码的配置

cmake/user/CMakeLists.txt 已經把 applications 和 bsp/boards 加入標頭檔案搜尋路徑,所以引用使用者標頭檔案時統一使用“模組目錄/標頭檔案名”的寫法:

#include "main/cpp_interface.h"
#include "delay/bsp_delay.hpp"
#include "common/struct_typedef.h"

在這兩個目錄下新增模組時,沿用這個寫法即可,不需要為每個模組單獨新增標頭檔案搜尋路徑。

開啟CubeMX生成的 Core/Src/main.c,在 USER CODE BEGIN Includes 和 USER CODE END Includes 之間加上:

#include "main/cpp_interface.h"

然後在 main() 的 USER CODE BEGIN 2 和 USER CODE END 2 之間呼叫 cpp_main(),此時系統時鐘和外設已經初始化完成:

cpp_main();

注意 applications/main/cpp_interface.h 中的 isRTOS 設定:

  • 裸機使用預設值 0,業務程式碼可以寫在 cpp_main() 的無限迴圈中;
  • 使用FreeRTOS時要改成 1,使 cpp_main() 執行完初始化後返回,程式才能繼續建立任務並啟動排程器。
  • 下面沿用前面配置了FreeRTOS的工程,因此先將 isRTOS 改為 1。

然後開啟工程根目錄的 CMakeLists.txt,在CubeMX原有的 add_subdirectory(cmake/stm32cubemx) 後面新增 add_subdirectory(cmake/user),引用使用者程式碼的配置:

# Add STM32CubeMX generated sources
add_subdirectory(cmake/stm32cubemx)

# Add USER generated sources
add_subdirectory(cmake/user)

在同一個頂層 CMakeLists.txt 中,保留原有的C語言標準設定,並在 project() 之前增加C++標準設定(模板的 README-zh_CN.md 中也有說明):

# Setup compiler settings
set(CMAKE_C_STANDARD 11 CACHE STRING "C language standard")
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

set(CMAKE_CXX_STANDARD 20 CACHE STRING "C++ language standard")
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

然後在 applications 下新建 led_task 資料夾,把 led_task.cpp 和 led_task.h 都放進去:

applications/
├── main/
│   ├── cpp_interface.cpp
│   └── cpp_interface.h
└── led_task/
    ├── led_task.cpp
    └── led_task.h

applications/led_task/led_task.cpp:

#include "led_task/led_task.h"
#include "cmsis_os.h"
#include "main.h"

int32_t t;

extern "C"
void StartDefaultTask(void *argument)
{
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
    ++t;
    osDelay(500);
  }
}

applications/led_task/led_task.h:

#ifndef LED_TASK_H
#define LED_TASK_H

#include "main/cpp_interface.h"

#endif

然後開啟 cmake/user/CMakeLists.txt,把剛才新建的原始檔新增到 Applications_Src 列表中:

set(Applications_Src
    ${CMAKE_CURRENT_SOURCE_DIR}/../../applications/main/cpp_interface.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/../../applications/led_task/led_task.cpp
)

只需要登記新增的 .c、.cpp 檔案,.h、.hpp 不需要列為編譯原始檔。因為 applications 已經是標頭檔案搜尋根目錄,led_task 模組也不需要額外新增搜尋路徑。

詳細介紹(可以不看):cmake/stm32cubemx/CMakeLists.txt 由CubeMX管理,重新生成程式碼時可能更新,因此使用者程式碼的原始檔列表和標頭檔案搜尋路徑統一維護在 cmake/user/CMakeLists.txt 中,頂層 CMakeLists.txt 通過 add_subdirectory(cmake/user) 載入它。這個使用者配置檔案已經包含在模板裡,前面複製時就已經帶過來了。

大功告成,編譯一次試試。可以看到下圖,那些新加的檔案都編譯上了。

alt text

4.4.下載程式到板子

下載之前首先要先配置:

如果你不是stlink和jlink,接著往下看

按下圖的來點選,你看看你是什麼debugger,你就選哪個。

如果這裡看不到對應裝置,遇到許可權問題,請檢視Linux 下 USB 許可權問題。

可以更新下STlink的驅動:

先安裝jlink-gdbserver的bundle,如下圖所示:

alt text

4.4.2.使用openocd服務驅動原生gdb偵錯程式

當你要使用除了ST-Link和J-Link以外的偵錯程式時:

先點除錯,讓他生成launch.json:

openOCD接管選STM32Cube: STM32 Launch GDB:

然後選openocd:

過一會兒,肯定會除錯失敗,然後提示你open launch.json

然後再點STM32Cube: STM32 Launch GDB:

launch.json內容如下:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "stgdbtarget",
            "request": "launch",
            "name": "STM32Cube: Launch Generic GDB Server",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "deviceName": "${command:st-stm32-ide-debug-launch.get-device-name}",
            "deviceCore": "${command:st-stm32-ide-debug-launch.get-core-name}",
            "deviceTrustzone": "${command:st-stm32-ide-debug-launch.get-trustzone-status}",
            "serverExe": "",
            "serverParameters": [],
            "serverHost": "localhost",
            "serverPort": "",
            "serverCwd": "",
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        },
        {
            "type": "stgdbtarget",
            "request": "attach",
            "name": "STM32Cube: Launch GDB Client",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "serverHost": "localhost",
            "serverPort": "${command:st-stm32-ide-debug-launch.get-server-port}",
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        }
    ]
}

我們需要改哪裡呢?

主要是:

  • serverExe : 就填二進位制程式名 openocd或者openocd.exe
  • serverParameters :填那兩個openOCD引數,參考 openocd的兩個-f引數
  • serverHost :OpenOCD GDB Server 預設監聽 localhost,一般不用改
  • serverPort :OpenOCD 預設 GDB 埠 為 3333
  • serverCwd : 填serverExe這個二進位制程式在哪個目錄底下
  • 新增liveWatch引數(重要)
  1. serverExe:

Linux填openocd Windows填openocd.exe

  1. serverParameters按下面這個格式來:

那倆-f的引數由openocd的兩個-f引數可知:

  • interface/stlink.cfg
  • target/stm32f1x.cfg

但是除了這倆,還需要一些引數:

            "serverParameters": [                
                "-f",
                "interface/stlink.cfg",

                "-c",
                "transport select swd",

                "-f",
                "target/stm32f1x.cfg",

                "-c",
                "$_TARGETNAME configure -gdb-max-connections 2"],

這裡建議按上面這個順序排布引數:先探針 → 再通訊協議 → 再 MCU → 最後修改這個 MCU target 的引數

這裡的-c transport select xxx是選協議:

實際除錯方式 配置
STM32 常用 SWD transport select swd
JTAG transport select jtag

咱們一般都是swd,所以選transport select swd。

而這個-c $_TARGETNAME configure -gdb-max-connections 2是允許這個 OpenOCD target 同時接受最多 2 個 GDB 客戶端連線。

正常除錯已經佔了一個:

OpenOCD :3333
    ↑
    └── GDB #1
         普通 Debug

咱們還需要用到Live Watch,所以把引數設定為2之後:

                  ┌─ GDB #1:普通 Debug
STM32 ← OpenOCD ──┤
                  └─ GDB #2:Live Watch
  1. serverCwd:

用終端命令直接查詢下:

# Linux
which openocd

# Windows
where.exe openocd

Linux如上圖是/usr/bin/openocd,所以serverCwd填/usr/bin。

Windows如上圖是C:\xpack-openocd-0.12.0-7\bin\openocd.exe,所以serverCwd填C:\xpack-openocd-0.12.0-7\bin。 但是不能直接填C:\xpack-openocd-0.12.0-7\bin,因為在json中\是跳脫字元,所以傻逼Windows應該填C:/xpack-openocd-0.12.0-7/bin或者雙反斜槓C:\\xpack-openocd-0.12.0-7\\bin。

  1. 新增liveWatch引數

在serverCwd後面,runEntry前面加上:

            "liveWatch": {
                "enabled": true,
                "samplesPerSecond": "4"
            },

最後:

Linux:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "stgdbtarget",
            "request": "launch",
            "name": "STM32Cube: Launch Generic GDB Server",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "deviceName": "${command:st-stm32-ide-debug-launch.get-device-name}",
            "deviceCore": "${command:st-stm32-ide-debug-launch.get-core-name}",
            "deviceTrustzone": "${command:st-stm32-ide-debug-launch.get-trustzone-status}",
            "serverExe": "openocd",
            "serverParameters": [                
                "-f",
                "interface/stlink.cfg",

                "-c",
                "transport select swd",

                "-f",
                "target/stm32f1x.cfg",

                "-c",
                "$_TARGETNAME configure -gdb-max-connections 2"],
            "serverHost": "localhost",
            "serverPort": "3333",
            "serverCwd": "/usr/bin",
            "liveWatch": {
                "enabled": true,
                "samplesPerSecond": "4"
            },
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        },
        {
            "type": "stgdbtarget",
            "request": "attach",
            "name": "STM32Cube: Launch GDB Client",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "serverHost": "localhost",
            "serverPort": "${command:st-stm32-ide-debug-launch.get-server-port}",
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        }
    ]
}

Windows:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "stgdbtarget",
            "request": "launch",
            "name": "STM32Cube: Launch Generic GDB Server",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "deviceName": "${command:st-stm32-ide-debug-launch.get-device-name}",
            "deviceCore": "${command:st-stm32-ide-debug-launch.get-core-name}",
            "deviceTrustzone": "${command:st-stm32-ide-debug-launch.get-trustzone-status}",
            "serverExe": "openocd.exe",
            "serverParameters": [                
                "-f",
                "interface/stlink.cfg",

                "-c",
                "transport select swd",

                "-f",
                "target/stm32f1x.cfg",

                "-c",
                "$_TARGETNAME configure -gdb-max-connections 2"],
            "serverHost": "localhost",
            "serverPort": "3333",
            "serverCwd": "C:/xpack-openocd-0.12.0-7/bin",
            "liveWatch": {
                "enabled": true,
                "samplesPerSecond": "4"
            },
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        },
        {
            "type": "stgdbtarget",
            "request": "attach",
            "name": "STM32Cube: Launch GDB Client",
            "origin": "snippet",
            "cwd": "${workspaceFolder}",
            "preBuild": "${command:st-stm32-ide-debug-launch.build}",
            "program": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
            "gdb": "${command:st-stm32-ide-debug-launch.get-gdb-executable}",
            "serverHost": "localhost",
            "serverPort": "${command:st-stm32-ide-debug-launch.get-server-port}",
            "runEntry": "main",
            "imagesAndSymbols": [
                {
                    "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "imageOffset": "",
                    "symbolFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}",
                    "symbolOffset": ""
                }
            ]
        }
    ]
}

4.4.3.如何進入除錯

4.4.3.1.顯示1

如果你是下圖這樣,請按下面這樣做:

如果不是,請往下滑看下面的顯示2。

alt text

點完Run and Debug後,如下圖:

  • ST-Link選STM32cube: STM32 Launch STLink GDB Server
  • J-Link選STM32Cube: STM32 LaunchJLink GDB Server
  • openOCD接管選STM32Cube: Launch Generic GDB Server

alt text

4.4.3.2.顯示2

如果你是下圖這樣,請按下面這樣做:

alt text

你顯示上面這樣,可能是因為你已經有生成的launch.json了。(這樣直接點選就行)

alt text

4.4.4.進入除錯

然後會出現這個條,他會下載程式到板子(僅J-link) alt text

然後就成功下載了程式並進入了Debug

alt text

按照下圖所示,把你要監視的變數輸入到最頂上的框裡,就可以加入到即時監視框裡了。

結構體也可以:

4.4.5.更換偵錯程式軟體為cortex debug(可選,很沒啥必要):

4.4.5.1.安裝cortex debug外掛

在VScode裡搜尋cortex debug並安裝

4.4.5.2.進行launch.json的配置

新建.vscode/launch.json:

{
    "version": "0.2.0",

    "configurations": [
        {
            // 调试配置名称
            "name": "STM32 - OpenOCD - Cortex Debug",

            // Cortex-Debug 固定写法
            "type": "cortex-debug",

            // 下载程序并开始调试
            "request": "launch",

            // 工程工作目录
            "cwd": "${workspaceFolder}",

            // ★ 必改:编译生成的 ELF
            "executable": "${workspaceFolder}/build/Debug/TEST.elf",

            // 使用 OpenOCD
            "servertype": "openocd",

            // ★ OpenOCD 可执行文件
            // Linux 下用 which openocd 查询
            "serverpath": "/usr/bin/openocd",

            // ★ 根据调试器和 MCU 修改
            //
            // ST-Link:
            // interface/stlink.cfg
            //
            // STM32F1:
            // target/stm32f1x.cfg
            //
            // STM32F4 则是:
            // target/stm32f4x.cfg
            "configFiles": [
                "interface/stlink.cfg",
                "target/stm32f1x.cfg"
            ],

            // ★ ARM GNU Toolchain 的 bin 目录
            // 建议不要直接写 "~"
            // 用 ${env:HOME} 更稳
            "armToolchainPath": "${env:HOME}/.local/share/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin",

            // 启动后运行到 main()
            "runToEntryPoint": "main",

            // ★ Cortex Live Watch
            // OpenOCD 下可用
            // samplesPerSecond 最大 20
            // 先用 4Hz 足够
            "liveWatch": {
                "enabled": true,
                "samplesPerSecond": 4
            }


            // ============================================================
            // 以下为可选配置
            // ============================================================


            // 如果 Cortex-Debug 找不到 OpenOCD,
            // Linux:
            // which openocd
            //
            // 一般 Fedora 是:
            // /usr/bin/openocd
            //
            // "serverpath": "/usr/bin/openocd",


            // 如果 OpenOCD 找不到 interface/*.cfg 或 target/*.cfg,
            // Fedora 一般脚本目录在:
            // /usr/share/openocd/scripts
            //
            // 可以显式增加:
            //
            // "searchDir": [
            //     "/usr/share/openocd/scripts"
            // ],


            // 调试 Cortex-Debug / OpenOCD 问题:
            //
            // "showDevDebugOutput": "raw"
        }
    ]
}

目前我們要知道三件事,configFiles,executable,armToolchainPath和serverpath:

  1. configFiles:

參考 openocd的兩個-f引數

我們用的stm32f103c8和st-link: 所以"configFiles": ["interface/stlink.cfg","target/stm32f1x.cfg"]。

  1. executable:

用vscode的終端命令直接查詢下,或者直接在VScode的檔案管理器裡找:

# Linux
find build -name "*.elf"
# Windows
gci build -Recurse -File -Filter "*.elf"

注意,Windows要用powershell,不可以用cmd。

如上圖所示,在build/Debug/TEST.elf。

所以executable = ${workspaceFolder}/build/Debug/TEST.elf。

  1. armToolchainPath:

用vscode的終端命令直接查詢下:

cube bundle show --project

這個輸出說明,我在用gnu-tools-for-stm32@14.3.1+st.2

用命令找他在哪:

# Linux
find ~/.local/share/stm32cube/bundles/gnu-tools-for-stm32 \
  -type f -name "arm-none-eabi-gdb"
# Windows
gci "$env:LOCALAPPDATA\stm32cube\bundles\gnu-tools-for-stm32" `
  -Recurse -File -Filter "arm-none-eabi-gdb.exe"

注意,Windows要用powershell,不可以用cmd。

複製輸出結果:

/home/tungchiahui/.local/share/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin/arm-none-eabi-gdb

但是去掉最後的執行程式arm-none-eabi-gdb,只需要到bin即可:

/home/tungchiahui/.local/share/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin

所以armToolchainPath = /home/tungchiahui/.local/share/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin。

  1. serverpath:

用終端命令直接查詢下:

# Linux
which openocd

而Windows,你自己裝哪的你應該知道吧。。。

最終的launch.json:

{
    "version": "0.2.0",

    "configurations": [
        {
            // 调试配置名称
            "name": "STM32 - OpenOCD - Cortex Debug",

            // Cortex-Debug 固定写法
            "type": "cortex-debug",

            // 下载程序并开始调试
            "request": "launch",

            // 工程工作目录
            "cwd": "${workspaceFolder}",

            // ★ 必改:编译生成的 ELF
            "executable": "${workspaceFolder}/build/Debug/TEST.elf",

            // 使用 OpenOCD
            "servertype": "openocd",

            // ★ OpenOCD 可执行文件
            // Linux 下用 which openocd 查询
            "serverpath": "/usr/bin/openocd",

            // ★ 根据调试器和 MCU 修改
            //
            // ST-Link:
            // interface/stlink.cfg
            //
            // STM32F1:
            // target/stm32f1x.cfg
            //
            // STM32F4 则是:
            // target/stm32f4x.cfg
            "configFiles": [
                "interface/stlink.cfg",
                "target/stm32f1x.cfg"
            ],

            // ★ ARM GNU Toolchain 的 bin 目录
            // 建议不要直接写 "~"
            // 用 ${env:HOME} 更稳
            "armToolchainPath": "/home/tungchiahui/.local/share/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin",

            // 启动后运行到 main()
            "runToEntryPoint": "main",

            // ★ Cortex Live Watch
            // OpenOCD 下可用
            // samplesPerSecond 最大 20
            // 先用 4Hz 足够
            "liveWatch": {
                "enabled": true,
                "samplesPerSecond": 4
            }
        }
    ]
}
4.4.5.3.Debug與LiveWatch

先編譯

點選進入debug:

成功進入:

複製一個你程式裡的某個全域性變數,我這裡是cmd_vel2:

填到cortex live watch,注意不是stm32cube live watch:

然後點執行看一下變數cmd_vel2

是不斷在變化的:

5.常見問題

5.1.Linux下USB許可權問題

如果你都正常識別出裝置了,則沒必要做這一步了

如果你遇到的話,你解決不了就讓AI來解決,AI幾秒鐘就給你把事辦了

如果偵錯程式插上後能在 lsusb 中看到,但 VS Code 找不到裝置,或者除錯輸出中出現下面的報錯,通常是當前使用者沒有訪問 USB 裝置節點的許可權:

libusb couldn't open USB device /dev/bus/usb/001/008, errno=13
libusb requires write access to USB device nodes
ST-Link enumeration failed

先在終端執行 lsusb,確認偵錯程式已被系統識別。報錯中的 /dev/bus/usb/001/008 只是示例,實際路徑以你自己的輸出為準。可以用 ls -l 檢視該節點的許可權:

lsusb
ls -l /dev/bus/usb/001/008

**使用 ST-Link:**先按上文點選外掛中的 install ST-Link udev rules。如果仍然報許可權錯誤,檢查規則是否裝到了系統中:

find /etc/udev/rules.d /usr/lib/udev/rules.d -maxdepth 1 -iname '*stlink*.rules' -print 2>/dev/null

如果沒有找到規則,可以從 ST 官方的 STSW-LINK007 下載頁獲取安裝包。解壓後進入 AllPlatforms/StlinkRulesFilesForLinux,按其中的 readme.txt 安裝與你的發行版對應的 udev 規則包。在這個目錄中,Fedora 使用 .rpm 包,Ubuntu/Debian 使用 .deb 包:

# Fedora:只运行这一行
sudo dnf install ./st-stlink-udev-rules-*.rpm

# Ubuntu/Debian:只运行这一行
sudo apt install ./st-stlink-udev-rules-*.deb

如果下載的包名不同,以實際檔名和隨包說明為準。ST 的發行說明也說明了 Linux 下需要安裝相應的 ST-Link USB 訪問規則。

**使用 J-Link:**上文安裝的 jlink-gdbserver bundle 用於啟動除錯服務;USB 許可權還需要 SEGGER 的 udev 規則。安裝 SEGGER J-Link Software and Documentation Pack 中對應發行版的 .rpm 或 .deb 包時,會一併安裝規則。如果使用解壓版,則按照包內 README.txt,將 99-jlink.rules 複製到 /etc/udev/rules.d/。具體方法見 SEGGER 的 Linux 排查說明。

安裝規則後,執行:

sudo udevadm control --reload-rules

然後拔下偵錯程式再插回去,重新執行 lsusb,用新的匯流排號和裝置號檢視 /dev/bus/usb/... 節點。可以將實際路徑代入下方命令,檢查當前使用者能否讀寫:

test -r /dev/bus/usb/001/008 && test -w /dev/bus/usb/001/008 && echo 'USB 设备节点可读写'

拔插後設備號可能變化,不要照抄示例中的 001/008。確認許可權後,回到 VS Code 重新選擇偵錯程式。如果 lsusb 根本看不到偵錯程式,應先檢查 USB 線、介面和供電;這不是 udev 許可權問題。

這裡檢查的是 /dev/bus/usb/...。如果另外還要開啟板載虛擬序列埠 /dev/ttyACM*,那是序列埠裝置的許可權,需要分別排查。