Raspberry pi pico/pico2をPicoProbeで量産書き込み「VScode+PlatformIO版」

カテゴリー: シングルボードコンピュータ  タグ:

Raspberry pi pico(以降raspico)にESP32のESPtoolの様に、pico probeを使って量産書き込みをするための環境を作ってみました。「VScode+platformIO版」とポータブル構成でコマンドラインで書き込む「スタンドアロン版」の両方作りました。今回は前者「VScode+PlatformIO版」の覚書です
まあ、作ってみた、といっても大部分AI頼りですが・・・

PlatformIO版OpenOCDを使う。パスを通しておく

openocd.exeはPlatformIO版を使います。まずこれを探します。

VScodeにPlatformIO拡張機能をインストールしてあることが必須で、raspico開発モジュールも必須です。私の環境では下記のパスになりました。バージョンによっても変わる可能性がありますので、ご自分で確認してください。

RP2350対応に関してはmaxgerhardt版のplatform-raspberrypiのインストールも必要かもしれません

C:\Users\<ユーザー名>\.platformio\packages\tool-openocd-rp2040-earlephilhower\binにopenocd.exeがあるのを確認して環境変数に登録しておきます

パスの設定は、PowerShellで

setx OPENOCD_PATH "C:\Users\[ユーザー名]\.platformio\packages\tool-openocd-rp2040-earlephilhower\bin\openocd.exe"

書き込みプログラム専用のフォルダを作る

VScodeで実行するためのフォルダを作ります。フォルダ名は何でも構いませんが私はPicoFlashとし、そこにファームウエアfirmware.elfを置きます(raspico開発ではVScodeのプロジェクトフォルダ\.pio\build\rpipicoにできています)これだけは手動でコピーします

その下にflash_onlyというフォルダを作成します

そのフォルダ構成は

C:.
│  firmware.elf
└─flash_only
    │  flash_dual.py
    │  platformio.ini
    ├─.pio
    └─.vscode
            c_cpp_properties.json
            extensions.json
            launch.json
            tasks.json

VScode上のターミナルでコマンドライン打ち込みで行う分には、.vscodeフォルダやjsonファイルは不要です

platformio.ini

[env:rpipico]
platform = raspberrypi
board = rpipico
framework = arduino
upload_protocol = picoprobe
debug_tool = picoprobe

プログラマ本体「flash_dual.py」

import subprocess
import sys
import os
import shutil

# === ベースディレクトリ ===
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))).replace("\\", "/")

def find_openocd():
    local_path = os.path.join(base_dir, "openocd.exe")
    if os.path.isfile(local_path):
        print(f"✅ ローカル版 OpenOCD 使用: {local_path}")
        return local_path

    env_path = os.environ.get("OPENOCD_PATH")
    if env_path and os.path.isfile(env_path):
        print(f"✅ 環境変数版 OpenOCD 使用: {env_path}")
        return os.path.abspath(env_path)

    which_path = shutil.which("openocd")
    if which_path:
        print(f"⚠️ PATH上の OpenOCD 使用: {which_path}")
        return os.path.abspath(which_path)

    print("❌ openocd.exe が見つかりません。")
    sys.exit(2)

def find_scripts(openocd_path):
    base = os.path.dirname(openocd_path)
    candidates = [
        os.path.join(base, "scripts"),
        os.path.join(base, "share", "openocd", "scripts"),
        os.path.join(os.path.dirname(base), "share", "openocd", "scripts"),
        os.path.join(base_dir, "scripts"),
    ]
    for c in candidates:
        if os.path.isdir(c):
            return os.path.abspath(c)
    print("⚠️ scripts フォルダが見つかりません。")
    sys.exit(3)

# === RP2040 / RP2350 自動判定 ===
def detect_target_chip(openocd, scripts):
    print("\n🔍 デバイス自動検出中...")

    for name, cfg in [("RP2040", "target/rp2040.cfg"), ("RP2350", "target/rp2350.cfg")]:
        cmd_probe = [
            openocd,
            "-s", scripts,
            "-f", "interface/cmsis-dap.cfg",
            "-f", cfg,
            "-c", "adapter speed 5000",  # 安定通信のため低速
            "-c", "init; shutdown"
        ]
        result = subprocess.run(cmd_probe, capture_output=True, text=True)
        if result.returncode == 0:
            print(f"✅ {name} デバイスを検出しました(正常応答)。")
            return cfg
        else:
            print(f"ℹ️ {name} では応答なし(returncode={result.returncode})")

    print("⚠️ 自動判定に失敗。RP2040として続行します。")
    return "target/rp2040.cfg"

# === 準備 ===
openocd = find_openocd()
scripts = find_scripts(openocd)
firmware = os.path.join(base_dir, "firmware.elf").replace("\\", "/")

# === 自動判定 ===
target_cfg = detect_target_chip(openocd, scripts)
speed = 20000

# === 書き込み ===
cmd_write = [
    openocd,
    "-s", scripts,
    "-f", "interface/cmsis-dap.cfg",
    "-f", target_cfg,
    "-c", f"adapter speed {speed}",
    "-c", f'init; program "{firmware}" verify; reset init; resume; shutdown'
]

print(f"\n=== Programming ({target_cfg.split('/')[-1].replace('.cfg','')}) @ {speed}kHz ===")
result = subprocess.run(cmd_write)

if result.returncode == 0:
    print(f"✅ 書き込み+自動再起動完了!({target_cfg})")
else:
    print("⚠️ 書き込みに失敗しました。")
    sys.exit(result.returncode)

sys.exit(result.returncode)

VScodeでflash_onlyフォルダを開き、コマンドラインで打ち込み。RP2040/RP2350自動判別

VScode上のターミナルで

python flash_dual.py

と打ち込むことで書き込み+自動再起動します。また、RP2040/RP2350は自動判別します

書き込み終了のメッセージは下記

ターゲットも自動再起動します

F5ショートカットキー、F1によるタスクコマンドでも対応

.vscodeフォルダにjsonファイルを作成し格納します。この記事では省略しますが、ご希望の方おられたらメールいただけたら対応します(コメント欄のメッセージでも対応しますが、毎日チェックしておりませんので悪しからず)

pico probeはpico/pico2どちらもOK。当然、公式debug probeでも動く

ただし、現時点ではマルチ書き込み器には対応していないので、probeは一台です

お気軽にコメントをどうぞ。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)