Arduino IDE で Raspberry Pi Picoの C/C++ SDKの関数を使用する

# １．Arduino IDE と C/C++ SDKの関数

ラズパイPico で実現したいことがあって、経験者の話とか使えそうな関数があるかな？　とネットで調べるとPython や C/C++ SDKでは成功例とか便利な関数ライブラリが用意されているけど、Arduino IDE用には無い、残念！　と、悔しい思いをしたことが何度もありました。

■ しかし、下記 arduino-picoというサイトに **「Raspberry Pi Pico SDK の完全なコピーが Arduino コアに含まれており、コア内のすべての機能が標準リンクライブラリ内で使用できます！！」** との記述（Googleで翻訳）を発見！

https://arduino-pico.readthedocs.io/en/latest/sdk.html

おおっ、迷える子羊に神の言葉！　あぁ、ありがたや、なんまんだぶ、なんまんだぶ。アッラー・アクバル。南無大師遍照金剛。アーメン・・・　わ～い、テンション一気に爆上がり～！　Pythonの入門書読み始めてたけど、ふん、こんなものゴミ箱行きだぁ！

■ しかも **「これらの関数を呼び出す単純なプログラムの場合は、以下に示すように適切なヘッダーを含めるだけです」** とのこと。

```C++
#include "pico/stdlib.h"

void setup() {
    const uint LED_PIN = 25;
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
    while (true) {
        gpio_put(LED_PIN, 1);
        sleep_ms(250);
        gpio_put(LED_PIN, 0);
        sleep_ms(250);
    }
}
void loop() {}
```

えっ、たったの1行 "～.h" を、これ入れるだけ？　どっかからライブラリをダウンロードしてインストールとかしなくてＥの？　ホンマでっか！！

・・って、大発見したつもりでいる訳ですが「知らなかったの？そんなの千年前から常識だよ」という上級者の方はこれ以上読む必要はありません、時間の無駄です。

※ どーでもいーけどURLの .io ってどこ？ ⇒ イギリス領インド洋地域(Indian Ocean Territory)でセーシェル等の約2300の島がある。

※ このサイト、C/C++ SDK以外にも興味深いタイトルの記事が色々あります。

■下記の注意事項、なんかよく理解できないところもありますが、気にせずスルーして先に進むことにしましょう。

:::note info
**Raspberry Pi Pico SDK (PICO-SDK) の使用**
■注: 独自のアプリで SDK 関数を呼び出す場合、コアとライブラリは実行する Pico への変更を認識しません。 したがって、そうすることで特定のライブラリの機能が壊れる可能性があります。

■マルチコア（CORE1）処理
警告: SDK を使用して CORE1 でマルチコア アプリケーションを生成することはできますが、Arduino コアではそれらのアプリケーションを適切に実行できない可能性があります。 特に、フラッシュ書き込みを伴うもの (EEPROM、ファイルシステムなど) は、CORE0 がフラッシュに書き込んでいる間に CORE1 がフラッシュから読み取ろうとするため、クラッシュする可能性があります。

