Raspberry pi pico/pico2(以降pico/pico2)のC++開発環境にはずっと試行錯誤していて、Arduino IDEである程度要望は達成できてはいたのですが、やっとESP32で使い慣れたVScode+PlatformIOで業務レベル開発ができるようになったので覚書です
要望というのは
- (必須)RP2040/RP2350両方開発したい
- (必須)FreeRtOS → Arduinoモードを使う時点で目標達成
- (必須)USBCDC
- (必須)デバッガで書込み(いちいちBoot&ResetしてからのD&Dが甚だ面倒くさい)
- Arduinoのライブラリが使える
- picoSDKの書式も使える
- (ささやかな要望)pioasmも開発環境内で使いたい
- (ささやかな要望)ソースファイルはプロジェクトルートの下の「src」にしたい
最近安定化したVScode拡張機能「Raspberry Pi Pico」がかなり良い線です、が、私のスキルではFreeRtOSが組み込めず、また、ウイザードで作成するとソースフォルダがプロジェクトルートになるのでいちいちCmakeLists.txtを編集するのが面倒でした
そのほか、
デバッグが佳境に入ると頻繁にキーボードに手を伸ばすことすら面倒なので、F5キー周辺のみの「デバッグ用USBキーボード」もpicoで作ってみて手元近くに置いて「効率化?」もしてみました
オールpicoのお話になっております
2025/03/14 修正 githubアドレスについて致命的なミスがありましたm(_ _)m。お詫びして修正しました。
VScode PlatformIOでpicoを使う
通常のPlatformIOのpico開発は、うまく機能しておらず諦めかけていたところ、たどり着いたのが / platform-raspberrypi 」。世の中にはこんなアレンジできてしまう人がいるんだ!、とひとしきり感心した後、コメントをDeepLで翻訳すると、作成者曰く
「このフォークは、Raspberry Pi RP2040とRP2350 Arduino Core for PlatformIOのアップストリーム開発が進んでいないために作成されました」というわけで、
maxgerhardt版platformが決めて
組み込み方はいくつかあるようですが、PIO HomeでPlatformsを選択し、「Advanced Installation」から、
2025/03/14 修正
「https://github.com/platformio/platform-raspberrypi.git」
「https://github.com/maxgerhardt/platform-raspberrypi.git」
を打ち込むとインストールできる。プロジェクト毎に使い分けたいときにはplatformio.iniに
「platform = https://github.com/platform-raspberrypi.git」
「platform = https://github.com/maxgerhardt/platform-raspberrypi.git」
と記述すれば良いようだ。Platformsに下記が追加されたらOK

