スポンサードリンク

デバイス編#15 ~君のapp0アンドapp1のその領域のせいだよ~

スマートカーテン

数記事前に複数ファイルからなるファームのコードを埋め込んだとき、全部縦に並んじゃってたんですよ。このブログを見てくださってる方にとってはすごく読みづらい見せ方になってたなーと反省してました。

そこでやぎ星人と裏でその問題を解決するようにphpを色々いじってやってました。
2人で頑張った末、指定したファイルの中身だけが表示されるタブ型の表示関数ができました。

時空が歪んでしまってますが、この記事で早速やぎ星人が使ってますんで見てやってください笑


こんにちは、ポニ丸です。

ファームの設計をやろうとおもってたんですが、前回の動作確認用ファームって実はBLE機能とWi-Fi機能が同居してなかったんですよ。

それがなぜかというと、同居させてコンパイルするとエラーが出てしまって失敗するんです。

今回はそんな問題解決を行う内容ですー。

問題提起

ESP32マイコンをターゲットボードとしてWi-FiとBLEの機能を同時に有効にした際、Arduino IDEでコンパイルをすると以下のメッセージが表示されて失敗する。

最大1310720バイトのフラッシュメモリのうち、スケッチが1330258バイト(101%)を使っています。
text section exceeds available space in board

ここで思うわけです。

ポニ丸
ポニ丸

あれ、ESP32のフラッシュって4MBじゃなかったっけ?1/4くらいになってんな。

英語の方を見ると「textセクションが使用可能スペースを超えてます。」とあるので、これはボードの設定側に問題があってあるんだろうと考えました。

おそらくtextセクションがハードウェアで使える領域よりかなり狭く設定されている可能性が高いです。

組み込み系に詳しくない方向けに説明すると、

textセクション=プログラムのそのものが格納される領域

になります。関数とかはこのセクションの中に入ってます。

ついでに書いておくと、変数は初期値のありなしスコープによってtextセクションとは別のセクションに格納されます。

組み込み系のプログラムを書く方でないと意識することが少ないと思いますが、もし気になればこのサイトを見てみてください。仕事し始めたころにこのサイトで組み込みの基礎知識を学んでました。

https://www.uquest.co.jp/embedded/learning/lecture11.html

今回みたいにBLEの機能やWi-Fiの機能を有効にすると呼ばれる関数とかが大幅に増えるためtextセクションに入れなきゃいけない内容がかなり増えちゃうんですが、「textセクションに入りきらないくらい内容が多いですよ!」と怒られちゃってる状況です。

「じゃあ処理を減らすしかないよね」と思うのは至極真っ当な考えではあるんですが、今回の問題として浮き上がってるのは実はそこじゃないんです。

ESP32マイコンがもってるフラッシュメモリってハードウェア的に4MBあるんですけど、このエラーでは最大1310720バイト(1.25MB)しかないって言われちゃってるんです。

4MBを色んなセクションで分けるのでtextセクションは4MB丸々もらえるわけじゃないんですが、それにしても割り当てられた領域が小さいわけです。

これはtextセクションを小さくしている黒づくめの悪人がいるってことなんです。もしかするとお酒の名前がコードネームとしてついてるのかもしれないです。

そこで!textセクションを小さく設定している箇所を突き止め、必要なサイズの領域を確保できるように修正をやっていこうというチャレンジです。

調査結果

早速ググりましょう!

google先生が間を取り持ってくれたおかげでSatoshi Shida先生のブログ内にその回答を見つけました。

Aruduino IDEだとBLEとWi-Fiを同時に使うアプリを書くとメモリ不足でビルドできない つれづれ日記
クラウド,コンピュータ,プログラム,サーバー,ソフトウェア,ネットワーク,日記

目論見通り、textセクションが小さく設定されていて入りきらない問題でしたね。

ほかの方のブログでも同じ解決方法をとっていたんですが、Arduino IDEから設定変更できずにexeファイルから読み込まれるボード設定ファイルを直接いじるっていうのは本質的に「修正」じゃなくてある種「裏技」といえるんじゃないかな、と。すごい不本意。

このページでは変更前と変更後の比較が載っていなかったため、そのあたりきっちり比較しながら解説していこうと思います。

default.csvの修正

状況把握

これは、ESP32マイコンをターゲットにコンパイルした際に読み込まれるパーティション設定のファイルです。このファイルで各セクションを配置する場所やサイズを指定してます。

ファイルがあった場所は以下です。

C:\Users\(ユーザ名)\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\tools\partitions

変更前のファイルがこんな感じになってます。

# Name		Type	SubType	Offset		Size		Flags
nvm		data	nvs	0x9000		0x5000	
otadata		data	ota	0xe000		0x2000	
app0		app	ota_0	0x10000		0x140000	
app1		app	ota_1	0x150000	0x140000	
spiffs		data	spiffs	0x290000	0x170000	

Nameのところに指定されたパーティション名の領域開始アドレスがOffsetで表され、Sizeがそのパーティションの領域サイズを示しています。

これだけじゃわかりづらい方もいると思うので、簡単に図示してみました。

ESP32が持っている4MBのフラッシュメモリはdefault.csvでは以下のように指定されています。

図にも書いていますが、app0とapp1がtextセクションの領域として取られています。

ここで「じゃあ1.25MBが2個分あるから2.5MB使えるんじゃないの?」って考える人も0じゃないかと思います。

これは今回の問題と関係ないことはないんですが、ちょっと本質とはずれるので簡単にだけ触れますね。

余談:ファーム更新機能とtextセクションの関係について

textセクションが二つ存在している理由は「ファームウェアを更新するため」なんです。

