Raspberry Pi Pico C/C++ SDK 環境構築 on Windows 10

# About
- Windows 10上でC/C++ SDKを使用したRaspberry Pi Picoの開発環境構築を行います。
	- ビルド
		- `Developer Command Prompt for VS 2019` を使用
		- `Developer Command Prompt for VS 2019` と `VSCode`を使用
		- `MSYS2` を使用  ★おすすめ
	- リモートデバッグ
		- `gdb` コマンドを使用
		- `gdb` と`VSCode` を使用  ★おすすめ
- いくつかの方法を紹介しますが、以下の組合せが一番楽だと思います。(Visual Studioのインストール不要)
	- コーディング: VSCode
	- ビルド: MSYS2
	- リモートデバッグ: VSCode
- リモートデバッグが不要な方は、前半の内容だけで大丈夫です

## 環境
- 基本環境
	- Windows10 64-bit
	- Raspberry Pi Pico
		- リモートデバッグを試す場合は2台
- その他
	- 手順毎に必要なツールは、都度記載します
	- ソースコード取得のためのgitは既にインストール済みとします
	- `getting-started-with-pico.pdf` にはpythonのインストールも必要と書いてありましたが、今回の内容だけであれば不要でした


## 情報源
- Web site
	- https://www.raspberrypi.org/documentation/pico/getting-started/
		- https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf     ★★★本記事の内容はほとんどこのpdfと同じ
		- https://datasheets.raspberrypi.org/pico/pico-datasheet.pdf
		- https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
		- https://datasheets.raspberrypi.org/rp2040/hardware-design-with-rp2040.pdf
		- https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-c-sdk.pdf
		- https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-python-sdk.pdf
		- https://rptl.io/pico-doxygen
- Raspberry Pi Pico SDK
	- https://github.com/raspberrypi/pico-sdk
	- https://github.com/raspberrypi/pico-examples
	- https://github.com/raspberrypi/pico-project-generator
- Others
	- https://github.com/raspberrypi/pico-playground
	- https://github.com/raspberrypi/pico-extras
	- https://github.com/raspberrypi/pico-tflmicro
	- https://github.com/raspberrypi/pico-bootrom
	- https://github.com/raspberrypi/pico-feedback
- tools
	- https://github.com/raspberrypi/picotool
	- https://github.com/raspberrypi/picoprobe
	- https://github.com/raspberrypi/pico-setup
- MicroPython
	- https://github.com/raspberrypi/pico-micropython-examples


## その他
- サンプルプロジェクト
	- https://github.com/iwatake2222/pico-work/tree/5179ff37ebe2b274bef58ed37b30b56f6f7a278c
	- 今後も更新していく予定なので、本記事と同じ内容を得るには上記commit idも指定してください
- 本記事内では、各フォルダは以下の位置にあるとします。
	- Windows用cmake: `C:\iwatake\tool\cmake-3.18.0-rc1-win64-x64\bin`
	- ARM GCC: `C:\iwatake\tool\gcc-arm-none-eabi-10-2020-q4-major\bin`
	- MSYS2: `C:\msys64`
	- ワークフォルダ: `C:\iwatake\devel\pico-work`
- 僕の作業メモ (本記事に記載されていないことが残っているかも)
	- https://zenn.dev/iwatake2222/scraps/8ace540ca04421
	- https://zenn.dev/iwatake2222/scraps/725fc773fcfd7d

# プロジェクトを用意する
## プロジェクト構造を作成する
- 適当な場所でGitBashを開き、ワークフォルダを作ります。その中に、pico-sdkをcloneします。
	- ワークフォルダ名を`pico-work` とします
		- その下に、実際に自分のソースコードなどを配置するフォルダを作ります。今回は`pj_base` とします
		- `pj_base` と同レベルの位置に、`pico-sdk` を配置します
	- ここでは、`pico-sdk` を`git submodule` として用います。他にも、cmake時に自動でダウンロードさせたり、完全にローカルで持つ方法もあります
