2016年6月16日木曜日

ArduinoとNucleoでPCとのSerial(UART)通信の最高速度を調べてみる。

SPIやI2Cの通信状態を解析しようと思うと補足した信号をPCに送ってから見やすいように整形・グラフ化するのが良さそうだ。

Arduinoでは、I2Cはデフォルトで100kbps、SPIはよく覚えていないが数Mhzぐらいだった気がする。

ArduinoのSerialはデフォルトが9600bps(9.6kbps)なので、I2Cと比べても明らかに遅い。

PCとの通信にはUSB HIDも使えそうなのでWebで調べてみたがUARTより特に速い感じでもない。

SDカードに一回保存して…とか、TCP-IP/Wi-fiを使ってみるとか一瞬思ったがかなりめんどくさそう。

なのでPCとArduino Uno/NucleoとのSerial通信をどれぐらいの速度でできるか調べてみた。


Arduino Uno


最高1Mbpsで送信できたが、PC(putty)で受信すると取りこぼしが結構ある。

Arduinoのスケッチ(SerialSpeedTest.ino)

#define BAUD_RATE 1000000
#define LOOP_N    1000
#define SEND_CHR  (0x55)

void setup() {
  Serial.begin(BAUD_RATE);
  Serial.println("***Serial Speed Test Start***");
}

void loop() {
  char strBuffer[80];

  Serial.print("\r\n\nBaud Rate: ");
  Serial.println(BAUD_RATE);
  
  unsigned long startTime = micros();
  for (int i = 0; i < LOOP_N; i++) {
    Serial.write(SEND_CHR);
  }
  unsigned long duration = micros() - startTime;
  unsigned long bps = (unsigned long)(8 * 1000000.0f * (float)LOOP_N  / (float)duration);
  
  Serial.print("\r\n");
  sprintf(strBuffer, "\r\n%lu bits/second\r\n", bps);
  Serial.print(strBuffer);
}


1Mbpsを指定した場合はおおよそ1Mbpsで出力できた。


ch1:D0(RX) ch2:D1(TX)

送信するバイトは #define SEND_CHR で指定した0x55なので、ビットにすると0b01010101になる。したがってオシロの表示値の499.3KHzの倍の998.6kHzが送信レートになる。

puttyの受信のようす

’U'がいっぱい並んでいるが、0x55をASCIIコードで文字にすると'U'になる。

ボーレートが1Mbpsで実際送信できたのは800kbps弱。しかも時々読みこぼしてしまうようだ。

Nucleo F401RE


main.cpp(Nucleo_Serial_Speed_test)

#include "mbed.h"

#define BAUD_RATE 2000000
#define LOOP_N    1000
#define SEND_CHR  (0x55)

Serial pc(SERIAL_TX, SERIAL_RX);
Timer timer;

int main()
{
    pc.baud(BAUD_RATE);
    pc.printf("***Serial Speed Test Start***");
   
    timer.start();
   
    while(1) {
        pc.printf("\r\n\nBaud Rate: %d\r\n", BAUD_RATE);
       
        timer.reset();

        for (int i = 0; i < LOOP_N; i++) {
            pc.putc(SEND_CHR);
        }
       
        uint32_t bps = (uint32_t)(8.0f * (float)LOOP_N / timer.read());
       
        pc.printf("\r\n\n%u bits/secon\r\n", bps);
    }
}


表示値が1MHzなので、同じく倍にして2Mbps。Arduino互換のD0、D1には信号が出ていなくて、分割できるようになっている通信用(?)の基板のRX、TXと書いてあるところでUART信号を捕捉できた。

F401REをmbedで使うと2Mbpsが最大のようだ。それ以上を指定すると信号が出ないか、めちゃくちゃ遅くなってしまう(1kHz以下)

メモ:


Nucelo F401REは最大84MHz駆動となっているが、ほんとにそのクロックで動作してるのだろうか?mbedだとクロックの計測方法がわからない。


Nucleoのボード上ではX3と書いてあるところにクリスタルを刺すような表示になっているが、実装されていない。

PSoC 5LPでもやりたかったが、UARTコンポーネントのinternal clockだと921,600bpsまでしか指定できない。External Clockを指定すればもっとSpeedを上げられそうだがまた気が向いたらやるかも(DataSheetには4Mbpsまで、みたいな記述がある)

Arduinoで1Mbpsはムリそう、Nucleo F401REで2Mbps。←データの取りこぼしがあるかどうかは要確認。

I2Cなら2信号、SPIでもSCKとMOSIに限れば2信号なので、ランレングス圧縮とかして通信コストを下げてやれば、なんちゃってLogic Analyzerはなんとか出来そうもするがPC側のプログラムを作るのもしんどそうだなあ(^q^;

フルスピードのUSBを使うにはどうすればいいんじゃろ。