RaspberryPi PICOのビルド環境構築 on Linux

 Linuxが動く従来のシングルボードコンピュータのRaspberryPiシリーズとは異なり、もっと素朴なマイコンボードのRaspberryPi PICOが2020年に発売になりました。しばらく入手困難な状況でしたが、やっと定価で店頭購入できるような状況になってきたようです。

 単なるマイコンボードなら各種Arduino(及び互換機)を使えばいいのでは?と思うわけですが、RaspberryPi PICOはUSBコントローラを内蔵しているのが大きな違いだと思っています。ほとんどのArduino系のマイコンボードはUSBシリアル変換チップを搭載し、マイコンそのものはシリアル通信しかサポートしてないことがほとんどです*1。ですが、RaspberryPi PICOはUSBコントローラを内蔵しており、USBデバイスを作ることができます。さらには、このコントローラはUSBホストにもなることができるそうです。
 つまり、Arduino系でUSB機器を自作しようと思ったら、基本的にはUSBシールドのようなオプションが必要になります*2。一方、RaspberryPi PICOなら単体でUSBを扱うことができるので、安価かつコンパクトに実装することができます。

 というわけで、RaspberryPi PICOを入手し、Ubuntu20.04に開発環境構築したので手順を残しておきます。
 


はじめに

 公式な手順は以下のgetting-started-with-pico.pdfに記載されていますので、RaspberryPi PICOが初めての方は必読です(英語のみで日本語を含め他言語版はありません)。
Getting started with Raspberry Pi Pico(PDF)

 但し、この手順書にはLinux環境への開発環境構築も載ってはいるのですが、そのLinuxマシンはシングルボードコンピュータのRaspberryPiシリーズが前提となっています。
 また、VS CODEも導入する前提となっていますが、私は他のエディタでコード書くつもりなのでVS CODEも不要です。
 
 つまり、「普通のAMD64なPC」で「VS CODEを使用しない」開発環境*3構築をしたかったので、公式の手順に変更を加えたものが以下の説明になります。
 


各種ソフトウェアインストール

 PDFの"Chapter 1. Quick Pico Setup"の手順を微妙に変更して実行します。
 

開発作業用ディレクトリの作成

 本投稿では、開発作業用のディレクトリを~/devとして話を進めます。後述のインストールスクリプト(pico_setup.sh)では./picoというディレクトリが切られますので、RaspberryPi PICO絡みのリソースは~/dev/pico/配下に配置されることになります。

$ mkdir ~/dev
$ cd ~/dev

 

インストールスクリプトのダウンロード

 SDKやToolchainやらをインストールしてくれる公式のスクリプトをダウンロードして実行権限を付与します。

$ wget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh
$ chmod +x pico_setup.sh

 

インストールスクリプト環境変数設定

 PDFには上記のインストールスクリプト内容の説明が無いのですが、中身を読むとシングルボードコンピュータのRaspberryPiシリーズを前提にしていることが判ります。
 また、各種環境変数の設定によって挙動を制御できる作りになっていることも解ります。
 VS CODEをインストールしたくないのと、シングルボードコンピュータのRaspberryPi固有のUARTの設定をしたくないので以下の二つの環境変数を設定します。

$ export SKIP_VSCODE=1
$ export SKIP_UART=1

 

インストール

 インストールスクリプトを実行します。

$ ./pico_setup.sh

 SKUP_UART=1にしたことの副作用で、minicomパッケージが入ってない状態になりますので入れておきます(ビルドに必須ではありません)。

$ sudo apt install minicom

 

(補足)

 ここまでの手順で既にビルド環境構築は完了しています。PDFを読み進めると、以下のようにSDKやToolchaiinの導入手順が出てきますが、pico_setup.shで実施済みとなるため作業不要です。

"2.1. Get the SDK and examples"
pico_setup.shで各reposはclone済みのため不要。~/dev/pico-sdk, pico-examples, pico-extras, pico-playgroundにcloneされている。
"2.2. Install the Toolchain"
libnewlib-arm-none-eabiパッケージのみpico_setup.shでインストールされないので手動で入れる必要があるかと思ったが、libnewlib-arm-none-eabiの依存関係でlibnewlib-arm-none-eabiも自動でインストールされているので作業不要。

 


サンプルプログラムのビルド

 PDFの"3.1. Building "Blink""の手順に従って作業します。

$ cd ~/dev/pico/pico-examples
$ cd build
$ export PICO_SDK_PATH=../../pico-sdk
$ cmake ..

 cmakeを叩いた後は以下のような出力が確認できます。