更新前で動いているファームを「ファームA」更新後のファームを「ファームB」だとしたときに、ファームAが持つ機能としてファーム更新を実行中にファームをtextセクションに書き込む必要があるんですね。

ただ、ファームAの動作中にファームAの領域にどんどこ上書きしちゃうと、上書きが完了する前にファームAとしての動作ができなくなってしまう上に、上書き前の状態に戻すことが自力で不可能になってしまいます。

そこでtextセクションを2つに分けるという考えが出てきます。

ファームAが書かれていない方のセクションにファームBを書き込んで、正常に書き込みが完了したときにだけ「起動するときに読み込むtextセクションの開始アドレス」を書き換えてリセットをかけるとファームBで起動ができるようになる、という仕組みです。

「起動するときに読み込むtextセクションの開始アドレス」の指定とかは図でいう予約領域にあります。

ちなみに図の中にあるOTAという単語はOver the Airという熟語の略で、簡単に言うと「無線通信を利用してファームウェアを受信してファーム更新を行う機能」だと思ってください、

ESP32マイコンはIoTに特化させたマイコンで、用途としてWi-Fiとかでつながってる機器に使われる前提があるのでOTA機能をサポートしたパーティション設定がデフォルトになってるという話ですね。

余談が長くなっちゃいましてすいません笑

修正方法

参考にしたページでは以下のように修正してください、と書いてます。

# Name	Type	SubType	Offset		Size		Flags 
nvm	data	nvm	0x9000		0x5000	 
otadata	data	ota	0xe000		0x2000	 
app0	app	ota_0	0x10000		0x340000	 
eeprom	data	0x99	0x350000	0x1000	 
spiffs	data	spiffs	0x351000	0xAF000		

一応、これに沿ってさっきのように図を載せておきますね。

textセクションが一つになった代わりに領域が大きくなりましたね。これで3.25MBまで使うことができます。

eepromの領域ですが、たぶん大本になっている人のファームでEEPROMとして使いたかったから確保したセクションだと思うので必須ではないです。(spiffsもいらなければ不要)

これでOKではあるんですが、textセクション用の領域が一つになったためにOTA機能が使えなくなっているのが注意事項ですね。

「OTAもやりたい。でも、Wi-FiとBLEも使いたい」という方はフラッシュメモリが大きなESP32マイコンを買ったり、両方の仕様が満たせるマイコンに変えるしかないですね。

boards.txtの修正

default.csvを修正してtextセクションが広がりましたが、これだけでは動かないです。

さっきの修正につじつまが合うようにboards.txtも修正をかけます。

C:\Users\(ユーザ名)\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4

上記のフォルダにあるboards.txtがターゲットです。

esp32.upload.maximum_sizeというパラメータの値を書き換えましょう。

[変更前]

esp32.upload.maximum_size=1310720

[変更後]

esp32.upload.maximum_size=3407872

変更後の値はなんぞやっていう話なんですが、これはdefault.csvでapp0のSizeを10進数に直した値です。0x340000 (16進数) = 3407872 (10進数) です。

これでうごくはず!

動作チェック

修正が完了したので再度コンパイルをやってみました。

結果は・・・

最大3407872バイトのフラッシュメモリのうち、スケッチが1330258バイト(39%)を使っています。

と表示され、無事コンパイル成功しました!やりました!

これである程度機能追加しても問題なくコンパイルすることができます。

衝撃の結末

無事問題を解決したわけですが、とんでもないことに後から気付いてしまいました。

結論から言うと、Arduino IDEで設定画面を見つけてしまったんです。

事の発端はdefault.csvが置いてあったフォルダで、同じようにパーティション設定のファイルがいっぱいあるんですよ。

それらを開くと特に修正なしで使えそうなものもあって、

ポニ丸
ポニ丸

読み込むファイルをdefault.csvから変えられれば解決やんけ。
むしろそういう設定がIDE上からできるからこうなってるんじゃ・・・?

と思ったわけです。

そこでArduino IDEの設定を見直しているとやはりありましたわ。ここまでの苦労が水の泡です。

「ツール」→「Partition Scheme」で連動してるんだったんですね。。ショック

んで、default.csvは一番上の「Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)」を示しているということだったんでしょう。

OTAを使わずtextセクションを広げる目的であれば「No OTA (2MB APP/2MB SPIFFS」を選択すれば2MBの領域を確保できるということですね。ちなみにそれでコンパイル通りました。

これが正攻法だったんですね。裏技を先に知ってしまいましたが笑

とはいえ、表示されている設定以外は受け付けられないですし、default.csvがあるフォルダに自前のファイルを追加してもこのIDE上で自動的に追加されることはないので、細かい設定がやりたい人はファイルを直で修正するしかないということですね。

難点としては、大本となるファイルを書き換えちゃうので別のプロジェクトでデフォルトの設定で使いたくても修正後の構成になっちゃう(プロジェクト固有の設定にできない)ところですね。

そこらへんも加味してプロジェクト毎にセクションもちゃんと設計したいという方には、ESP32用のコンパイラが入ったツールチェーンを導入してEclipseというIDEでやるのがおススメだと思いました。

時間があればEclipseでESP32の開発環境を整える記事を書くかもしれません。


正直、軽いメモ的な記事にするつもりでしたがかなりのボリュームになってしまいました笑

ファーム開発を仕事としてきた手前、持ってる知識を自分なりに加えてお伝えしたくなってしまったのが大きな原因ですね。反省。

ただ、ひとつひとつをしっかり理解しないまま先に進んでしまうと後で後悔することになるので、この記事では記事のメインストリームから外れすぎない程度に補足させていただきました。

見ていただいてる方の一助になればいいなと思います。

次回はファームの仕様設計を進めていきます。

ではでは!

コメント

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