ESP32のメモリレイアウトの理解と最適化

2024/03/28に公開

ESP32は、Wi-FiとBluetoothの統合、低消費電力、そして豊富な機能を提供する人気の高いEspressif Systemsのマイコンです。カタログスペックでは、520KBのSRAMを持っていることになっていますが、実際にスケッチをコンパイルしてみると、それより遥かに少ない容量なのにコンパイル、または転送エラーになることがります。

このブログ記事は、ESP32のメモリレイアウトに焦点を当て、その深淵に迫っていきたいという細かすぎて伝わらない企画になっております。

ESP32のメモリアーキテクチャ

ESP32のメモリレイアウトを理解するためには、この表が何より重要になります。Espressif Systemsの出しているテクニカルリファレンスから引用です。テクニカルリファレンスはこのページにあります(PDF)。

ESP32 Hardware Reference

このメモリレイアウトはとても複雑で、これが理解の妨げになっていると思います。

ESP32は、ハーバードアーキテクチャという仕組みを導入していて、プログラムを収める命令用メモリとデータを収めるメモリが、別のアドレスに配置されていることが特徴です。上記の表で見ると、Bus Typeが「Instruction(命令)」となっているのがプログラム用の領域で、「Data」となっているのがデータ用の領域になります。

命令領域とデータ領域の分布

それぞれの領域がどのような分布になっているのか?については、こちらの記事が参考になりました。

ESP32 Programmers’ Memory Model

恐らく、Espressif Systemsの開発者の方だと思いますが、メモリレイアウトと使われ方について解説されています。

ここでは、SRAMが、IRAM(Instruction RAM)とDRAM(Data RAM)に分かれているという説明がなされていますが、興味深いのは、SRAM1の領域が重なっていることです。下の図をご覧ください。

この図のとおり、SRAMの領域は、SRAM0,SRAM1,SRAM2の3つの領域に別れていて、下記のようになっています。

  • SRAM0: 命令領域(IRAM)

  • SRAM1: 命令、データの共有領域(IRAM/DRAM)

  • SRAM2: データ領域(DRAM)

SRAM1の領域は、一番上の表の通り、メモリレイアウト上は2つのエリアに存在するように見えます。しかし、これはそれぞれのバス(Data BusとInstruction Bus)を通して、物理的に同じメモリにつながっているという構造をしています。

図の矢印が右と左から伸びているのですが、これもある意味曲者で、IRAMとDRAMをつないでいるBusは、アドレッシングの方法が逆になっており、物理領域の割当順が逆になります(伝わる?)。つまり、IRAMとして見たときは図の左からアドレスが振られているのに対して、DRAMとして見たときは図の左からアドレスが振られているということです(同じことを言っている)。

SRAM1の領域をIRAMとして使うか、DRAMとして使うかはユーザーに任されているのですが、ここで言うユーザーというのは、ハードウェアとしてのESP32を直接叩くファームウェアの開発者ぐらいの意味で、ESP-IDF(公式の開発フレームワーク)の実装は、SRAM1をDRAMとして使う設定になっているようなので、我々ユーザー(製品としてのESP32の利用する人々)にとっては、これが唯一の選択肢になると思います。

それぞれの領域の詳細

大事なことなので、もう一度いいますが、ESP-IDFによってSRAM1はデータ領域として定義されています。そのため、私達が使う際にプログラムのロード領域として利用できるのは、SRAM0が唯一の領域となります。さらに悪いことに(?)、SRAM0(=IRAM)の領域もすべてが使えるわけではなく、一部がCPUキャッシュとして予約されています。

  • IRAM: 合計192KBの内、最初の64KBはCPU0とCPU1のキャッシュに固定的に割り当てられています。残りの128KBは、特に時間が重要な処理やフラッシュメモリ自体にアクセスする処理に使用されます。
  • DRAM: 合計328KB。アプリケーションのデータ、BSSセグメント(グローバル・スタティックな変数領域)、ヒープに使用されます。アプリケーションの動的メモリ割り当てがここで行われます。

ESP32はデュアルコアCPUなので、CPUキャッシュに必要な領域も2つ必要になり、これに32KBつづ合計64KB取られます。つまり、色々用途に合わせて切り取られ、実質的に使える領域は128KBということになります。

これを多いと見るか、少ないと見るか。

DRAMの領域は328KBあって、実際にプログラムを開発するときは、命令領域よりもデータ領域の方が不足するという判断の元このようになっているみたいです。とはいえこちらも、最初の8KBはROMが使うデータ領域として予約され、Bluetoothを使うと54KB持っていかれます。残った領域はヒープとして利用できますが、264KBほどの容量と考えた方が良いですね。

結論

ESP32で、プログラムのロード領域として使用できるのは、128KBほどです。それ以外に、実行時の動的メモリ確保用に265KBほど利用できるということになります。

皆さん、利用はご計画的に。

Discussion