PAYATHON 2026

使用 "Raspberry Pi Pico" 扩展导入 PICO C 项目后无法调试

排障赵师傅

结论

命令行已经能通过 Raspberry Pi Debug Probe、OpenOCD 和 gdb-multiarch 完成调试,调试探针、Pico W 接线、USB 权限和基础工具链大概率都没有问题。VSCode 调试失败,多半是 .vscode/launch.json 与实际环境不匹配,例如 ELF、GDB、OpenOCD 或脚本目录的路径有误,或者 preLaunchTask 配置不对。

可以先让 VSCode 连接手动启动的 OpenOCD,只检查 VSCode 和 GDB 的调试配置,暂时绕过自动构建、自动烧录和 OpenOCD 启动任务。确认连接正常后,再配置 VSCode 自动启动 OpenOCD。

项目也不要求 .vscode 中一定要有六个 JSON 文件。调试主要使用 launch.json,构建前任务通常写在 tasks.json 中。CMake 配置可能在 settings.json、CMakePresets.json 或扩展自己的配置中。

确认实际生成的 ELF 文件

调试器需要加载包含调试信息的 .elf 文件,不能使用 .uf2 或 .bin。

在项目根目录执行:

find build -type f -name '*.elf' -print

假设输出为:

build/my_app.elf

launch.json 中的 executable 就要准确指向这个文件:

"executable": "${workspaceFolder}/build/my_app.elf"

文件名通常来自 CMakeLists.txt 中的目标名。例如:

add_executable(my_app
    main.c
)

对应的 ELF 通常是 build/my_app.elf。如果项目使用多级构建目录,以 find 命令的实际结果为准。

同时确认构建产物包含调试信息。使用单配置生成器时,可以明确指定 Debug 构建:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DPICO_BOARD=pico_w
cmake --build build

如果项目或扩展使用多配置生成器,构建方式可能不同,需要根据 CMake 输出确认当前选择的配置。

连接手动启动的 OpenOCD

命令行调试已经成功,可以直接沿用原来验证过的 OpenOCD 命令。例如:

openocd \
  -s /absolute/path/to/openocd/scripts \
  -f interface/cmsis-dap.cfg \
  -f target/rp2040.cfg \
  -c "adapter speed 5000"

不同 OpenOCD 发行版使用的脚本位置和配置文件可能不同。示例中的路径仅用于说明,实际配置应使用命令行调试成功时的原始参数。

OpenOCD 正常启动后,通常会监听 GDB 端口 3333。接着在 .vscode/launch.json 中加入一个最小配置:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Pico W: connect to existing OpenOCD",
            "type": "cortex-debug",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "executable": "${workspaceFolder}/build/my_app.elf",
            "servertype": "external",
            "gdbTarget": "localhost:3333",
            "gdbPath": "/usr/bin/gdb-multiarch",
            "runToEntryPoint": "main",
            "showDevDebugOutput": "raw"
        }
    ]
}

其中有两处需要根据本机环境修改。

"executable": "${workspaceFolder}/build/my_app.elf"

将它替换为实际的 ELF 路径。

"gdbPath": "/usr/bin/gdb-multiarch"

这里应填写以下命令返回的真实路径:

command -v gdb-multiarch

这份配置依赖 Cortex-Debug 扩展,因为 "type": "cortex-debug" 由该扩展提供。如果现有 launch.json 使用了其他 type,不要把两种调试器的字段写进同一个配置。

如果程序已经烧录,只需要附加到正在运行的目标,可以尝试将:

"request": "launch"

改为:

"request": "attach"

launch 通常会复位目标、下载程序并运行到入口点。attach 更适合保留目标的当前状态。具体行为还会受到 Cortex-Debug 版本和 OpenOCD 配置的影响。

配置 VSCode 自动启动 OpenOCD

确认外部 OpenOCD 配置能够正常调试后,再加入自动启动配置:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Pico W: launch OpenOCD",
            "type": "cortex-debug",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "executable": "${workspaceFolder}/build/my_app.elf",
            "servertype": "openocd",
            "serverpath": "/absolute/path/to/openocd",
            "gdbPath": "/usr/bin/gdb-multiarch",
            "searchDir": [
                "/absolute/path/to/openocd/scripts"
            ],
            "configFiles": [
                "interface/cmsis-dap.cfg",
                "target/rp2040.cfg"
            ],
            "device": "RP2040",
            "runToEntryPoint": "main",
            "showDevDebugOutput": "raw"
        }
    ]
}

可以用以下命令核对 OpenOCD 和 GDB 的路径:

command -v openocd
command -v gdb-multiarch

查找 OpenOCD 脚本目录:

find /usr /opt -type f -path '*/target/rp2040.cfg' 2>/dev/null

