LoginSignup
3
1
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

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

Last updated at Posted at 2024-01-28

1.Arduino IDE と C/C++ SDKの関数

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

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

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

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

#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" を、これ入れるだけ? どっかからライブラリをダウンロードしてインストールとかしなくてEの? ホンマでっか!!

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

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

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

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

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ページのドキュメントです。

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

目次
1章:SDKについて
2章:SDKのアーキテクチャ
3章:Programmable I/O (PIO) の使い方
4章: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)とサンプルプログラムがあります。

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

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

[参考資料②] Pico-C-SDK のドキュメント

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

これ ↓ ⇓ は、ただの画像です。クリックしてもどこにもジャンプしません。
Pico_SDKのページ.JPG

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

[参考資料③] サンプルプログラムのリンク

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

RTC, UART, ADC, I2C, Clock, Timer, Flash programming, Watchdog, Divider, PWM, Multicore, Reset

それらのインデックスがこちらです。

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

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

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

#include "hardware/dma.h"

のように記述します。

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

Pico-C-SDK,pico_flashの関数.JPG

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

SDK-関数のパラメータの説明.JPG

[例2]下記のように
   datetime
   Part of: HighLevel APIs > pico_util

となっている場合は、
   #include "pico/util/datetime"
となります。

ここは要注意&チョー重要なポイントです!! (ワタクシ的には、これも大発見です)

Pico-C-SDK,datetime_to_str()の説明.JPG

3.SDK のサンプルプログラムを試す

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

// **** ラズパイ 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 の中にありました。

void datetime_to_str (char *buf, uint buf_size, const datetime_t *t)

以下のように変更しました。

// **** 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");
⑥ 下記3つの変数宣言は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-コンパイルエラー1.JPG

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

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(候補者)という単語がありますが、どうすれば良いのか分かりません。 どうしよう? ⇒ 取り敢えずコメントアウトしたらどうなる? ⇒ おおっ、通ったぞ! OK、Good Job! ①と同様の理由でしょうか。

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

RasPiPico-SDK-RTC-コンパイルエラー2.JPG

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

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

RasPiPico-SDK-RTC動作.JPG

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

4.感想など

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

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

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

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

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

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1