« 中華製温調はんだごて(5) | トップページ | 無帰還CR型フォノイコライザの製作(基板頒布あり) »

2025年4月10日 (木)

Windows用 Paspberrypi PICO 公式SDKについての備忘録

ラズベリーパイPICOは安価で高性能なマイコンで、使いこなせればかなり強力なアイテムだ。
開発環境は公式SDK(C/C++)、MicroPython、Arduinoなどが選択でき、わりと気軽に試してみることができる。
ただ、特徴的な機能であるPIO(プログラマブルIO)や、USBの機能などを十分に使いこなすには公式SDKでC/C++での開発が必要になりそうなので、調べながらあれこれ試してみたが、Windows上での公式SDKの使い方がいまひとつわかりにくく、同梱のexampleのコンパイルができても、任意ホルダに配置した独自コードのビルドの方法がわからないなど、どうにも全体的に判然としないことが多かった。

今回は公式SDKのセットアップが完了していて、同梱exampleのbuildが行える、という状態から、
① exampleホルダの中から、任意の特定のプロジェクトのホルダのみを任意の作業ホルダにコピー
② CMakeLists.txtを書き換え
③ buildしてuf2ファイル(PICOに書き込む最終ファイル)を生成

という一連の作業を備忘録として書いておこうと思う。

まずは公式SDKをダウンロードして、Windowsにインストールする。
このサイトの真ん中あたりに"Downlload Windows Pico Installer"というボタンがあるので、クリックしてダウンロードし、
これを実行してインストール。
すると、VS CODE、GCC(Pico用のクロスコンパイラ)、CMake(ビルドシステムの生成ツール)、Ninja(高速ビルドツール)、Git(ライブラリ管理)、pico-sdk(SDKとサンプルコード)などが一括してインストールされる。

まずはexampleのbuildを試してみる。
SDKがインストールされていれば、WindowsのスタートメニューにRaspberry Pi Pico SDK v1.5.1という項目ができて、その中にPico-Visual Studio Codeが生成されているので、これを起動する。そして次の手順でexampleをbuildする。

①ファイルのOpen Folderからexampleのプロジェクトホルダ”pico-examples”を開く。
(場所はC:\Users\(ユーザー名)\Documents\Pico-v1.5.1\pico-examples)
②"Do you trust the authors of the files in this folder?"→Yes
③Select a Kit for pico-examples → "Pico ARM GCC"または"GCC 10.3.1 arm-none-eabi"など、有効なコンパイラを選択
④画面左側のアイコンバーのCMAKE(△マークにスパナ)をクリック
⑤PROJECT OUTLINEの下のプロジェクト名の下の”プロジェクト名(Excutable)”の右側のbuildアイコン(ごみ箱のようなアイコン)をクリック
⑥プロジェクトのbuildホルダ内にuf2ファイルが生成されるので、これをpicoに書き込めばすぐに動作を開始する

以上のようにexampleのbuildはとても簡単にできる。uf2ファイルのPICOへの書き込みは、PICOのBOOTボタンを押した状態でpcにUSB接続すると、メモリデバイスとして認識するので、そこに生成されたuf2ファイルをコピーしてやればよい。

ところがここからが問題なのだが、実際の開発は、任意の開発用ホルダ内に保存したCのソースコードをbuildするという作業になる。
上で試したサンプルのbuildは、まず作業ホルダとして、すべてのサンプルが含まれたpico-exampleホルダを開いておいて、その状態からその中に含まれる特定のプロジェクト(たとえばblink)を選んでbuildするというやり方になっていて、
たとえば最初に選ぶ作業ホルダをpico-exampleホルダの中のblinkホルダにしてbuildしようとするとエラーになってしまう。

なので、任意の場所に作ったプロジェクトホルダの中に保存したコードをbuildする、という課題に対して、まずはpico-exampleの中の任意のプロジェクトホルダを、別の場所にコピーして、それをbuildできるようにする、ということを実行してみたい。

今回は、pico-exampleに入っている、adc\microphone_adcを例にやり方を紹介する。

まずはpicoの任意の開発用ホルダに、microphone_adcをホルダごとコピーする。開発ホルダはここではc:\pico_prjとする。
microphone_adc内にbuildホルダが存在していれば、念のためその中身は空にしておく。
次にmicrophone_adcのホルダ内のCMakeLists.txtを次のように書き換えて保存する。

###################ここから############################
cmake_minimum_required(VERSION 3.13)