- `pico-sdk`　を使うのに必要なファイル(`pico_sdk_import.cmake` )を自分のワークフォルダにコピーしておきます
- また、その他必要な空ファイルだけ作っておきます

```sh:GitBash
mkdir pico-work && cd pico-work
git init
git submodule add https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk && git submodule update --init && cd ..
touch CMakeLists.txt
cp pico-sdk/external/pico_sdk_import.cmake .
mkdir pj_base && cd pj_base
touch CMakeLists.txt Main.cpp
```

```txt:構造
pico-work
├─CMakeLists.txt
├─pico_sdk_import.cmake
├─pico-sdk/
└─pj_base/
        CMakeLists.txt
        Main.cpp
```

## CMakeとソースコードを用意する
本記事の主題は環境構築なので、ソースコード関係はとりあえずコピペしてください。
重要なポイントとして、`getting-started-with-pico.pdf` では`PICO_SDK_PATH` の環境変数を設定する必要があると書かれています。ここではpico-sdkがどこにあるか既に知っているのでトップレベルのCMakeLists.txt内で指定しています。逆に、環境変数で設定されているとうまくいかないかもしれません。

```cmake:pico-work/CMakeLists.txt
cmake_minimum_required(VERSION 3.12)

set(PICO_SDK_PATH ${CMAKE_CURRENT_LIST_DIR}/pico-sdk)
include(pico_sdk_import.cmake)

set(ProjectName "pico-work")
project(${ProjectName})
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_subdirectory(pj_base)
```

```cmake:pico-work/pj_base/CMakeLists.txt
set(BinName "pj_base")
add_executable(${BinName}
	Main.cpp
)

pico_enable_stdio_usb(${BinName} 1)
pico_enable_stdio_uart(${BinName} 1)

target_link_libraries(${BinName} pico_stdlib)
pico_add_extra_outputs(${BinName})
```

```cpp:pico-work/pj_base/Main.cpp
#include <cstdint>
#include <cstdio>

#include "pico/stdlib.h"

int main() {
	stdio_init_all();
	const uint32_t LED_PIN = 25;
	gpio_init(LED_PIN);
	gpio_set_dir(LED_PIN, GPIO_OUT);

	while (true) {
		printf("Hello, world!\n");
		gpio_put(LED_PIN, 1);
		sleep_ms(250);
		gpio_put(LED_PIN, 0);
		sleep_ms(250);
	}

	return 0;
}
```

# ビルド環境を構築する
Visual Studio 2019を使用する方法と、MSYSを使用する方法の2つを紹介します。どちらでもできることは同じはずですが、Visual Studio 2019を使用するのが正式な方法です。何か問題があったらVisual Studio 2019で正規の方法でも試すことをお勧めします。

## ビルド環境を構築する (VS2019)
### インストール
- Visual Studio 2019
	- インストール時に、Windows 10 SDKも追加すること
- ARM GCC
	- https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
	- 僕は、インストーラ無しの`gcc-arm-none-eabi-10-2020-q4-major-win32.zip` を使用。その後、`arm-none-eabi-c++.exe` が格納されているbinディレクトリをパスに追加しました
	- インストーラを使用する場合は、インストール時にADD PATHにチェックを付けること
- Windows用cmake
	- `cmake.exe` が格納されているbinディレクトリをパスに追加
	- 注意: 別途msys等をインストール済みで、msysの/usr/bin等にもパスが通っている場合には無効にしておく

### ビルドする
- `Developer Command Prompt for VS 2019` を開き、`pico-work` を作成したフォルダに移動して下記コマンドを実行します
- 成功したら、`pico-work\build\pj_base\pj_base.uf2` が作られているはずです。これを、picoに書き込めばLEDがチカチカしながら、ターミナルに"Hello, world!" が出力されます。

```sh:VSCommandPrompt
cd C:\iwatake\devel\pico-work
mkdir build && cd build
cmake -G "NMake Makefiles" ..
nmake
```