PICO_SDK_PATH is /home/devuser/dev/pico/pico-sdk
PICO platform is rp2040.
Using regular optimized debug build (set PICO_DEOPTIMIZED_DEBUG=1 to de-optimize)
PICO target board is pico.
Using board configuration from /home/devuser/dev/pico/pico-sdk/src/boards/include/boards/pico.h
TinyUSB available at /home/devuser/dev/pico/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040; adding USB support.
Compiling TinyUSB with CFG_TUSB_DEBUG=1
-- Configuring done
-- Generating done
-- Build files have been written to: /home/devuser/dev/pico/pico-examples/build

 ここまでエラーメッセージが出力されていないことを確認し、makeします。

$ cd blink
$ make -j4

 makeを叩いたら以下のような出力が確認できます。

[  0%] Performing build step for 'ELF2UF2Build'
[  0%] Built target bs2_default
[  0%] Built target bs2_default_padded_checksummed_asm
[100%] Built target elf2uf2
[  0%] No install step for 'ELF2UF2Build'
[  0%] Completed 'ELF2UF2Build'
[  0%] Built target ELF2UF2Build
[100%] Built target blink

 make完了すると、以下のようなファイル群が生成されています。

$ ls -ltr
total 1072
drwxrwxr-x 4 devuser devuser   4096 Sep 12 14:17 elf2uf2
-rw-rw-r-- 1 devuser devuser    997 Sep 12 14:18 cmake_install.cmake
-rw-rw-r-- 1 devuser devuser  84526 Sep 12 14:18 Makefile
-rw-rw-r-- 1 devuser devuser 243548 Sep 12 14:18 blink.elf.map
-rwxrwxr-x 1 devuser devuser 392604 Sep 12 14:18 blink.elf
-rw-rw-r-- 1 devuser devuser  59112 Sep 12 14:18 blink.hex
-rwxrwxr-x 1 devuser devuser  20996 Sep 12 14:18 blink.bin
-rw-rw-r-- 1 devuser devuser 334396 Sep 12 14:18 blink.dis
-rw-rw-r-- 1 devuser devuser  42496 Sep 12 14:18 blink.uf2
drwxrwxr-x 4 devuser devuser   4096 Sep 12 14:36 CMakeFiles

 これらのファイルの内、*.elfはデバッガで使用し、*.uf2がRaspberryPi PICO本体に書き込むバイナリとPDFに説明されています。

blink.elf, which is used by the debugger
blink.uf2, which can be dragged onto the RP2040 USB Mass Storage Device

 というわけで、uf2ファイルが生成されているのでビルド完了です。
 


サンプルプログラムのRaspberryPi PICOへの書き込み

 PDFの"3.2. Load and run "Blink""の手順に従って作業します。
 まず、RaspberryPi PICOのBOOTSELボタンを押しながらPCのUSBポートに接続します。正常に認識されていれば、dmesg(syslog)に以下のような出力が確認でき、USBマスストレージデバイスとして認識されているのが判ります。

[ 2302.673250] usb 1-2: new full-speed USB device number 5 using xhci_hcd
[ 2302.823253] usb 1-2: New USB device found, idVendor=2e8a, idProduct=0003, bcdDevice= 1.00
[ 2302.823271] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2302.823286] usb 1-2: Product: RP2 Boot
[ 2302.823297] usb 1-2: Manufacturer: Raspberry Pi
[ 2302.823306] usb 1-2: SerialNumber: ************
[ 2302.936829] usb-storage 1-2:1.0: USB Mass Storage device detected
[ 2302.938061] scsi host0: usb-storage 1-2:1.0
[ 2302.938363] usbcore: registered new interface driver usb-storage
[ 2302.945677] usbcore: registered new interface driver uas
[ 2303.959985] scsi 0:0:0:0: Direct-Access     RPI      RP2              2    PQ: 0 ANSI: 2
[ 2303.962771] sd 0:0:0:0: Attached scsi generic sg0 type 0
[ 2303.964126] sd 0:0:0:0: [sda] 262144 512-byte logical blocks: (134 MB/128 MiB)
[ 2303.964883] sd 0:0:0:0: [sda] Write Protect is off
[ 2303.964900] sd 0:0:0:0: [sda] Mode Sense: 03 00 00 00
[ 2303.965607] sd 0:0:0:0: [sda] No Caching mode page found
[ 2303.965633] sd 0:0:0:0: [sda] Assuming drive cache: write through
[ 2303.986750]  sda: sda1
[ 2303.989008] sd 0:0:0:0: [sda] Attached SCSI removable disk

 自動マウント有効になってれば、以下のような感じでマウントされます(自動でマウントされない場合は手動でマウントします)。