# pico-sdkのパス(適宜書き換えてください)
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(microphone_adc C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_executable(microphone_adc
    microphone_adc.c
)

target_link_libraries(microphone_adc pico_stdlib hardware_adc)

pico_add_extra_outputs(microphone_adc)
######################ここまで###########################

あとは上書いた手順で、CMAKEアイコンを押して、”PROJECT OUTLINE”の下のmicrophone_adcの下のmicrophone_adc(Executable)の横にあるbuildアイコン(ごみ箱のようなアイコン)を押せばbuildが実行される。
このCMakeLists.txtの記述中、ターゲットのホルダ名microphone_adcが4箇所、ソースファイル名microphone_adc.cが1箇所出てくるが、これはプロジェクト名、ファイル名に応じて都度書き換えること。

【重要事項】
最初、blinkのコピーを実行してうまくいったので、CMakeLists.txtをそのまま流用したら、microphone_adc.cの
#include "hardware/adc.h"
の行でエラーになってしまった。adc.hが見つけられない、という内容のエラーだった。
そこで原因を調べたら、CMakeLists.txtのtarget_link_libraliesの記述が
target_link_libraries(microphone_adc pico_stdlib )
となっていて、hardware/adc.hが検索範囲に含まれていなかったのが原因だった。なので、hardware_adcを追加して、
target_link_libraries(microphone_adc pico_stdlib hardware_adc)
とするとOKになった。

もともとのPICO SDKの#includeの検索範囲は、
${PICO_SDK_PATH}/src/common/pico_base/include
${PICO_SDK_PATH}/src/rp2_common/hardware_adc/include(← この下に hardware/adc.h がある)
(PICO_SDK_PATHはpico-sdkのパス)
となっていて、カッコ書きしたようにadc.hは範囲から外れているので、上のようにtgetar_link_librariesに追記する必要がある。

書式として、hardware/adc.hがhardware_adcとなっているが、このほかにも以下の例のようになっている。

pico/stdlib.h         →             pico_stdlib
hardware/spi.h     →             hardware_spi
hardware/i2c.h     →             hardware_i2c
……etc


そういうわけで、ようやく任意ホルダにPICO SDKのソースプロジェクトを構築する準備ができました(^-^)


【20250411追記】
せっかくなので、動作確認可能なサンプルで試してみよう。
pico-examplesの中身を見ていたら、i2cホルダの中にssd1306_i2cというプロジェクトがあるのを見つけた。
ssd1306はoledの表示パネルだ。aliexpressでも安く販売している。
このサンプルプロジェクトを、上述したように任意の場所にコピーして、buildして動作確認してみる。

ssd1306との接続はreadmeに書いてあるが、GP4→SDA、GP5→SCL、あとはGNDと3.3V。

まずpico-examplesのi2cの中にssd1306_i2cホルダがあるので、これを任意の場所にコピーする。
次に、コピーしたssd1306_i2cホルダの中のCMakeLists.txtの内容を次のように変更して保存する。

####################ここから
cmake_minimum_required(VERSION 3.13)

# Set the path to the SDK
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")

# Import the SDK
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(ssd1306_i2c C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_executable(ssd1306_i2c
ssd1306_i2c.c
)

target_link_libraries(ssd1306_i2c pico_stdlib hardware_i2c)
pico_add_extra_outputs(ssd1306_i2c)
###################ここまで

上でも注意したとおり、ホルダ名のssd1306_i2cが4箇所、ファイル名のssd1306_i2c.cが一箇所あるので、このCMakeLists.txtを他のプロジェクトに流用する場合などは変更忘れに注意すること。
また
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")
の行はpico-sdkのパスを設定しているが、別の場所にインストールしている場合は修正すること。

次の手順でbuildする。
①Pico-Visual Studio Codeを起動して、ファイルのOpen Folderからコピーしたssd1306_i2cホルダを開く。
②Select a Kit for pico-examples → "Pico ARM GCC"または"GCC 10.3.1 arm-none-eabi"など、有効なコンパイラを選択
③左のアイコンバーから△にスパナのマークのCMAKEのアイコンをクリック。
④PROJECT OUTLINEペインのssd1306_i2cの下のssd1306_i2c(Executable)にカーソルを合わせると、右の方にゴミ箱のような形のbuildアイコンが表示されるので、これを押す。
⑤ssd1306_i2cホルダの中のbuildホルダの中にssd1306_i2c.uf2が生成されているのを確認
⑥PICOのBOOTSELボタンを押しながらPCにUSBケーブルで接続すると、ドライブとして認識するので、そこにssd1306_i2c.uf2をコピー。

以上で、自動的にリセットがかかり、プログラムが起動する。
互換ボードで確認した様子を動画1に示す。


動画1

\(^o^)/



【20250412追記】PCとのシリアル通信
pico-examplesのi2cホルダの中に、bmp280_i2cというサンプルがある。BMP280は有名な気象センサで、温度、気圧が測定できるのでたいへん便利なデバイスだ。接続は、GP4→SDA、GP5→SCL、あとはGNDと3.3V

さっそくやってみようと思ったが、測定結果はどこに表示されるのだろうか?
ソースコードbmp280_i2c.cを見てみると、いきなりprintf文で表示している。何か釈然としないと思いつつ、手順に従ってbuildしてみた。つまり、
①bmp280_i2cのホルダを任意の作業ホルダにコピー
②CMakeLists.txtを書き換え(以下のとおり)

#################ここから
cmake_minimum_required(VERSION 3.13)

# Set the path to the SDK
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")

# Import the SDK
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(bmp280_i2c C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_executable(bmp280_i2c
bmp280_i2c.c
)

target_link_libraries(bmp280_i2c pico_stdlib hardware_i2c)
pico_add_extra_outputs(bmp280_i2c)
#################ここまで

③VS CODEでホルダを開いて、コンパイラを選択して、CMAKEからbuild。
④buildホルダにbmp280_i2c.uf2ができたので、これをpicoに書き込み。

ここまでは問題なくできたが、書き込みが終わっても何も起こらない。表示するものがないので当然といえば当然なのだが、念のためCOMポートで認識していないかPC側を調べたが、認識していない。はて……?

結論を先に書くと、CMakeLists.txtのtarget_link_librariesに、”pico_stdio_usb”を追加する必要がある。つまり

target_link_libraries(bmp280_i2c pico_stdlib hardware_i2c pico_stdio_usb)

とすればOKだ(^-^)
pico_stdio_usbについては、CMakeLists.txtのこの部分で定義しているだけで、ソースコード上では特に#includeしているということもなく謎といえば謎だ……(実際はイニシャライズが必要→後述)

CMakeLists.txtを上記のように修正して、buildして書き込むと、picoは再起動し、パソコンからCOMポートとして認識するので、デバイスマネージャなどでポート番号を調べて、ターミナルソフトで確認する。速度は115200。表示の様子を図1に示す。

20250412bmp280
図1.測定値の表示


ところで、マイコンの開発ではデバッグツールがない場合でも、何らかの表示手段が必要で、通常はUSBシリアルでマイコンからの情報をPCに表示させるようにする。通常はターゲットのマイコンのUART端子にUSB-UARTインタフェイスを接続して、これをPCに接続し、PC上のターミナルソフトを使って表示させる場合が多い。
PICOの場合はもともとUSBインターフェイスを備えているのでこれを使えばよいのだが、この情報をあまり見かけないのは不思議だ。
これは上に書いたように、CMakeLists.txtでpico_stdio_usbをターゲットに登録し、下記のようにmain()でstdio_usb_init()を実行すれば、printfでの出力が可能になる。
UARTにprintfで出力するだけのプロジェクトは以下のとおり。

プロジェクトホルダ:USB_Serial
Cソースファイル:USB_Serial.c

/////////////////////////////USB_Serial.cここから
#include <stdio.h>
#include "pico/stdlib.h"

int main() {
stdio_usb_init();
while (true) {
printf("Hello via USB CDC!\n");
sleep_ms(1000);
}
/////////////////////////////ここまで


################CMakeLists.txtここから
cmake_minimum_required(VERSION 3.13)

# Set the path to the SDK
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")

# Import the SDK
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(USB_Serial C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()

add_executable(USB_Serial
USB_Serial.c
)

#pico_generate_pio_header(USB_Serial ${CMAKE_CURRENT_LIST_DIR}/i2s_out.pio)

target_link_libraries(USB_Serial pico_stdlib pico_stdio_usb)
pico_add_extra_outputs(USB_Serial)
################ここまで


つまり、次の2つをプロジェクトに盛り込めば、printfでUART出力ができる。すなわち、
①CMakeLists.txtでtarget_link_librariesにpico_stdio_usbを追加する
②main()でstdio_usb_init();(またはstdio_init_all();)を実行

ところで、先ほどのbmp280_i2cのbmp280_i2c.cを見ても、stdio_usb_init();が書かれていない。どういうことだろうか?
このコードには、stdio_usb_init();の代りにstdio_init_all();が記述されている。
stdio_init_all()には利用可能な標準出力バックエンド(USBやUART)などをすべて初期化する関数で、これにはstdio_usb_init()が含まれているので、間接的にstdio_usb_init()が実行されるということだそうだ。


そういうわけで、CMakeLists.txtの書式と、シリアルモニタの使い方がわかったのでPICO公式の開発もやりやすくなりました(^-^)

 

| |

« 中華製温調はんだごて(5) | トップページ | 無帰還CR型フォノイコライザの製作(基板頒布あり) »

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« 中華製温調はんだごて(5) | トップページ | 無帰還CR型フォノイコライザの製作(基板頒布あり) »