ESP32 の SPI_MODE が修正。HSPI , VSPI , 複数SPIデバイス制御 , SPI高速化などについて

ESP32 ( ESP-WROOM-32 )

こんばんは。

今回は、ESP32 ( ESP-WROOM-32 ) の SPI ( Serial Peripheral Interface )通信について報告したいと思います。
Arduino core for the ESP32 についてです。

まず、今までずーっとバグっていた SPI_MODE2 と SPI_MODE3 が最新版 Arduino core for the ESP32 で修正されました
( 2017/5/8 時点 )

これは、get.exe をクリックしただけでは修正されませんので注意してください
新たに GitHub から ZIP ファイルをダウンロードしてインストールし直さなければなりません。
これについては後で述べます。

また、ESP32 – DevKitC ( ESP-WROOM-32 開発ボード ) の SPI ( Serial Peripheral Interface )通信には VSPI と HSPI がありますが、その使い分けがようやくできました。
これができると、複数の SPI デバイスを制御するのに役立ちます。
特に micro SDHC カードスロットと併用する場合に良い効果が得られそうです。
I2C 通信よりも格段に高速なので、SPIの複数デバイス制御は必須ですね。

また、Arduino core for the ESP32 の SPI 標準ライブラリを使う場合に、関数をうまく使い分けると SPI 通信の高速化ができます。
残念ながら、レジスタを直接叩く GPIO ダイレクトアクセスは今回使えませんでした。
SPI 標準ライブラリだけで、十分高速です。
そもそも、SPI ライブラリ自信がGPIO を直接レジスタ制御するコマンドで出来ているので、当たり前といえば当たり前です。
現在ある情報でGPIO ダイレクトアクセスを試してみたら、digitalWrite と大差ありませんでしたし・・・。

それと、最近気づいたのですが、Arduino core for the ESP32 の CPU 周波数は、今まで最高 80 MHz だと勘違いしていて、実は既に 240 MHz で動いておりました。
フラッシュメモリの周波数の方が最大 80MHz ということでした。
これについても後述します。

スポンサーリンク

検証で使うもの

今回の検証で使うものは以下の通りです。

ESP32 – DevKitC

私は秋月電子通商さんで購入しましたが、Amazonさんでも販売していますね。

フルカラー OLED SSD1331 モジュール

SparkFun マイクロSDカードスロット・ピッチ変換基板

SparkFun マイクロSDカードスロット・ピッチ変換基板

10kΩ固定抵抗

1/4W で良いです。
micro SDHC カードの信号ピンのプルアップに使います。

サンハヤト ブレッドボード SAD-101

サンハヤト SAD-101 ニューブレッドボード
サンハヤト
¥568(2024/12/21 04:04時点)

100MHz 以上のオシロスコープ

SPI 信号の周波数24MHz くらいの波形を見るので、最低 100MHz 以上のオシロスコープでないと正確な波形は見られません。
私は、日本製のこれを使っています。
持ち運びに便利で重宝しています。
因みに、プローブは別売りです。結構お高いです。

USB接続デジタルストレージオシロスコープ メモリ1M搭載モデル PA-S2000/E
ピーアンドエーテクノロジーズ
¥107,700(2024/12/21 10:53時点)

Arduino core for the ESP32 の再インストール

先にも述べましたが、get.exe をクリックしただけでは SPI_MODE は修正されませんのでご注意ください。
必ず、GitHub から ZIP ファイルをダウンロードして再インストールしなければなりません

しかし、この get.exe は毎回セキュリティーソフトで弾かれてしまいますね。
その場合はファイアウォール設定を解除するしかありません。
怪しい動作をしていないのなら、ESPRESSIF 社がセキュリティーソフト会社に申告してもらいたいものですね。

では話を戻しまして、Arduino core for the ESP32 を再インストールします。

その前に、以下のフォルダ内のファイルを全て削除してください
( Windows 10 の場合 )

C:Usersユーザー名DocumentsArduinohardwareespressifesp32

その後、以下の記事を参照して、Arduino core for the ESP32 を再インストールしてください。

Arduino core for the ESP32 のインストール方法

ESP32 ( ESP-WROOM-32 ) のCPUクロック周波数の確認

