rp2040を採用している評価ボードでBOOTSELボタンが壊れている時に読む記事

こんにちは
この記事はKLab Engineer Advent Calendar2023の記事です。

:::note warn
警告・免責事項
執筆者は組み込み系エンジニアではなく、趣味で学んだことを記事にしているため、拙い部分があるかとは思いますがご了承ください。専門分野外のことに取り組んだ奮闘記だと捉えていただくのが良いかと思います。本記事の情報をもとにした開発、製作、運用などの結果について、いかなる責任も負いません。(例: Raspberry Pi Picoが壊れたり等)
:::


## Raspberry Pi PicoのBOOTSELボタンとは
まずBOOTSELモードについての説明をします。
Picoを初めて触る方は「Pico向けに書いたプログラムをどうやってPicoに書き込むか？」という疑問があると思います。
最もお手軽な方法としてBOOTSELモードというものがあります。
PicoをBOOTSELモードでUSBでPCに接続すると、PicoはUSBマスストレージデバイスとして認識されます。
Picoに書き込む自作のプログラムはUF2ファイル形式にしておきます。
このストレージにUF2ファイルをドラッグ&ドロップするだけで、プログラムをPicoに書き込むことができます。
(かなり便利です。ただ、どういう仕組みでそうなっているか、私は理解していません。)


## BOOTSELボタンが効かない個体に遭遇
私は仕事は関係なく趣味でRaspberry Pi Picoをはじめrp2040のSoCを採用している評価ボードを触っているのですが、たまにBOOTSELボタンを押しながらPCにUSB接続しても、ストレージとして認識しない個体と遭遇することがありました。おそらくBOOTSELボタンが接触不良で壊れているのだと思います。
この個体はBOOTSELボタン以外にも不具合がありそうな予感はしますが、もし壊れているのがBOOTSELボタンのみであれば、なんとかして、プログラムを書き込むことができればこのジャンクな評価ボードを使えるかもしれません。

(基本的にジャンク品という認識ではあるので、破棄等するのが良いと思います。)

