ESP32とTeensy4.1のスピード比較(GPIO編)※修正有り

DIY

2020/11/3修正:ESP32の速度が遅かったのはレジスタの選択ミスだったので、そこを修正

GPIOスピード比較

Arduinoの”digitalWrite()”はまあ遅いことで有名なので、Lチカのような時は使っても、高速通信をするのには向かないのだが、じゃあ何を使うかというとArduinoでは”FastGPIO”というライブラリがある。(”FastGPIO”はArduino IDEでライブラリを検索して導入できる。)
しかし、これはESP32系とTeensy系では使えないようで、他の方法でGPIOを速くオンオフする方法を検証してみる。

・レジスタを直接書き換える
 マイコンの中ではレジスタという領域にデータが入っていおり、この値を変えることでマイコンの設定を変えることができる。ArduinoのpinModeやdigitalWriteも結局は特定のレジスタの値を変更して実現している。この方法の良いところは最速であるのと、複数のIOを同時に変更できることで、欠点はマイコンの種類ごとにレジスタを調べる必要があること。

ESP32では表のようになっており、例えば、5ピンのpinModeをOUTPUTにして、GPIO_OUT_REGの6ビット目を1にした値(b100000)を代入すると、5ピンがHIGHになる。GPIO_IN_REGはインプットなので、例えば2ピンをINPUTにしておいて、GPIO_IN_REGの3ビット目が1であれば2ピンの入力はHIGHであるはず(未検証)。
※GPIO_OUT_REGを書き換えるよりも速い方法がありました。詳しくは後述

NameDescriptionAddress
GPIO_OUT_REGGPIO 0-31 output register0x3FF44004
GPIO_OUT1_REGGPIO 32-39 output register0x3FF44010
GPIO_IN_REGGPIO 0-31 input register0x3FF4403C
GPIO_IN1_REGGPIO 32-39 input register0x3FF44040
Register Summery
(https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf)

一方のTeensy4.1も同様のことができるはずなのだが、正直資料が少なくてよく分からない。。。

・digitalWriteFast()を使う
 これはTeensyでのみ使える方法。使い方は簡単でdigitalWrite()をdigitalWriteFast()に置き換えるだけ。

速度の測定

 ESP32はM5Stackを使って測定した。測定に使ったコードは以下の通り。

・ESP32

・Teensy 4.1

ESP32平均[ns]標準偏差[ns]
digitalWrite119.70.0042
directIO126.00.0008
Teensy4.1平均[ns]標準偏差[ns]
digitalWrite35.840.0003
digitalWriteFast3.3340.00007

結果

あれ…?ESP32のdirectIOが全然速くない。。。というかdigitalWriteが意外と速い?Teensy4.1に関してはdigitalWriteFastを使うほうが10倍速いね、ESP32と比べると36倍速い。なお…↓

レジスタを別のものにしたらもっと速くなりました(20/11/3追記)

「レジスタのリードとライト2回アクセスが発生して」しまうというコメントをいただき、もう一度データシートを見直してみたらこんなのが

NameDescriptionAddressAccess
GPIO_OUT_W1TS_REGGPIO 0-31 output bit set register0x3FF44008WO
GPIO_OUT1_W1TS_REGGPIO 32-39 output bit set register0x3FF44014WO
GPIO_OUT_W1TC_REGGPIO 0-31 output bit clear register0x3FF4400CWO
GPIO_OUT1_W1TC_REGGPIO 32-39 output bit clear register0x3FF44018WO
Register Summery
(https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf)

つまり、これらのレジスタを1にするとポートの出力がW1TSの場合HIGHに、W1TCの場合はLOWになるよ、というものでGPIO_OUT_REGのアクセスが”R/W”(Read/Write)であるのに対して、このレジスタは”WO”(Write Only)のため、一回のアクセスで済むということの様です。

速度測定

改めて速度を測定したら表のようになりました。GPIO_OUT_REGを書き換えていた時よりも2倍以上速くなり、digitalWriteを使うよりも速くなりました。複数のポートを一度に書き換えられるので、digitalWriteの代わりに使用する機会は多そうです。

ESP32平均[ns]標準偏差[ns]
digitalWrite120.00.0011
GPIO_OUT_REG125.90.0012
GPIO_OUT_W1T_REG50.460.0010

・測定に使用したコード

追記

なんで(GPIO編)としているかというと、(SDカード編)をやりたいからなのだけど、一度計ろうとして挫折しているのでここ(エレホビカ様)を参照してやってみたい。

コメント

  1. a より:

    ESP32
    上記のDirectIOの例だと、1回のポート出力にレジスタのリードとライト2回アクセスが発生してしまいます。ESP32にはセット、リセットを行う別のレジスタがあります。それだと1回のライトで出力できます。指定しないビットのポートは変化なしなので、排他制御もいりません。digitalWriteでは、セット、リセットをするレジスタを使用しているので速度が逆転したんだとおもいます。

    • やまたい(Yamatai) yamatai より:

      aさん
      ありがとうございます!レジスタを別のものにして試したら速度が改善しました。

タイトルとURLをコピーしました