[Raspberry Pi PicoをWSL(Windows Subsystem for Linux)で使う]
(https://qiita.com/yunkya2/items/e67996301a2d8d2a5609)の続きです。WSL上でRaspberry Pi PicoのJTAGデバッグをやってみました。
接続の概要
Raspberry Pi Picoが2枚ある場合は、1枚を**Picoprobe**というアプリでJTAG(SWD)デバッグプローブにすることで、もう1枚のRaspberry Pi Pico上のアプリのデバッグに使うことができます。
具体的なやり方は Getting started with Raspberry Pi Pico の Appendix A: Using Picoprobe に載っているのですが、WSLを利用する場合、WSLからはPicoprobeのつながったUSBが見えないため、以下のような接続になります。
- OpenOCDはWindowsアプリとして動作させ、USBの先のPicoprobeに接続する
- gdbはLinuxアプリとしてWSL上で動作させ、Windows側のOpenOCDにTCP/IPで接続する
OpenOCDのビルド
まず、PicoprobeとつながるWindows側のOpenOCDをビルドします。A.1.2. Windows のやり方に従って、WSLでなくMSYS2を使用します。
こちら (https://github.com/yunkya2/openocd-win64) にMSYS2上でOpenOCDをビルドしてWSL環境用のtarballを作るためのMakefileを用意しました。
また、私の環境でビルドしたバイナリをこちら に置いてありますので、ダウンロードして使っていただくこともできます(動作の保証は致しかねますので自己責任で)。
ビルドもしくはダウンロードしたtarballは、WSL環境側で展開してopenocd-w64/bin
にパスを通しておきます。bashからopenocd.exe
が実行できることを確認します。
$ openocd.exe
Open On-Chip Debugger 0.11.0-rc2+dev-gabbf03b09 (2021-01-30-21:57)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
embedded:startup.tcl:26: Error: Can't find openocd.cfg
in procedure 'script'
at file "embedded:startup.tcl", line 26
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Error: Debug Adapter has to be specified, see "adapter driver" command
embedded:startup.tcl:26: Error:
in procedure 'script'
at file "embedded:startup.tcl", line 26
$
Raspberry Pi Pico (デバッグプローブ用)の環境準備
デバッグプローブとなる Raspbberry Pi Pico にpicoprobeをインストールします。
方法は A.2. Build and flash picoprobe にありますが、Raspberry Pi公式でビルド済みのpicoprobeバイナリが用意されていますので、ここ からダウンロードした picoprobe.uf2 を BOOTSELボタンを押しながら起動したRaspbberry Pi Picoにドラッグ&ドロップするだけでOKです。
結線
A.3. Picoprobe Wiring の通りです。
picoprobe自体にUSBシリアル変換の機能がありますので、Raspberry PiのUART同士をつないでやることで、picoprobeを接続したWindows PC側からデバッグターゲットのUARTを見ることができます。
Windows側のドライバインストール
A.4. Install Picoprobe driver (only needed on Windows) の通り…かと思ったのですが、ドキュメント通りにZadig (http://zadig.akeo.ie) からlibusb-win32をインストールしてもOpenOCDがクラッシュしてしまいます。いろいろ試したところ、ここでWinUSBをインストールしたら動作するようになりました(このあたりのドライバの違いが良く分からん…)。
デバッグの実行
WSL側には事前にgdb-multiarchをインストールしておきます。
$ sudo apt install gdb-multiarch
また、デバッグ対象のアプリのビルド時には、5.1. Build "Hello World" debug version にあるように、cmakeに-DCMAKE_BUILD_TYPE=Debug
を指定してデバッグ情報が入るようにします。
$ cd ~/pico/pico-examples/
$ rm -rf build
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ cd hello_world
$ make -j4
この後、WindowsアプリであるOpenOCDを起動して、WSL上で動かすgdbからこれに接続する必要があるのですが、この手順はWSL1とWSL2とで大きく異なります。WSL2はVMのLinuxカーネル上で動作しているため、WSL環境とWindows環境が異なるIPアドレスとして扱われるためです。
WSL1の場合
5.4. Use GDB and OpenOCD to debug Hello World と同じ手順でできます。WSL上から以下のコマンドラインでOpenOCDを実行します。
$ openocd.exe -f interface/picoprobe.cfg -f target/rp2040.cfg
Open On-Chip Debugger 0.11.0-rc2+dev-00014-gabbf03b09-dirty (2021-01-28-13:19)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'swd'
Warn : Transport "swd" was already selected
adapter speed: 5000 kHz
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
OpenOCDを実行したのとは別のターミナルを開いて、デバッグ対象のELFファイルを指定してgdb-multiarchを実行し、target remote
コマンドでOpenOCDに接続します。
$ gdb-multiarch hello_world.elf
:
(gdb) target remote localhost:3333
load
コマンドでフラッシュにELFファイルをロードし、monitor reset init
コマンド実行後、continue
コマンドで実行を開始します。
(gdb) load
Loading section .boot2, size 0x100 lma 0x10000000
Loading section .text, size 0x49c8 lma 0x10000100
Loading section .rodata, size 0xd88 lma 0x10004ac8
Loading section .binary_info, size 0x24 lma 0x10005850
Loading section .data, size 0x9ec lma 0x10005874
Start address 0x10000104, load size 25184
Transfer rate: 6 KB/sec, 4197 bytes/write.
(gdb) monitor reset init
target halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
target halted due to debug-request, current mode: Thread
xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00
(gdb) continue
Continuing.
WSL2の場合
以下のコマンドラインでOpenOCDを実行します。bindto
コマンドの実行を追加することで、OpenOCDを実行しているホスト以外からの接続を受け入れるようにします。
$ openocd.exe -f interface/picoprobe.cfg -f target/rp2040.cfg -c 'bindto 0.0.0.0'
初回の接続の場合のみ、以下のようなファイアウォールの警告が出ます。WSL2から接続できるようにするためには、「パブリック ネットワーク」の方にもチェックを入れてアクセスを許可する必要があります。
もしチェックを入れ忘れてダイアログを閉じてしまった場合は、コントロールパネルの「Windows Defenderファイアウォール」→「Windows Defenderファイアウォールを介したアプリまたは機能の許可」を選択し、openocd.exe に対して「プライベート」「パブリック」の両方にチェックが入っている状態にします。
更に、OpenOCDの接続先となる、WSLから見たWindows側のIPアドレスを知る必要があります。/etc/resolv.confでnameserverが指定されているアドレスがそれになるので、事前に調べておきます。
$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.xx.xx.xx <=== このアドレスを覚えておく
gdbのリモート接続時にはこのアドレスを指定します。
$ gdb-multiarch hello_world.elf
:
(gdb) target remote 172.xx.xx.xx:3333 <=== 先ほど調べたアドレスを指定する
この後の実行手順は同じです。
(追記)WSL2用gdb起動スクリプト
以下のようなスクリプトを用意しておくと、いちいちアドレスを調べる手間が省けて便利です。
#!/bin/sh
gdb-multiarch -ex "target remote `tail -1 /etc/resolv.conf|awk '{print $2}'`:3333" $*
上のスクリプトをgdb-pico
という名前で保存しておけば、実行したいELFファイルを指定して
$ gdb-pico hello_world.elf
これだけで、OpenOCDに接続するところまでやってくれます。