## ビルド環境を構築する (VS2019 + VSCode)
### インストール
- Visual Studio Code
	- 以下のエクステンションをインストール
		- ms-vscode.cpptools
		- ms-vscode.cmake-tools

- VSCodeの設定
	- Manage (左下(ナビゲーションバーの左の歯車アイコン)) -> Settings -> Extensions -> CMake Tools configuration 
		- `Cmake: Generator`
			- `NMake Makefiles`


### ビルドする
- `Developer Command Prompt for VS 2019` を開き、`code` コマンドによってVSCodeを起動します
	- ★★★非常に重要です。通常の手順でVSCodeを起動するとビルドに失敗します
- 起動したVSCodeで`pico-work` フォルダを開く。(フォルダをドラッグ&ドロップするのが楽)
- ctrl+shift+pでコマンドパレットを開き、`CMake: Configure`
	- `GCC for arm-none-eabi` を選択
- ctrl+shift+pでコマンドパレットを開き、`CMake: Build`
- 成功したら、先ほどと同様にbuildフォルダの下にpj_base.uf2が作られます

### その他
- デフォルトだとCMakeLists.txtを編集するたびに自動的にconfigureされてしまいうざいので、VSCodeのsettingsから`Cmake: Configure On Open` と`Cmake: Configure On Edit` をoffにしておくといいと思います


## ビルド環境を構築する (MSYS2)
### インストール
- MSYS2
	- https://www.msys2.org/
		- https://repo.msys2.org/distrib/x86_64/msys2-x86_64-20210105.exe
		- WindowsのPATHを引き継がないようにしておく (デフォルトでそうなっているはず)
	- 実行時は、`MSYS2 MinGW 64-bit` を使用
	- 以下のパッケージをインストールしておく
		- `pacman -S mingw-w64-x86_64-cmake`
	- ↑だけで足りなかったら、以下のパッケージもインストール(一部余計なものを含んでいます)
		- `pacman -S mingw-w64-x86_64-toolchain git make libtool pkg-config autoconf automake texinfo mingw-w64-x86_64-libusb`
- ARM GCC
	- MSYS2(pacman)のコンパイラを使用する場合は不要。不安な場合はこっちを使う
	- https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
	- 僕は、インストーラ無しの`gcc-arm-none-eabi-10-2020-q4-major-win32.zip` を使用。パス追加は不要

### ARM GCCについて
- ARM GCCは、以下の2つの手順でインストール可能です
	- 公式手順書に記載の`https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads` をダウンロードして、MSYSから参照する
		- MSYS2起動後、毎回以下コマンドを実行。または、.bashrc等に記載しておく
		- `export PATH=/c/iwatake/tool/gcc-arm-none-eabi-10-2020-q4-major/bin:${PATH}`
	- MSYS内でインストールする
		- `pacman -S mingw-w64-x86_64-arm-none-eabi-gcc`
- おそらく、上記の2つはまぜるな危険です。どちらか一つの方法を選んでください。不安なら1個目の方法を使ってください。

### ビルドする
- MSYS2を起動し、`pico-work` を作成したフォルダに移動して下記コマンドを実行します
- 成功したら、`pico-work\build\pj_base\pj_base.uf2` が作られているはずです。

```sh:msys
# export PATH=/c/iwatake/tool/gcc-arm-none-eabi-10-2020-q4-major/bin:${PATH}
cd /c/iwatake/devel/pico-work
mkdir build && cd build
cmake .. -G "MSYS Makefiles" 
make
```

# リモートデバッグ環境を構築する
基本的には、getting-started-with-pico.pdfの「Appendix A: Using Picoprobe」の通りです。

## Picoprobeをビルドする
- 本手順は1度だけ必要です
- デバッガとして動作するRaspberry Pi Pico用のファームウェア(uf2)を作成します
- ここでは、MSYS2を使ってビルドします。
- ビルドに成功したら、`picoprobe.uf2` というファイルが生成されるので、デバッガとして使用したいRaspberry Pi Picoに書き込みます。
- 同じものを以下に配置しておきます
	- https://github.com/iwatake2222/pico-work/releases/download/20210211/picoprobe.uf2