※公式からの是非は不明なので、現状は自己責任レベルかな、とは思いますが、社内用から始め治具にもどんどん使っています。ほんと感謝m(_ _)m
ArduinoとPicoSDK両方が使えることがわかる
Pico-Probeの用意
D&D書き込みを避けるには、デバッガで書き込むしかないのである
デバッガはpicoを使った「pico-probe」
公式ページからたどり、「raspberry pi/debug prove」から、「 debugprobe_on_pico.uf2 」をロードして、通常の書き込みモードでマスストレージpicoに書き込む。pico2の場合は「~pico2.uf2」というファイル名をロードすることになる
ターゲットとの接続
pico-probe側③ピンGND ターゲット側DEBUGコネクタ②ピンGND
pico-probe側④ピンGP2 ターゲット側DEBUGコネクタ①ピンSWC
pico-probe側⑤ピンGP3 ターゲット側DEBUGコネクタ③ピンSWD
接続の様子。下の写真は、上がデバッガpico、下がターゲットpico2
UART経由のシリアルモニターを使う方はTx、Rxも配線しますが、今回は使わないのでSWC/SWDのみとしました
テストプログラムの作成
PlatformIO+NewProgramからのウイザードで下のようにしてみた。ターゲットはpico2です
platformio.iniのデバッガの設定
[env:rpipico2]
platform = raspberrypi
board = rpipico2
framework = arduino
upload_protocol = cmsis-dap
debug_tool = cmsis-dap
debug_init_break = tbreak setup ;
build_type = debug
board_build.core = earlephilhower
board_build.filesystem_size = 0m
FreeRtOS・USBCDCのテストプログラム
タスクでLEDを点滅しながら、別タスクでUSBCDCに文字列を送り、USBCDCからポーリングで文字受信し’a’ならメッセージを送るプログラム。
今回は1文字のみの受信確認だが、USBCDCでは受信割り込みという概念がなく、そのかわりバックグラウンドで受信バッファに取り込まれるので、文字列受信ができる
したがって受信割り込みハンドラを使わなくてもタスクで数msループでポーリングで十分にシリアル送受信が可能
#include <Arduino.h>
#include <FreeRTOS.h>
#include <task.h>
void ledTask(void *pvParameters) {
bool isOn = false;
while(1) {
digitalWrite(25, isOn = !isOn);
Serial.printf("Hello! \n\r");
vTaskDelay(500);
}
}
void mainTask(void *pvParameters) {
for(;;) {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'a') {
Serial.printf("Receive!\n\r");
}
}
vTaskDelay(5);
}
}
void setup() {
pinMode(25, OUTPUT);
xTaskCreate(mainTask, "MainTask", 1024, NULL, 1, NULL);
xTaskCreate(ledTask, "LedTask", 1024, NULL, 1, NULL);
}
void loop() {}
タスクを生成したら、ディレイはすべてvTaskDeley関数で行う。sleepが使えるのはタスク生成前までにしておいたほうが無難
arduinoモードではvTaskScheduler()関数は不要らしい。記述するとおかしくなるようだ
TeraTermで受信中およびキー入力の様子の画像
デバッグ開始:F5、実行:F5、デバッグ終了:Shift+F5
デバッグは?
F5を押してロードからsetup()で停止するまで10数秒かかる。大規模プログラムではもっとかかるかもしれない。debugspeed = 2000とかしても上限があるらしく、指定しなくても特に変わらない
詳細なテストではないですが、デバッガpico-probeをpicoとpico2で比較した結果、上のテストプログラム程度ならロード時間は1秒も変わらないようでした。
ブレークを決めると普通に止まる。変数Watchも普通にできる。ロード時間がかかるとは言え、シリアルprintと併用すればさらに効率は上がる
デバッグ用に専用キーボードをpicoで製作
Platformio.iniにdebug_init_break = tbreak setupの記述を入れたので、実行させると一旦setup()で止まる。したがって、通常実行させるにはF5を二回押すことになる
この記述をコメントアウトすると、.platformio下のテンポラリソース内で止まるのでこれはこれでヤバい。現段階では止まらないで一気に実行する設定がわからない
実行・停止・更新のたびにPCキーボードに手を伸ばすのはちょっと煩雑なので、デバッグ専用のキーボードを作って手元で操作できるようにした。これによりちょっとした変更とマウス操作は右手だけで、ターゲット操作とデバッグ操作は左手に分けて出来る。私にとっては少し効率が上がる
配線はGP2:F5、GP3:Shift+F5、GP4:Ctrl+F5、GP5:Ctrl+Shift+F5。
raspberry pi 4/5などのpythonデバッグにも使えるようにCtrl+F5やCtrl+Shift+F5キーを増やした。まあ、ショートカットキーを変えても良いのだが・・・今更使い慣れているので
#include <Arduino.h>
#include <Keyboard.h>
bool keyPressed[8] = {false, false, false, false, false, false, false, false}; // キーが押されたかどうかを追跡するフラグ
void setup() {
// GPIOピンを入力として設定
pinMode(2, INPUT_PULLUP); // GP2
pinMode(3, INPUT_PULLUP); // GP3
pinMode(4, INPUT_PULLUP); // GP4
pinMode(5, INPUT_PULLUP); // GP5
Keyboard.begin(); // USBキーボードの初期化
}
void loop() {
// GP2 → F5
if (digitalRead(2) == LOW && !keyPressed[0]) {
Keyboard.press(KEY_F5);
keyPressed[0] = true; // キーが送信されたことを記録
} else if (digitalRead(2) == HIGH) {
keyPressed[0] = false; // GPIOがHIGHになったらフラグをリセット
Keyboard.release(KEY_F5);
}
// GP3 → Ctrl+F5
if (digitalRead(3) == LOW && !keyPressed[1]) {
Keyboard.press(KEY_LEFT_SHIFT);
Keyboard.press(KEY_F5);
keyPressed[1] = true;
} else if (digitalRead(3) == HIGH) {
keyPressed[1] = false;
Keyboard.release(KEY_LEFT_SHIFT);
Keyboard.release(KEY_F5);
}
// GP4 → Shift+F5
if (digitalRead(4) == LOW && !keyPressed[2]) {
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_F5);
keyPressed[2] = true;
} else if (digitalRead(4) == HIGH) {
keyPressed[2] = false;
Keyboard.release(KEY_LEFT_CTRL);
Keyboard.release(KEY_F5);
}
// GP5 → Ctrl+Shift+F5
if (digitalRead(5) == LOW && !keyPressed[3]) {
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_SHIFT);
Keyboard.press(KEY_F5);
keyPressed[3] = true;
} else if (digitalRead(5) == HIGH) {
keyPressed[3] = false;
Keyboard.release(KEY_LEFT_CTRL);
Keyboard.release(KEY_LEFT_SHIFT);
Keyboard.release(KEY_F5);
}
delay(10); // デバウンス処理のために少し待機
}
HIDキーボードを使うには、platformio.iniには下の一行を追加
キー操作に関するファームでは、操作を間違うとソースファイルに連続打鍵してえらいことになった経験があるので、ここはpico-probeを使わないでマスストレージにuf2を書き込む方法でしっぽりとプログラミング。やっとうまくいった(´▽`) ホッ
以上