■PIOASM（PIOプロセッサ用のコンパイル）
PIOASM ツールのプリコンパイル済みバージョンはダウンロード パッケージに含まれており、CLI から実行できます。CLI を必要とせずに Web ブラウザーで実行できる完全オンライン バージョンの PIOASM もあります: 
https://wokwi.com/tools/pioasm 
 (GitHub source: https://github.com/wokwi/pioasm-wasm)
このツール用の Docker コードも次の場所にあります: 
https://github.com/kahara/pioasm-docker
:::

# ［参考資料①］ Pico C/C++  SDKのデータシート

PDF形式、英文201ページのドキュメントです。

https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf

この資料は読まなくても問題ありません。後日、必要になるかもしれませんので目次だけ紹介します。

:::note info
目次
１章：SDKについて
２章：SDKのアーキテクチャ
３章：Programmable I/O (PIO) の使い方
４章：Pico-C-SDK のドキュメント　（次の参考資料②のURL）
Appendix A: アプリケーションノート
Appendix B: SDK configuration
Appendix C: CMake build configuration
Appendix D: Board configuration
Appendix E: Building the SDK API documentation
Appendix F: SDK release history
Appendix G: Documentation release history.
:::
この資料で見るべきはアプリケーションノートです。色々な応用例のブレッドボードの実体配線図(fritzing)とサンプルプログラムがあります。

:::note info
**Appendix A: アプリケーションノート**
・7 セグメントLED via GPIO
・DHT-11, DHT-22, AM2302 センサ
・16x2 LCD via TTL
・マイクロフォン using the ADC.
・BME280 温度/湿度/気圧 センサ via SPI
・MPU9250 加速度計/ジャイロスコープ via SPI
・MPU6050 加速度計/ジャイロスコープ via I2C
・16x2 LCD via I2C
・BMP280 温度/気圧 センサ via I2C
・LIS3DH Nano 加速度計 via i2c
・MCP9808 digital 温度センサ via I2C
・MMA8451 3軸デジタル加速度計 via I2C
・MPL3115A2 高度計 via I2C
・OLED ディスプレイ via I2C
・PA1010D ミニ GPS モジュール via I2C
・PCF8523 RTC（リアルタイムクロック） via I2C
・Interfacing 1-Wire devices to the Pico
・Communicating as master and slave via SPI 
:::

実は「２章：SDKのアーキテクチャ」に重要な事がチョロッと書いてあるのですが・・後述します。

# ［参考資料②］ Pico-C-SDK のドキュメント

下記にRaspberry Pi Pico C/C++ SDKのドキュメントがあります。各ライブラリで使用されるAPIの基本情報が書いてあります。こちらは今後、関数を探したり関数の使用法を調べたりする際に必要になります。

https://www.raspberrypi.com/documentation/pico-sdk/

これ ↓ ⇓ は、ただの画像です。クリックしてもどこにもジャンプしません。
![Pico_SDKのページ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/6a657afb-c7a2-879b-62b0-17fb82f036b1.jpeg)

:::note info
■ **Introduction**

■ **Hardware APIs**
　ここには hardware_adc のようにhardware_～ というカテゴリで分類され、その中に様々な関数の説明があります。
 
hardware_adc　hardware_base　hardware_claim　hardware_clocks　hardware_divider　hardware_dma　hardware_exception　hardware_flash　hardware_gpio　hardware_i2c　hardware_interp　hardware_irq　hardware_pio　hardware_pll　hardware_pwm　hardware_resets　hardware_rtc　hardware_spi　hardware_sync　hardware_timer　hardware_uart　hardware_vreg　hardware_watchdog　hardware_xosc
 
■ **High Level APIs**
　pico_～ というカテゴリで分類され、その下に様々な関数があります。
 
　pico_async_context　pico_flash　pico_i2c_slave　pico_multicore　pico_rand
　pico_stdlib　pico_sync　pico_time　pico_unique_id　pico_util
  
■ **Third-party Libraries**　（tinyusb_device, tinyusb_host）

■ **Networking Libraries**　 (pico_btstack, pico_lwip, pico_cyw43_driver, pico_cyw43_arch)

■ **Runtime Infrastructure**
　pico_～ というカテゴリで分類され、その下に様々な関数があります。
 
pico_base　pico_binary_info　pico_bit_ops　pico_bootrom　pico_bootsel_via_double_reset　pico_cxx_options　pico_divider　pico_double　pico_float　pico_int64_ops　pico_malloc　pico_mem_ops　pico_platform　pico_printf　pico_runtime　pico_stdio pico_stdio_semihosting　pico_stdio_uart　pico_stdio_usb　pico_standard_link
 
■ **External API Headers**　(boot_picoboot, boot_uf2)
:::

「Datasheets」というページにいくとPico ではないラズパイに混ざって、PicoのPDF資料がいくつかあります。日本語の ～JP.PDF もあります。
（これ ↓ ⇓ も、ただの画像です。クリックしてもどこにもジャンプしません。）
![PicoのPDF資料.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/4934fc19-2fac-e6a2-3b06-64598a94cbc7.jpeg)

# ［参考資料③］ サンプルプログラムのリンク

上記②のSDK ドキュメントには以下のAPI関数のサンプルコードがあります。

:::note info
RTC, UART, ADC, I2C, Clock, Timer, Flash programming, Watchdog, Divider, PWM, Multicore, Reset
:::
それらのインデックスがこちらです。

https://www.raspberrypi.com/documentation/pico-sdk/examples_page.html

# ２．C/C++ SDKの関数を使用するためのヘッダーファイル

前記のように非常に多くの関数があることが分かりました。この中に自分が必要とする機能の関数が見つかったとして、次に必要なのは、これらの関数を使用するためのヘッダーファイルです。　そのファイル名は何？　どこにあるの？　と悩みましたが答は「参考資料① SDKのデータシート」の 2.4 Directory structure の項に書いてありました。

:::note info
SDKライブラリヘッダー名の規則は、ライブラリの名前が　foo_bar　の場合、関連付けられたヘッダーは　foo/bar.h　です。具体例として、
Hardware APIs の中の hardware_dma というカテゴリに含まれる dma_channel_claim() という関数を使用したい場合は、hardware_dma ⇒ hardware/dma.h なので

#include "hardware/dma.h"

のように記述します。
:::

［例１］参考資料②の下記の関数は High Level APIs の中の pico_flash というカテゴリなので、
　　　　#include "pico/flash.h" ですね。

![Pico-C-SDK,pico_flashの関数.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/0bc2fd40-786a-4c06-7a8a-596b75b40884.jpeg)

■ この画面で関数のパラメータや戻り値の説明を見たいときは、関数名（赤い文字）をクリックします。例えば "flash_safe_execute" をクリックすると次のような画面が表示されます。
英語が分かり難いときはGoogle 翻訳を活用しましょう。

![SDK-関数のパラメータの説明.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/f5387656-ac54-29e0-a729-e33f3a5a07b1.jpeg)



［例２］下記のように
　　　**datetime
　　　Part of: HighLevel APIs > pico_util**
   
となっている場合は、
　　　**#include "pico/util/datetime"**
となります。

ここは要注意＆チョー重要なポイントです！！　（ワタクシ的には、これも大発見です）

![Pico-C-SDK,datetime_to_str()の説明.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/93c8cecc-9f3c-5131-bd48-e613628d9619.jpeg)

# ３．SDK のサンプルプログラムを試す

SDK の関数が本当に Arduino IDE 環境で作成したスケッチで動作するのでしょうか？　これを試すために［参考資料③］のRTCのリンクから下記のサンプルプログラムををダウンロードしました。Picoに内蔵のRTCで現在時刻を表示するというものです。

```C++
// **** ラズパイ Pico の C/C++ SDK の RTC のサンプルプログラム ****

#include <stdio.h>
#include "hardware/rtc.h"
#include "pico/stdlib.h"
#include "pico/util/datetime.h"
 
int main() {
    stdio_init_all();
    printf("Hello RTC!\n");
 
    char datetime_buf[256];
    char *datetime_str = &datetime_buf[0];
 
    // Start on Friday 5th of June 2020 15:45:00
    datetime_t t = {
            .year  = 2020,
            .month = 06,
            .day   = 05,
            .dotw  = 5, // 0 is Sunday, so 5 is Friday
            .hour  = 15,
            .min   = 45,
            .sec   = 00
    };
 
    // Start the RTC
    rtc_init();
    rtc_set_datetime(&t);
 
    // clk_sys is >2000x faster than clk_rtc, so datetime is not updated immediately when rtc_get_datetime() is called.
    // tbe delay is up to 3 RTC clock cycles (which is 64us with the default clock settings)
    sleep_us(64);
 
    // Print the time
    while (true) {
        rtc_get_datetime(&t);
        datetime_to_str(datetime_str, sizeof(datetime_buf), &t);
        printf("\r%s      ", datetime_str);
        sleep_ms(100);
    }
}
```

これをArduino IDE 用に改造します。
ハードウェアは外付け部品は不要、PCとPicoをUSBケーブルで接続するだけでOKです。
datetime_t という構造体と datetime_to_str() という関数は、High Level APIs ⇒ pico_util ⇒ datetime の中にありました。
```C++
void datetime_to_str (char *buf, uint buf_size, const datetime_t *t)
```
以下のように変更しました。
```C++
// **** C++ SDK ⇒ Arduino IDE 用に改造した RTC のスケッチ ****

// #include <stdio.h>
#include "hardware/rtc.h"
//#include "pico/stdlib.h"
#include "pico/util/datetime.h"

char datetime_buf[256];
char *datetime_str = &datetime_buf[0];
 
// スタートは 2024年2月28日 23:59:50 とする
datetime_t t = {
    .year  = 2024,
    .month = 02,
    .day   = 28,
    .dotw  = 3,     // 0 は日曜日なので3は水曜日
    .hour  = 23,
    .min   = 59,
    .sec   = 50
};

//int main() {
//    stdio_init_all();
//    printf("Hello RTC!\n");

void setup () {
    Serial.begin(9600);
    delay(5000);    // シリアルモニタ表示確認準備期間
    Serial.print("Hello RTC!\n");
 
    // RTCを起動する
    //rtc_init();
    _rtc_init();
    rtc_set_datetime(&t);
 
    // clk_sys はclk_rtcと比べ2000倍速いので datetime は 
    // rtc_get_datetime() がコールされた時に直ぐには更新されない。
    // ディレイは 3 RTC クロックサイクル以上
    //  (それはデフォルトのクロック設定では64us)
    // sleep_us(64);
    delayMicroseconds(64);
}
    //while (true) {
void loop() {    // 時刻を表示し、LEDを点滅する
    digitalWrite(LED_BUILTIN, HIGH);   // 内蔵LEDを点灯
    rtc_get_datetime(&t);
    datetime_to_str(datetime_str, sizeof(datetime_buf), &t);
    //printf("\r%s      ", datetime_str);
    //sleep_ms(100);
    Serial.println(datetime_str);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);    // 内蔵LEDを消灯
    delay(900);
}
```
変更内容は以下の通りです。
① #include \<stdio.h\>は一般的なC言語プログラムでは必須ですが Arduino では不要なので削除（コメントアウト）する
② #include "pico/stdlib.h" は削除（コメントアウト）する ⇒ 理由は［後述］
③ int main() は setup() と loop() に分割する
④ stdio_init_all(); は①と同じ理由で削除（コメントアウト）する
⑤ printf("Hello RTC!\n"); を下記2行に変更する
　　Serial.begin(9600);
　　Serial.print("Hello RTC!\n");
⑥ 下記３つの変数宣言はsetup()と loop()のどちらからも使用できるように移動する
　　char datetime_buf[256];
　　char *datetime_str = &datetime_buf[0];
　　datetime_t t = {}
⑦ rtc_init(); ⇒ _rtc_init(); 理由は［後述］
⑧ sleep_us(64); ⇒ delayMicroseconds(64);
⑨ while(true) { ⇒ void loop() {
⑩ sleep_ms(100); ⇒ delay(100);
⑪ 動作していることを目視で確認できるようLEDを点滅させる

※ 上記②で #include "pico/stdlib.h" を削除したのは下記のコンパイルエラーが出たためです。
![RasPiPico-SDK-RTC-コンパイルエラー１.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/d42f31d7-6030-4d8e-84f7-56ddf5d915bb.jpeg)

画面からはみ出ているエラーメッセージは下記を横にスクロールすると見えます。

```C++
In file included from C:\Users\user\Documents\Arduino\RaspPiPico-SDKtest-RTC\RaspPiPico-SDKtest-RTC.ino:5:0:

C:\Users\user\AppData\Local\Arduino15\packages\arduino\hardware\mbed_rp2040\4.0.10\cores\arduino/mbed/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/common/pico_stdlib/include/pico/stdlib.h:11:10: fatal error: pico/stdio.h: No such file or directory
```
めちゃくちゃ深いPATHですが、pico/stdlib.h の中で pico/stdio.h というファイルが見当たりませんという内容です。
Alternatives（選択肢、代替案）とか candidates（候補者）という単語がありますが、どうすれば良いのか分かりません。　どうしよう？ ⇒ 取り敢えずコメントアウトしたらどうなる？ ⇒ おおっ、通ったぞ！ ＯＫ、Good Job！　①と同様の理由でしょうか。

しかし・・・　更に別のコンパイルエラーが出ました！

![RasPiPico-SDK-RTC-コンパイルエラー２.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/10acf6b6-652d-29cd-63a3-3c64fba98489.jpeg)

これが⑦の問題、rtc_init() が見つからないとのことです。 suggested alternative（提案された代替案）が提示されてます。言われるがままに rtc_init(); ⇒ _rtc_init(); としたらエラーが解消しました。

コンパイル完了後、Picoにダウウンロードすると、シリアルモニタに以下のように表示されました。

![RasPiPico-SDK-RTC動作.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/aef8b837-d917-d839-7dbc-7a70cb81eec4.jpeg)

うるう年、オリンピックイヤーの処理も正しくできてます。

# ４．感想など
■ Arduino IDE で Raspberry Pi Picoの C/C++ SDKの関数を使えることが証明できました。但し、SDK のサンプルプログラムを流用する場合は、「たったの1行ヘッダーファイルを入れるだけでOK」というわけにはいかず、少しいじる必要があることも分かりました。
  何れにせよ Arduino IDE で SDK の関数が使えることが分かったのは大きな収穫です。

■ 今回は題材として Pico 内蔵の RTC を使用しましたが、私は以前下記の記事を公開しました。

https://qiita.com/totuto/items/d3bc435d3d2f545c1c02

これは３つのライブラリをインストールして現在時刻をシリアルモニタに表示するというものです。ライブラリに付属のサンプル・スケッチを使用しましたが、**PCからシリアルモニタ経由で日付と時刻を設定できる関数** を作成しました。興味ある方はご覧頂ければ幸いです。

# 【関連記事】　－ Raspberry Pi Pico に関するもの －

https://qiita.com/totuto/items/38349e66865d518c45d8

https://qiita.com/totuto/items/0268e0e73caeb0d545d3

https://qiita.com/totuto/items/3e4bf52189515015cb90

https://qiita.com/totuto/items/6a3ab3c5f888d49739b1

https://qiita.com/totuto/items/2a8db63abd1d3c82880f

https://qiita.com/totuto/items/81944426dc81ab4b7e57

https://qiita.com/totuto/items/d3bc435d3d2f545c1c02

上記以外に ESP32 の応用例の記事もいくつかあります。