Seeed XIAO RP2040をArduino-Picoで動かす

新商品開発、技術開発

概要

Raspberry Pi PicoをArduino-Picoで動かすという記事は多く見かけたのですが、Seeed XIAO RP2040を使う記事は少なかったので、調べて色々試した結果を紹介します。

◆念のためArduino-Picoの説明
Raspberry Pi Picoは公式でArduino IDEに対応しています。ただし、下記のような一部の機能に対応していません。

  • 一部のライブラリ
  • FLASHメモリを疑似EEPROMのように使う
  • 2コアでの並列処理
  • I2C、SPIを複数ポート使ったり、チャンネルを変えて使う

    ※他にもありそうなので随時追加します。

上記の点を改良したArduino Coreを、Earle F. Philhower, III氏が新たに作成して無料で公開されています。
これが「Arduino-Pico」です。私個人としては公式ではなく個人が作成したものだと保守性で問題はないのか…?と感じているのですが、日本語の資料の多くがArduino-Picoを使用した環境のため、様子を見つつ使用しています。
この記事を書いている時点では更新は頻繁にされているようです。

I2CやSPIのポートについては公式のものでも何とかなるケースが多いのですが、2コアでの並列処理が使えるのは大きいですね。

実行環境

MCU: Seeed XIAO RP2040
IDE: Arduino IDE 1.8.19 windows(portable)

参考資料

Arduino-Pico 公式ページ https://arduino-pico.readthedocs.io/en/latest/#
Arduino-Pico Github https://github.com/earlephilhower/arduino-pico

Seeed XIAO RP2040のピンアサイン

Arduino IDEの設定

Raspberry Pi Picoと同じ手順になります。
詳細は参考サイトを参照ください。
※英語が読める方は公式ページ、もしくはGithubを参考にするのが確実です。日本語で読みたい方は↓こちらの「Earle Philhowerコアのインストール」が説明が丁寧です。

Seeed XIAO RP2040をPCに接続する

初回はBOOTSELボタン(下図の赤枠部のボタン)を押したままUSBケーブルでPCに接続します。
この方法で接続すると大容量記憶デバイス(USBメモリ等と同じ扱い)として認識されます。

スイッチサイエンス・購入画面から引用

Arduino IDEを起動し、ツール → ボード → Raspberry Pi RP2040 Boards(X.X.X) → Seeed XIAO RP2040 をクリックしてボードを設定します。
Flash Sizeなどの設定項目が増えますが、とりあえず動かすだけならデフォルトのままでOKです。
後ほど必要に応じて変更します。

Raspberry PiやXIAO RP2040などRP2040搭載ボードは普通のArduinoと違い、PCと接続してもシリアルポートは認識されません。
普通のArduinoはシリアル通信でプログラムを書き込むのでシリアルポートの設定が必要ですが、RP2040は大容量記憶メモリとして認識され、USBメモリのように.uf2ファイルを保存する形でプログラムが書き込めれるためです。
おそらくですが、「RPI-RP2」「RP2-Boot」という名前のデバイスを自動認識して書き込むようです。(詳しくは確認中)

※参考画像ではシリアル通信でデバッグ情報が見れるよう設定変更しています。元に戻すのが面倒で…

ここまで出来たら通常のArduinoと同じく、コードを書いて「マイコンボードに書き込む」ボタンを押せばプログラムが書き込めます。
検証も書き込みもかなり時間がかかるので気長に待ちましょう。
↓このようなメッセージが出てきたら書き込み完了です。(コードやPCの環境によってメッセージが少し変わります)

Resetting COM7
Converting to uf2, output size: 116736, start address: 0x2000
Flashing D: (RPI-RP2)
Wrote 116736 bytes to D:/NEW.UF2

2回目以降の書き込みは「BOOTSELボタンを押しながらPCとUSBに接続」する必要はありません。
ただし、たまに書き込みが上手くいかない時があるようで、その時は初回の書き込みと同じ手順が必要です。

Lチカしてみる

ファイル → スケッチ例 → 01.Basics → Blink の順にクリックしてLチカ用のサンプルコードを開きます。

これを一切変更せずに書き込むと、USBコネクタ横の赤LEDが点滅します。

シリアル通信(UART)でPCと通信する

シリアル通信は特にボードの設定変更なく使えます。

当方の環境では書き込みか何かが上手くいかなかったのか、最初はシリアルポートが認識されませんでした。
理由はわかりませんが、Debug Portを「Disable」から「Serial」に、Debug Levelを「なし」から「全て」に変更して書き込むとPC側に認識されるようになりました。
以降はデフォルト設定に戻しても普通にシリアルポートが認識されています。

ファイル → 01.Basics → DigitalReadSerial の順にクリックしてスケッチ例を開き、変更せずに書き込みます。

GPIOの電圧をHIGHなのかLOWなのか判断してシリアル出力するサンプルプログラムです。
デフォルトでは、2番ピン(D8)に3.3Vをつなぐと1、GNDをつなぐと0が出力されます。

I2C通信

Seeed XIAO RP2040のI2C通信は、初期化がやや特殊です。
RP2040はI2Cが2チャンネルあり、割り当てピンはいくつかの選択肢から選ぶことが出来ます。しかし、デフォルトの割り当てピンとSeeed XIAO RP2040のI2Cピンが一致していないため、必ずWire.begin()の前にピン設定が必要になります。

ピン名称デフォルト割り当てSeeed XIAO RP2040
ピンアサイン
SDAGPIO4(I2C0)GPIO6(I2C1)
SCLGPIO5(I2C0)GPIO7(I2C1)

↓こちらのブログでSeeed XIAO RP2040を使ったI2Cscannerのコードを紹介されているので、こちらを参考にさせていただきました。

https://aloseed.com/it/xiao_rp2040/#toc18

ピン設定で「SDA」「SCL」という文字列を代入していますが、これはSeeed XIAO RP2040のボード情報の部分でそれぞれ「6」「7」と定義されています。
また当方の環境では「Wire1」を使用したプログラムを書き込むと、PCに認識されなくなってしまいました。(BOOTSELボタンで起動して別のプログラムを書き込めば直ります)
以下、動作確認出来たプログラムです。

#include <Wire.h>

void setup(){
  Wire.setSDA(SDA);
  Wire.setSCL(SCL);
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop(){
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address &lt; 127; address++ ){
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0){
      Serial.print("I2C device found at address 0x");
      if (address &lt; 16)Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4){
      Serial.print("Unknown error at address 0x");
      if (address &lt; 16)Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)Serial.println("No I2C devices found\n");
  elseSerial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}