Seeeduino XIAO
Seeed Studioから出ているArduino互換の小型マイコンボード。ARM Cortex-M0+のCPU(SAMD21G18)でFlash256KB, SRAM32KBついてお値段なんと600円以下! いい時代になったものですね。
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環境でシリアル通信の速度を計測してみます。
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は速い/安い/小さいの三拍子が揃っていてすばらしいですね。