- 本作業が終わったら`picoprobe` フォルダは不要なので削除して大丈夫です

```sh:msys
# export PATH=/c/iwatake/tool/gcc-arm-none-eabi-10-2020-q4-major/bin:${PATH}
cd /c/iwatake/devel/pico-work
git clone https://github.com/raspberrypi/picoprobe.git
cd picoprobe
mkdir build && cd build
export PICO_SDK_PATH="../../pico-sdk"
cmake .. -G "MSYS Makefiles" 
make
```

## ドライバをインストール
- 本手順は1度だけ必要です
- https://zadig.akeo.ie/
	- https://github.com/pbatard/libwdi/releases/download/b730/zadig-2.5.exe
- 実行して、以下を選択してドライバをインストールする
	- PicoProbe (Interface 2) -> Install Driver
	- Picoprobe用のpicoを接続した状態だと、自動で選択されたと思います。そうじゃなければ自分で選択してください

## OpenOCDをビルドする
- 本手順は1度だけ必要です
- デバッガとして動作するRaspberry Pi Pico用と通信をする、OpenOCDをビルドします。ビルドにはMSYS2を使用します。
- 以下のパッケージをインストールします。

	```sh:msys
	pacman -Syu
	pacman -Su
	pacman -S mingw-w64-x86_64-toolchain git make libtool pkg-config autoconf automake texinfo mingw-w64-x86_64-libusb
	# 全部default設定を選択 (Enter押すだけ)
	```

- 以下コマンドによってビルドします。

	```sh:msys
	git clone https://github.com/raspberrypi/openocd.git --branch picoprobe --depth=1
	cd openocd
	./bootstrap
	./configure --enable-picoprobe --disable-werror
	make -j4
	```

- 以下コマンドによってOpenOCDを起動します。
- リモートデバッグ実行時は、事前に必ず起動しておくようにします。起動時のパスはどこでもいいです。起動後は放置して大丈夫です

	```sh:msys
	cd openocd
	src/openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl
	```

![ocd.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/0ff30390-35d8-a948-2394-cd44f15048f2.jpeg)


## デバッガとデバッグ対象のRaspberry Pi Picoを接続する
https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf より


![wire.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/73ec1e01-2767-f1da-41e0-02bcbc7862c3.jpeg)



## デバッグ用ビルドをする
- ビルド時に、以下のオプションを付けてビルドします。無くても実行は出来ますが、ブレークポイントを張ったりできません。
	- `CMAKE_BUILD_TYPE=Debug`
		- デバッグ情報付加
	- `PICO_DEOPTIMIZED_DEBUG=on`
		- 最適化しない
- MSYS2からビルドする場合は以下のようになります

	```sh:msys
	# export PATH=/c/iwatake/tool/gcc-arm-none-eabi-10-2020-q4-major/bin:${PATH}
	cmake .. -G "MSYS Makefiles"  -DCMAKE_BUILD_TYPE=Debug -DPICO_DEOPTIMIZED_DEBUG=on
	make
	```
- Developer Command Prompt for VS 2019からビルドする場合は以下のようになります

	```sh:VSCommandPrompt
	cmake -G "NMake Makefiles" .. -DCMAKE_BUILD_TYPE=Debug -DPICO_DEOPTIMIZED_DEBUG=on
	nmake
	```

## リモートデバッグする (gdbコマンド)
- 上述の通り、MSYS2上でOpenOCDを起動しておきます。これとは別のMSYS2を開き、ビルドしたelfファイルがある場所で以下のようにデバッグが可能です。

```sh:msys
cd /c/iwatake/devel/pico-work/build/pj_base/
gdb-multiarch pj_base.elf

(gdb)
target remote localhost:3333
load
monitor reset init
b main
continue
n
n
n
quit
```

![gdb.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/0d2c3c28-58b5-0dbd-e04d-7c43f3d86c66.jpeg)