先にも述べましたが、私がずっと勘違いしておりました。
Arduino IDE で開発する場合の ESP32 ( ESP-WROOM-32 ) のCPU クロック周波数は最大の 240MHz で動作していたようです。
Windows 10 の場合、以下のアドレスのフォルダを開いて下さい。

C:Usersユーザー名DocumentsArduinohardwareespressifesp32

そこの、boards.txt というファイルをテキストエディタで開くと、ESP32 Dev Module のところに、

esp32.build.f_cpu=240000000L

という記述がありました。
つまり、240 MHz 設定でビルド(コンパイル)していたということです。
大変失礼しました。
m(_ _)m

ということは、最も電力を食う、最速のCPU で動いていたということですので、SPI のクロック設定もそれを念頭に置かねばなりません。
SPI 周波数は CPU クロック周波数で割り切れる周波数で使う原則があるためです。

SPIクロック周波数設定の決め方

では、デバイスによる、SPIクロックの周波数の私なりの我流の決め方を説明します。

通常、Arduino の場合では SPIクロックは分周器 ( ClockDivider )を使って、システムクロックの1/2, 1/4, 1/8, 1/16 と2の累乗で決めていきますが、ESP32 では setFrequency 関数があり、SPIクロック周波数をユーザーが直接決めることができます。
ただ、分周器 ( ClockDivider )を使わずに直接周波数を決めてしまう、この使い方が正しいかどうかは分かりません。
分周器 ( ClockDivider )を使うと、あまり高速にできないのです。
ClockDivider を何回か使って試してみたのですが、これは外部クロック用なのでしょうか、イマイチ速度が上げられませんでした。

私が実験したところ、setFrequency 関数で直接周波数を指定してもエラーが出ていなく、高速化できるので、今回はこれで説明していきます。
こちらの方が周波数を微調整できるので便利です。
setClockDivider関数は使いません。

micro SDHC カードの場合

電子工作レベルでできる micro SDHC カードの読み書きは SPI モードまでです。
これは理論値で24 MHz 程度だそうです。
もっと高速の読み書きをするには、ライセンス料を支払わねばならないようです。
(参考記事)
ESP32 ( ESP-WROOM-32 ) で micro SDHC メモリカードを使う場合の注意点

よって、ESP32 の CPU が240MHz なので、micro SDHC カードのSPI周波数設定は最大 24MHz となります。
ClockDivider を使う場合は1/16 分周で 16MHz となってしまうのでしょうか?
それでは遅くなってしまいますね。

SD.h ライブラリの場合は デフォルトで VSPI を使うようになっています。
周波数設定は下のように begin 関数内で設定します。

SD.begin(5, SPI, 24000000, “/sd”);

OLED SSD1331 モジュールの場合

データシートによると、SPIクロックサイクルの最小値が 150ns なので、6.6666…. MHz です。
つまり、240で割り切れる近似値とすると、6 MHz 設定となります。
setFrequency関数を使うとこういう指定になります。

SPI.setFrequency(6000000);

これをオシロスコープで見てみるとこうなります。

ただ、これでは最小の150ns よりも長くなっています。
そこで、240で割り切れない 7 MHz としてみると、下図のようになります。

ほぼピッタリ 150 ns となりました。
ClockDivider よりも細かく微調整できますね。
ただ、CPUクロックで割り切れないということについて何か弊害があるかもしれませんので、6 MHz とした方が無難かもしれませんね。
何か問題があればぜひ教えていただきたいものです。

コメント

  1. 匿名 より:

    You have “readBytes is so explosive that it is incomparable.”

    That should state writeBytes, not readBytes.

  2. nino より:

    ありがとうございます。とても
    参考になりました。
    受信側は複数バイト どうなるんでしょうか

    • mgo-tec mgo-tec より:

      ninoさん

      記事をご覧いただき、ありがとうございます。

      ただ、この記事は3年半以上も前に書いたもので、現在の環境とは異なっていることをご了承ください。
      Arduino core for the ESP32 では、だいぶ修正されてきています。

      また、この頃は私自身がまだまだ勉強不足で、ただ単に標準的なプログラミング手法を知らなかっただけということもありました。
      プロのプログラマーの間では複数バイトをまとめて送ることはあたりまえの作法だったようです。

      ESP32のSPI受信はやったことが無いので、想像でしか言えませんが、おそらく1バイトづつ受信するより、まとめて受信した方が断然高速だと思われます。

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