結論を早く知りたい方は[作戦](#作戦)まで読み飛ばしてOKです。
今回は答えまでたどり着いた経緯まで書いています。


## 答えに辿り着くまでの記録
とりあえず改めてRaspberry Pi PicoのGetting Startedを一通り目を通そうと考えました。
こちらのページに "Getting started with Raspberry Pi Pico" のpdfへのリンクがあります。
https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html#raspberry-pi-pico

pdfの初めのほうは、開発環境のセットアップについて書かれています。
ここでは詳しくみていきませんので、環境セットアップがまだできていない方は各自でセットアップをお願いします。
(※基本的にRaspberripy Picoは Raspberry Pi 4B などで動作するRaspberry Pi OSで開発することを前提としているようですが、筆者は Raspberry Pi 4B を持っていないため、Windowsの WSL2で開発しています。)

「BOOTSELボタンを使わなくて済む方法がないか」を念頭に置いて、このpdfを読み進めると、
「3.2.3. Aside: Other Boards」が目につき、

```
 Most boards expose the SWD interface (Chapter 5) which can reset the board and load code without any button presses
```

という文章が気になりました。
SWDというものを使えばボタンを使わなくともコードをloadできると書かれています。
Chapter5やSWDがかなり気になります。
ということで、「5. Flash Programming with SWD」や「6. Debugging with SWD」をみていきましょう。
「5. Flash Programming with SWD」のチャプターを眺めると、「5.2. SWD Port Wiring」で、Raspberry Pi 4BとPicoをケーブルで繋げた配線図が描かれていました。
図にあるように、ケーブルをPicoに接続しているところをよくみると、microUSB端子が付いているボード端とは反対側に3つの穴(スルーホール)に接続しています。
手元にあるRaspberry Pi Picoのボードをみると、「▼DEBUG」と印字されているところに繋げているようです。

これはなんだろうと思いましたが、SWDというものに使用するスルーホールみたいです。
pdfにある図では Raspberry Pi 4B を使っています。
私は Raspberry Pi 4B は持っていません。この方法は使えなさそうです。


しかし、「5.2. SWD Port Wiring」 のTIPのところに、

```
If you are using another debug probe, like Picoprobe (Appendix A), you need to connect the GND, SWCLK and SWDIO pins on your probe to the matching pins on your Raspberry Pi Pico, or other RP2040-based board.
```

と書かれていました。Picoprobeを使う場合は...と書かれています。
代替手法としてPicoprobeなるものがあるといった感じがします。
Appendix Aを見てみます。


「Appendix A: Using Picoprobe」をみると、二つのpicoを使った配線図が目に留まりました。
先ほどと同じように「▼DEBUG」のスルーホールにジャンパケーブルを接続してなにかやる方法らしいとわかります。
これであれば Raspberry Pi 4B を持っていない私でもなにか手が打てるかもしれません。
Picoprobeについて読んでいきます。

読んだところ、一つのPicoをデバッガとして使って、ターゲットとなるデバッグ対象のPicoをデバッグできるとわかりました。
また、デバッグシンボルがあるelfファイルをロードしてデバッグできるではありませんか。

↓写真左側のPicoがpicoprobeで、写真右側のPicoがデバッグ対象のPico
![picoprobeとデバッグ対象のpico](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320268/af6a6e4c-80be-3af2-3b44-a5f1774e347d.jpeg)



しかも(実際に手を動かして試してみると)デバッグシンボルがあるelfファイルをloadしたデバッグ対象のpicoは、picoprobeと切り離してもスタンドアローンとして稼働していることがわかりました。

つまり、もう既にこの時点でBOOTSELボタンをつかわずともプログラムを書き込むことができたということになります。
しかし、loadしたのはデバッグシンボルがあるバイナリのはずです。
もしかすると、(デバッグシンボルがないものと比較して)多少のオーバーヘッドはあるかもしれません。

他に方法がないか一考しましたがopenocdコマンドでもプログラムを書き込めるようです。
GettingStartedのPDFには、openocdコマンドでも書き込む方法が書かれています。ただ、これもマニュアル上ではデバッグシンボル付きのelfファイルです。デバッグシンボルなしのELFファイルも書き込むことができるかもしれませんが、私は今回試していません。
またopenocdについて軽く調べると、アドレス指定でバイナリを指定して書き込むこともできるようですが、どのアドレスにどのバイナリを書き込めば良いのかわかりません。そこまでPicoに詳しくはありません。

やはり簡単な方法である、BOOTSELモードで起動してストレージとして認識してuf2ファイルをドラッグ&ドロップでPicoに渡したいところです。

ふと素朴な疑問が湧きました。
「都度プログラムを書き込むたびに、既にpicoをPCに接続したものをPCから切り離してBOOTSELボタンを押しながらPCにUSBケーブルで接続するってめんどくさくないか？」
という疑問です。

「もっとお手軽に、BOOTSELボタンを押さずにBOOTSELモードに入る方法を確立してる人がいてもおかしくないはず。」
こう考えました。

ググったところ、PicoをBOOTSELボタンを押さずに、PCに普通にUSB接続しておき、あとはresetボタンを素早く二回押せばいつでもBOOTSELモードに入れる方法があることがわかりました。
問題のBOOTSELボタンが壊れているジャンクな評価ボードは、幸いにもresetボタンが標準搭載されています。この方法は使えそうです。


:::note info
蛇足

しかし、「ボタンを素早く二回押す」がなにか見覚えがある気がしてきました。
そう、既に私はこの方法があることを知っていたはずなのですが、それを 忘 れ て し ま っ て い た のです。

> 3.2.3. Aside: Other Boards
```
Some boards will have a reset button but no BOOTSEL, and may include some code in flash to detect a doublepress of the reset button and enter the bootloader in this way.
```

Chapter3には、
いくつかのボードでは、BOOTSELボタンが無いがresetボタンがあるものがあり、そのresetボタンを素早く二回押せばbootloaderに入れるコードが含まれているかも知れない、とあります。見覚えがある気がしていた、正体はこれだったのでしょう。
問題の評価ボードには、resetボタンを素早く二回押してもBOOTSELモードに入れなかったので、残念ながらそういったコードは工場出荷時に組み込まれていない様子です。

おそらくこれと同様のことを後述の方法で自前で用意できるのだと思われます。

:::


調べたところ、
リセットボタンを素早く二回押したらBOOTSELモードに入るようにする方法は、
ビルド時に pico_bootsel_via_double_reset ライブラリをリンクしておけば良いようです。
[公式ドキュメント | pico_bootsel_via_double_reset](https://www.raspberrypi.com/documentation/pico-sdk/runtime.html#pico_bootsel_via_double_reset)

```text:pico_bootsel_via_double_reset
When the 'pico_bootsel_via_double_reset' library is linked, a function is injected before main() which will detect when the system has been reset twice in quick succession, and enter the USB ROM bootloader (BOOTSEL mode) when this happens. This allows a double tap of a reset button on a development board to be used to enter the ROM bootloader, provided this library is always linked.
```

BOOTSELボタンが破損したボード復旧用のPico用プロジェクトの作成や、CMakeLists.txtを書くのも面倒くさいなと思ったらなんとpico-exampleにてコードが公開されていました。App名はhello_double_tapです.
[hello_double_tap/CMakeLists.txt](https://github.com/raspberrypi/pico-examples/blob/eca13acf57916a0bd5961028314006983894fc84/system/hello_double_tap/CMakeLists.txt#L9)へのリンクも置いておきます。




コードを一行もかかずにelfファイルをつくれます。手元でビルドするだけです。
~~もはやBOOTSELボタンが破損したボードの復旧用プロジェクトを本家が配っているようなものです~~
BOOTSELボタンがない、サードパーティのrp2040を採用している評価ボードのために用意されているようなものですね。
つまり作戦はこうです。


### 作戦
0. BOOTSELボタンが壊れたrp2040を搭載した評価ボード(SWD接続可能なもの)をpicoprobeと接続する。
1. pico-exampleのhello_double_tapをビルドしてelfバイナリをつくる
2. pico-probeでgdb-multiarchで先ほどビルドしたelfをloadする(BOOTSELボタンが壊れて効かないPicoに対して)
    → これでPCとUSB接続すればresetボタンを素早く二回押せばBOOTSELモードに移行するはずです
3. resetボタンを素早く2回押してBOOTSELモードに入り、UF2ファイルをドラッグ&ドロップでプログラムを書き込む
4. 無事プログラムが書き込めて、めでたしめでたし。

これでうまくいかなければこの評価ボードは本当に廃棄行きです。

すこし文字数が多いので少し簡略化したバージョンも下記に記載しておきます。

### 作戦(簡略化版)
1. picoprobeを使って、BOOTSELボタンが壊れたボードにhello_double_tapのelfバイナリをロードさせる
2. picoprobeとの接続を解除(ジャンプワイヤーなどの配線をとりのぞく)
3. 開発用のPCとPicoをUSB接続する
4. Resetボタンを素早く2回押すとBOOTSELモードに入れるはず...!

## 結論

- 作戦はうまくいきました！

- raspberry Pi Picoの場合はresetボタンは標準で付いていないので、30番目のピン(RUN)と二つ隣にある28ピンのGNDの間をブレッドボード等でタクトスイットで接続するなどしてresetボタンを用意してあげれば良いと思います。


## 他の方法
こちらの方法でもTinyGoにはなりますが、tinygo flashコマンドではBOOTSELボタンを押さなくてもOKなようです
[Zenn | TinyGo で Raspberry Pi Pico の Lチカ](https://zenn.dev/mattn/articles/453893e3fde4b1)

Raspberry Pi Picoであればボードの裏面にTP6ピンがBOOTSELのピンとして出ているため、これを使うことができます。(今回問題となっていたボードではこのピンはありませんでした。。)
[elchila | ラズピコに「長押し書き込みボタン」を追加する](https://elchika.com/article/655f8b41-200b-40d9-8a1c-23d88460eb29/)
[シャポログ | ラズピコに「長押し書き込みボタン」を追加する](https://blog.shapoco.net/2023/10/raspico-longpush-button.html)

## 未調査
- openocdコマンドでelfファイルが書き込めるのは分かっていましたが、デバッグシンボルのないelfを作ってそれを書き込めば良いようにも思います(こちらは試していません)
- UF2ファイルはバイナリデータとそれをフラッシュメモリのどのアドレスに書き込むべきかを指定する情報を含んでいるようで、UF2ファイルがやってくれていたのと同じことをopenocdコマンドで手動でアドレスを指定してあげれば再現できるのではと仮説を立てていますが、試せていません。