Raspberry Pi PicoのWSL+OpenOCDデバッグにVSCodeを使う


の続きです。Raspberry Pi Pico(以下Pico)をWSLのコマンドラインでgdbを使ってデバッグできるようになったので、今度はこれをVisual Studio Codeから使えるようにします。

実は現時点ではまだ不完全な点があって、事前にブレークポイントを置いてそこに止めることはできる一方で、実行中のプログラムを停止させることができていません(コマンドラインでgdbを使う際は普通にCtrl+Cで止まるのに…)。
とは言え、VSCodeのGUI上でのデバッグができると便利なことは確かなので、不完全ではありますが情報として公開したいと思います。

(実行環境のWSLはWSL2を前提としています。WSL1の場合はWindows側のIPアドレスを指定している箇所を削除するなどすれば動くと思います)

実行前の準備

  • 以下のシェルスクリプトをgdb-picoというファイル名でパスの通った箇所に置きます。 (ここ で書いたものから少しだけ変わっています)
gdb-pico
#!/bin/sh
killall -q gdb-multiarch
gdb-multiarch -ex "target remote `tail -1 /etc/resolv.conf|awk '{print $2}'`:3333" $*
  • Pico SDKで動かすプログラムのあるフォルダをVSCodeのRemote WSLでワークスペースとして開き、そのルートに.vscodeというフォルダを作成して以下のファイルlaunch.jsonを置きます。
    • (pico-examplesの場合は pico-examples/.vscode/launch.json)
launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb)",
            "type": "cppdbg",
            "request": "launch",
            "targetArchitecture": "arm",
            "program": "${workspaceFolder}/build/${relativeFileDirname}/${fileBasenameNoExtension}.elf",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "MIMode": "gdb",
            "miDebuggerPath": "${env:HOME}/bin/gdb-pico",
            "launchCompleteCommand": "exec-continue",
            "setupCommands": [
                {
                    "text": "load ${workspaceFolder}/build/${relativeFileDirname}/${fileBasenameNoExtension}.elf"
                }
            ]
        }
    ]
}

VSCodeでのデバッグ

  • WSLのシェルから以下のコマンドを実行しておきます。
openocd.exe -f interface/picoprobe.cfg -f target/rp2040.cfg -c 'bindto 0.0.0.0'
  • VSCodeでデバッグしたいアプリをビルドしておき、そのソースコード (ここではblink/blink.c) を開きます。
  • main()の最初の行の行番号の左をクリックして、ブレークポイントを置きます(赤い丸が付く)。
  • F5 または 実行(R)-デバッグの開始で、gdbが動いて事前に実行していたopenocdに接続し、ブレークポイントに止まることでデバッグを開始します。

  • ブレークポイントを置かずに続行(F5)すると止められなくなってしまうことだけ注意が必要ですが、その他通常のデバッグ操作は普通にできます。
    • 続行するとgdbがVSCodeの制御を離れて動きっぱなしになってしまうのですが、停止して再度デバッグを開始する際は、gdb-picoスクリプトに入れたkillallで削除されるようにしています。

(おまけ) cmake/make等を行うtasks.json

Getting StartedではVSCodeを使う際はCMake Tools機能拡張を使うように書いてありますが、私は以下のようなtasks.json.vscodeに置いて使っています。

ソースコードを開いてCtrl+Shift+Bまたはターミナル-ビルド タスクの実行で以下の内容を実行することができます。

  • cmake
    • プロジェクトのルートにbuild/ディレクトリを掘ってcmakeを実行します
  • distclean
    • build/ディレクトリを削除します
  • make
  • make (verbose)
    • 開いているソースコードのアプリをビルドします
  • clean
    • ビルドの生成物を削除します
  • install
tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "make",
            "type": "shell",
            "command": "make -j4",
            "options": {
                "cwd": "${workspaceFolder}/build/${relativeFileDirname}"
            },
            "presentation": {
                "revealProblems": "onProblem"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build"
        },
        {
            "label": "make (verbose)",
            "type": "shell",
            "command": "make VERBOSE=1",
            "options": {
                "cwd": "${workspaceFolder}/build/${relativeFileDirname}"
            },
            "presentation": {
                "revealProblems": "onProblem"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build"
        },
        {
            "label": "clean",
            "type": "shell",
            "command": "make clean",
            "options": {
                "cwd": "${workspaceFolder}/build/${relativeFileDirname}"
            },
            "problemMatcher": [],
            "group": "build"
        },
        {
            "label": "install",
            "type": "shell",
            "command": "pico-install",
            "args": [
                "*.uf2"
            ],
            "options": {
                "cwd": "${workspaceFolder}/build/${relativeFileDirname}"
            },
            "problemMatcher": [],
            "group": "build"
        },
        {
            "label": "distclean",
            "type": "shell",
            "command": "rm -rf ${workspaceFolder}/build",
            "problemMatcher": [],
            "group": "build"
        },
        {
            "label": "cmake",
            "type": "shell",
            "command": "mkdir build; (cd build; cmake .. -DCMAKE_BUILD_TYPE=${input:buildType} -DPICO_DEFAULT_BINARY_TYPE=${input:binaryType})",
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [],
            "group": "build"
        },
    ],
    "inputs": [
        {
            "type": "pickString",
            "id": "buildType",
            "description": "Build Type",
            "options": [
                "Release",
                "Debug"
            ],
            "default": "Debug"
        },
                {
            "type": "pickString",
            "id": "binaryType",
            "description": "Binary Type",
            "options": [
                "default",
                "no_flash",
                "copy_to_ram",
                "blocked_ram"
            ],
            "default": "default"
        }
    ]
}