$ df -Th /dev/sd*
Filesystem     Type      Size  Used Avail Use% Mounted on
udev           devtmpfs  1.9G     0  1.9G   0% /dev
/dev/sda1      vfat      128M  8.0K  128M   1% /media/devuser/RPI-RP2
$ ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Sep 12 14:44 /dev/sda
brw-rw---- 1 root disk 8, 1 Sep 12 14:44 /dev/sda1
$ ls -l /media/devuser/RPI-RP2
total 8
-r--r--r-- 1 devuser devuser 241 Sep  6  2008 INDEX.HTM
-r--r--r-- 1 devuser devuser  62 Sep  6  2008 INFO_UF2.TXT
$ cat  /media/devuser/RPI-RP2/INDEX.HTM
<html><head><meta http-equiv="refresh" content="0;URL='https://raspberrypi.com/device/RP2?version=************'"/></head><body>Redirecting to <a href='https://raspberrypi.com/device/RP2?version=************'>raspberrypi.com</a></body></html>
$ cat  /media/devuser/RPI-RP2/INFO_UF2.TXT
UF2 Bootloader v2.0
Model: Raspberry Pi RP2
Board-ID: RPI-RP2

 RaspberryPi PICOにuf2ファイルを書き込みます。前述のようにRaspberryPi PICOはUSBマスストレージデバイスとして認識されていますので、単にファイルコピーするだけです(syncはキャッシュを吐き出して、確実に書込みを完了させる目的です)。

$ cp blink.uf2 /media/devuser/RPI-RP2/
$ sync

 すると、自動でUSB接続が解除され、アンマウントされます。dmesgには以下のような出力が確認できます。

[ 2865.309588] usb 1-2: USB disconnect, device number 5
[ 2865.376000] FAT-fs (sda1): unable to read boot sector to mark fs as dirty

 この例ではsdaとして認識されていたRaspberryPi PICOは既に存在しなくなっています。

$ ls -l /dev/sd*
ls: cannot access '/dev/sd*': No such file or directory

 この時、RaspberryPi PICOでは書き込んだblink.uf2の処理(オンボードLEDの点滅)が既に実行されています。書き込みは完了しているので、RaspberryPi PICOの電源を再投入(USBを抜いて再接続)してもblink.uf2の処理が直ちに開始されます。※書き換えにはBOOTSELボタンを押してUSB接続して、*.uf2を書き込む。
 


自作プログラムのビルド

 PDFの"Chapter 7. Creating your own Project"を参考に作業します。

自作プログラム用のディレクトリ作成

 pico-sdkディレクトリ(~/dev/pico/pico-sdk)と並列の階層に新規ディレクトリを作成します。

$ mkdir ~/dev/pico/my-project1
$ ls -l
total 32
drwxrwxr-x  2 devuser devuser 4096 Sep 12 15:27 my-project1
drwxrwxr-x 12 devuser devuser 4096 Sep 12 14:21 openocd
drwxrwxr-x 29 devuser devuser 4096 Sep 12 14:17 pico-examples
drwxrwxr-x  7 devuser devuser 4096 Sep 12 14:17 pico-extras
drwxrwxr-x 10 devuser devuser 4096 Sep 12 14:17 pico-playground
drwxrwxr-x 11 devuser devuser 4096 Sep 12 14:17 pico-sdk
drwxrwxr-x  5 devuser devuser 4096 Sep 12 14:18 picoprobe
drwxrwxr-x  7 devuser devuser 4096 Sep 12 14:18 picotool
$ cd ~/dev/pico/my-project1

 

ソース(*.c)とCMakeLists.txtとpico_sdk_import.cmakeを配置
  • *.c

 PDFには明示されていませんが、Cのソースファイル名とディレクトリ名は一致している必要はないようです(問題無くビルドできました)。

  • CMakeLists.txt

 PDFに例示されたCMakeLists.txtの以下の各項目の記載がほぼ必要なようです。target_link_librariesなどは自作プログラムに合わせて追加が必要です。

cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(test_project)
pico_sdk_init()
add_executable(test
  test.c
)
pico_add_extra_outputs(test)
target_link_libraries(test pico_stdlib)

 もう少し詳しい説明はSDKのPDFに記載されています。
Raspberry Pi Pico C/C++ SDK(PDF)

  • pico_sdk_import.cmake

 SDKから単純にコピーするだけで編集は不要です。

$ cp ../pico-sdk/external/pico_sdk_import.cmake .

 

ビルドディレクトリの作成
$ mkdir build
$ cd build

 

環境変数の設定とcmake

 SDKのパスを設定して、cmakeを叩きます。

$ export PICO_SDK_PATH=../../pico-sdk
$ cmake ..

※エラー発生後に再実行時する際は、CMakeCache.txtを削除してからcmakeを叩く。或いはbuildディレクトリ内を全削除しても良い。
 

make
$ make -j4

 正常にビルド出来たら、出来上がった*.uf2をRaspberryPi PICOに書き込みます(サンプルプログラムの場合と同様に、BOOTSELボタンを押しながらRaspberryPi PICOをUSB接続し、出現したディスクにファイルコピーします)。
 



以上。

*1:ProMicroのATmega 32U4のように例外もあります

*2:ATmega 32U4のような例外を除く

*3:VS CODEを使用しないのでIDEが無いので開発環境というよりはビルド環境と言った方が正確な表現かもしれません。