## リモートデバッグする (VSCode)
### インストール
- Visual Studio Code
	- 以下のエクステンションをインストール
		- marus25.cortex-debug

### 準備
- ワークフォルダをVSCodeで開きます (ビルドをしないでデバッグだけの場合は、普通に開いて大丈夫です)
- `.vscode` フォルダがない場合は自分で作ります
	- TERMINAL上で、`mkdir .vscode`
- 設定ファイルのひな形をダウンロードします
	- `curl https://raw.githubusercontent.com/raspberrypi/pico-examples/master/ide/vscode/launch-remote-openocd.json -o .vscode/launch.json`
	- `curl https://raw.githubusercontent.com/raspberrypi/pico-examples/master/ide/vscode/settings.json -o .vscode/settings.json`
- ※上記コマンドは一例なので、どのようにダウンロードしても大丈夫です

### launchファイルの修正
- `launch.json` ファイルにデバッグ用の設定が記載されていますが、自分の環境に合わせて修正します。修正箇所は主に以下の通りです。
	- `executable` : elfファイル。トップレベルのCMakeLists.txtにadd_executableが含まれていたらそれが使用される模様。そうじゃないとエラーになるので、自分で指定する
	- `gdbPath` : gdb実行ファイルのパス。今回はmsysのgdbを指定するのでフルパスで指定する
	- `gdbTarget` : 別途msysで起動中のOpenOCDで設定したターゲットのURLとポートを指定する
	- `svdFile` : ハードウェア情報が記載されたファイルへの場所。デフォルトだと環境変数としての`PICO_SDK_PATH` を使用しているので、ここも変更
- 結果、以下のようになります。これは僕の環境の場合ですので、適宜変更をしてください。

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Pico Debug",
            "type":"cortex-debug",
            "cwd": "${workspaceRoot}",
            // "executable": "${command:cmake.launchTargetPath}",
            "executable": "${workspaceRoot}/build/pj_base/pj_base.elf",
            "request": "launch",
            "servertype": "external",
            // This may need to be arm-none-eabi-gdb depending on your system
            "gdbPath" : "C:/msys64/mingw64/bin/gdb-multiarch.exe",
            // Connect to an already running OpenOCD instance
            "gdbTarget": "localhost:3333",
            "svdFile": "pico-sdk/src/rp2040/hardware_regs/rp2040.svd",
            "runToMain": true,
            // Work around for stopping at main on restart
            "postRestartCommands": [
                "break main",
                "continue"
            ]
        }
    ]
}
```

### リモートデバッグする
F5キーを押すことで、デバッグが開始されます。自動的に、Main.cppのmain関数先頭でブレークポイントがかかって止まるはずです。
この場合も、別途OpenOCDを起動しておく必要があります。

![vscode.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/b4db547f-ab89-2268-0858-aac79310e4cf.jpeg)


# おまけ
## デバッグ線
僕はRaspberry Pi Picoの内1つはデバッガ専用とするため、デバッグ用配線は直接接続してみました。
ただ、ターゲットとなるRaspberry Pi PicoにもUSBを接続してUART (USB CDC)接続しようとしたら、上手く動きませんでした。

![debug.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/b7b04652-49c1-1092-8180-b82a84554c71.jpeg)

## RUN(Reset)ボタン
こんな感じにResetボタンを付けると便利です。

![reset.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214268/de7a64a7-e58d-387e-6eb0-35db96416c28.jpeg)


## 自分用コマンドまとめ
```
[msys]
cd openocd
src/openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl

[vs]
mkdir build && cd build
cmake -G "NMake Makefiles" ..
cmake -G "NMake Makefiles" .. -DCMAKE_BUILD_TYPE=Debug -DPICO_DEOPTIMIZED_DEBUG=on
nmake


[msys]
cmake .. -G "MSYS Makefiles" 
cmake .. -G "MSYS Makefiles"  -DCMAKE_BUILD_TYPE=Debug -DPICO_DEOPTIMIZED_DEBUG=on
make
```