LoginSignup
8
5

More than 3 years have passed since last update.

Seeeduino XIAOでPCと爆速シリアル通信

Last updated at Posted at 2020-12-08

Seeeduino XIAO

Seeed Studioから出ているArduino互換の小型マイコンボード。ARM Cortex-M0+のCPU(SAMD21G18)でFlash256KB, SRAM32KBついてお値段なんと600円以下! いい時代になったものですね。

Seeeduino XIAO

Seeeduino XIAOのUSBについて

さてこのXIAOですが、マイコンチップがネイティブでUSBに対応しているので、ボードのUSB TypeCポートがマイコンチップに直接接続されています。
そのため、PCとシリアル通信をする際には「シリアル通信」といいながらUSBを仮装シリアル(CDC)として認識させて通信しているので、シリアル通信といってもUSBの高速通信を使うことができ、通常のUARTとは比べ物にならないほど高速にシリアル通信ができます。
Arduino UNOなどは、ボードのUSBポートはUSBシリアル変換チップからメインのマイコン(UNOの場合はATMEGA328)にTXとRXのUARTで接続されているため、どうしてもボトルネックとなり115200bps(14kbyte/s)程度が限界になります。
SAMD21G18はUSB2.0 Fullspeedに対応しているので、12Mbps(1.5Mbyte/s)のポテンシャルはあります。もちろんプロトコルのオーバーヘッドがあるのでそれ以下にはなりますが。

図にするとこんな感じです。

Arduino UNOとSeeeduino XIAOのシリアル通信

実験

Arduino環境でシリアル通信の速度を計測してみます。
PC側の通信はProcessingを使いました。
今回はボード側からPC側の方向の速度を計測しています。

Arduinoソースコード

Arduino側ではひたすらデータを送信します。データチェックがしやすいように0,1,2,...255というデータを送ります。
また、PC側から送信開始の指示ができるようにしてあります。
Arduino UNO, Seeeduino XIAO両方で共通のコードが動きました。

boolean sending = false;
const int BUF_SIZE = 256;
byte buf[BUF_SIZE];

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }
  // バッファ初期化 0,1,2,3,...,255
  for (int i = 0; i < BUF_SIZE; i++) {
    buf[i] = i;
  }
}

void loop() {
  int c = Serial.read();
  switch (c) {
    case '1':
      sending = true; // 送信開始
      break;
    case '0':
      sending = false; // 送信停止
      break;
  }
  if (sending) {
    // 送信中ならバッファを送信する
    Serial.write(buf, BUF_SIZE);
  }
}

Processingソースコード

Processingではシリアルでデータを受信して受信速度を計算します。
送った通り0,1,2,...255,0,1,...とデータが来ているかどうかもチェックしています。

import processing.serial.*;

Serial serial;
long startms = 0;
long totalbytes = 0;
byte[] buf = new byte[32 * 1024]; // 32kbのバッファ

void setup() {
  printArray(Serial.list());
  serial = new Serial(this, Serial.list()[0], 115200); // [0]の部分はポートによって変える
}

void draw() {
  if(serial.available() > 0) {
    // データ読み込み
    int bytes = serial.readBytes(buf);
    // バッファの中身チェック
    for(int i = 0; i < bytes; i++) {
      if(buf[i] != (byte)(totalbytes + i) % 256) { // 0,1,2,...,255,0,1,...となっているのを確認
        println("DATA ERROR", buf[i], totalbytes, (byte)(totalbytes + i) % 256);
        break;
      }
    }
    // 総受信バイト数に加算
    totalbytes += bytes;
    // 開始からの経過時間計算
    long t = millis() - startms;
    // 経過時間, 今回の受信バイト数, 総受信バイト数, 平均速度[bytes/s] を出力
    println(t, bytes, totalbytes, totalbytes * 1000 / t);
  }
}

void keyPressed() {
  switch(key) {
  case '1':
    // 1キーを押すと受信開始
    startms = millis(); // 開始時刻リセット
    totalbytes = 0; // 総受信バイト数リセット
    serial.write('1'); // Arduino側の送信を開始させる
    break;
  case '0':
    // 0キーを押すと受信終了
    serial.write('0'); // Arduino側の送信を停止させる
    break;
  }
}

実験結果

上記プログラムで測定した結果は以下です。
Seeeduino XIAOがArduino UNOの10倍以上の速度が出ています!!

ボード ボーレート設定 結果(転送速度)
Arduino UNO 115200 11753[byte/s] = 11.5[kbyte/s]
Arduino UNO 234000 22207[byte/s] = 21.7[kbyte/s]
Arduino UNO 500000 49976[byte/s] = 48.8[kbyte/s]
Arduino UNO 1000000 測定不能(データエラー)
Seeeduino XIAO 115200 705002[byte/s] = 688.5[kbyte/s]

Arduino UNOではボーレートの設定を変えながら実験しました。ボーレートの設定を1000000にしたところ、Processing側で仕込んだデータチェックに引っ掛かり、計測不能となりました。Arduino UNOではボーレートは500000が限界といったところでしょうか。
Seeeduino XIAOではボーレートの設定にかかわらず転送速度は変わりませんでした。なんとProcessing側とArduino側でボーレートの設定が違っていても通信ができました。仮装シリアルポートだからですかね。USB2.0 Fullspeedの1.5M[byte/s]の理論値と比べるとそれなりに出ていることもわかります。

まとめ

ネイティブUSBをつかえば高速にシリアル通信ができることがわかりました。画像や音を転送したり、高速なセンサーデータの転送に使えるのではないでしょうか。
Arduino DUEのようなネイティブUSBポートを持つArduinoでも同じように高速に通信ができると思います。もちろんSeeedのWio Terminalも!
Seeeduino XIAOは速い/安い/小さいの三拍子が揃っていてすばらしいですね。

8
5
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
8
5