searchDir 要填写脚本根目录,也就是包含 interface、target 等子目录的目录,不能填写 rp2040.cfg 文件所在的目录。

Raspberry Pi Debug Probe 使用 CMSIS-DAP,常见的接口配置为:

interface/cmsis-dap.cfg

第一代 Pico W 使用 RP2040,常见的目标配置为:

target/rp2040.cfg

如果命令行调试成功时使用的是其他文件,继续使用已经验证过的配置,不要直接换成示例中的文件。

检查 preLaunchTask

生成的 launch.json 中可能有以下配置:

"preLaunchTask": "Compile Project"

这里的名称必须与 .vscode/tasks.json 中某个任务的 label 完全一致:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Compile Project",
            "type": "shell",
            "command": "cmake",
            "args": [
                "--build",
                "${workspaceFolder}/build"
            ],
            "problemMatcher": "$gcc"
        }
    ]
}

任务不存在、名称大小写不一致或任务执行失败,都会导致 VSCode 在启动 GDB 前终止调试。

排查时可以暂时删除 preLaunchTask,手动构建后直接启动调试。确认调试正常,再恢复自动构建任务。

不要混用不同的 CMake 生成器

手动运行 CMake 和通过 VSCode 扩展运行 CMake 时,可能分别使用 Unix Makefiles 和 Ninja。同一个 build 目录不适合混用不同的生成器,否则可能出现以下错误:

generator does not match the generator used previously

也可能出现 VSCode 找不到扩展所需构建文件的情况。

确认 build 只是可以重新生成的构建目录后,可以将它删除,再统一使用一种方式配置:

rm -rf build
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DPICO_BOARD=pico_w
cmake --build build

如果需要同时测试手动构建和扩展构建,最好分别使用不同的目录:

cmake -S . -B build-manual -DCMAKE_BUILD_TYPE=Debug -DPICO_BOARD=pico_w

然后让 VSCode 使用另一个目录,例如 build-vscode。

还要检查顶层 CMakeLists.txt 能否在不加载交互式 Shell 初始化脚本的环境中找到 Pico SDK。不要只依赖终端启动时临时设置的环境变量。可以在 VSCode 集成终端中检查:

printf '%s\n' "$PICO_SDK_PATH"
cmake --version
ninja --version

检查 Snap 版 VSCode 的环境差异

当前 VSCode 运行在 Snap 环境中。即使相关命令可以在普通终端执行,扩展进程看到的 PATH、文件访问范围和 USB 环境仍可能不同。

blink 已经能够烧录,因此 USB 访问不是首要排查项。不过,仍建议在 VSCode 集成终端中重新运行:

command -v cmake
command -v openocd
command -v gdb-multiarch
openocd --version
gdb-multiarch --version

如果普通终端能找到工具,而 VSCode 集成终端找不到,请在配置中填写绝对路径。如果日志中出现 Permission denied、无法访问扩展下载目录或无法打开 USB 设备,再检查 Snap 连接:

snap connections code

实际的 Snap 包名不一定是 code,应以 snap list 的输出为准。也可以使用非 Snap 版 VSCode 做一次对照测试,判断问题是否来自沙箱环境。

需要提供的日志和配置

如果使用上述最小配置仍无法启动,请优先提供以下内容:

  1. .vscode/launch.json
  2. .vscode/tasks.json
  3. .vscode/settings.json
  4. 顶层 CMakeLists.txt
  5. find build -type f -name '*.elf' -print 的输出
  6. 命令行调试成功时使用的完整 OpenOCD 命令
  7. command -v openocd gdb-multiarch cmake 的输出
  8. VSCode “调试控制台”中的完整错误
  9. VSCode “输出”面板中 Cortex-Debug、Raspberry Pi Pico 和 CMake 相关通道的日志
  10. OpenOCD 从启动到失败位置的完整输出

"showDevDebugOutput": "raw" 会让 Cortex-Debug 输出实际执行的 GDB 命令,通常能直接定位失败环节:

  • 找不到 ELF:检查 executable
  • 找不到 GDB:检查 gdbPath
  • OpenOCD 无法启动:检查 serverpath
  • 找不到 rp2040.cfg:检查 searchDir
  • 无法连接 localhost:3333:确认 OpenOCD 是否仍在运行,以及端口是否被占用
  • 调试前任务失败:检查 preLaunchTask 和 tasks.json
  • ELF 可以加载但断点无效:确认使用 Debug 构建,并检查编译优化级别和源文件路径

结合目前的现象,可以按以下顺序排查:先确认 ELF 路径,再删除或绕过 preLaunchTask,然后连接手动启动的 OpenOCD。确认这些步骤正常后,再恢复 VSCode 自动启动 OpenOCD 和自动构建。

备注:内容仅供参考。