M5Stack basicで日本語フォント表示に大変苦労した話
M5Stack basicで日本語表示したい!
誰かに見せる事を考えると日本語フォントを表示したいことはありますよね
ただ、自分の場合はちゃんと表示できるようになるまでとても苦労したのでその経緯を残しておきます。
日本語表示
M5Stackでの日本語表示はSDカードにフォントを保存し、SDカードを挿した状態で以下のようにできます。
M5.Lcd.loadFont(フォント名,SD);
M5.Lcd.println("こんにちは、世界");
問題発生!
実際に自分がすでに書いていたWifiやPubsubクライアントなどを使用したプログラムに日本語表示を組み込みました。
しかし、実行したら以下のようなダンプを吐いてクラッシュしてしまいました
Guru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400d5310 PS : 0x00060330 A0 : 0x800d59f1 A1 : 0x3ffb2700
A2 : 0x3ffc42f4 A3 : 0x000033b9 A4 : 0x00000000 A5 : 0x0005a854
....
原因
メモリ不足でした。M5Stack basic の全体のRAMが520kBで小さめであることが問題のようです。
調査履歴
その1
日本語表示のみを行うプログラムを書いて実行できる事を確認
その2
loadFontを行うタイミングでクラッシュしている事を確認
その3
loadFontをプログラムの最初で行うと今まで動いていた他の部分がクラッシュする
原因特定!
上記の内容を鑑みて、空きメモリ量を確認してみたところヒープメモリが足りないことがわかりました。
メモリ不足かどうかを確認するには esp_get_free_heap_size()
関数を使います。
int before = esp_get_free_heap_size();
M5.Lcd.loadFont(フォント名,SD);
M5.Lcd.println("こんにちは、世界");
int after = esp_get_free_heap_size();
M5.Lcd.print("フォント名は ");
M5.Lcd.print(after-before);
M5.Lcd.print(" byteのヒープメモリを使用しています");
対策方法
原因が分かったとはいえ対策はちょっと大変です。
いろいろ調べてみたところ対策方法は以下の3つが多いようです
対策案その1
日本語フォントファイルを必要な文字のみを含むよう小さいものにする
対策案その2
フォント以外のライブラリを軽量化する
対策案その3
フォントの読み込み方法を変更し、メモリ負荷を軽くする。
今回は対策案その3を使います
プログラムのメモリ構造
ここで、対策の前にメモリ構造の話をちょっとだけします。
プログラムのメモリは多くのシステムで以下のような構造で配置されています。
領域名 | 用途 | 配置先 |
---|---|---|
テキスト領域 | プログラム本体を配置 | フラッシュメモリ |
データ領域 | グローバル変数やstatic変数 | RAM |
BSS領域 | 初期化されていないグローバル変数やstatic変数。0初期化される | RAM |
ヒープ領域 | newやmallocで取得する領域 | RAM |
スタック領域 | ローカル変数や関数呼び出しの引数、戻り値 | RAM |
今回はloadFont内で大量にメモリを確保しようとしたためにヒープ領域が足りなくなった事が原因ですね。
まず、M5Stack basicのプログラムが使用するメモリであるRAMは520kBです。
そしてプログラムから確認したところ、プログラム開始時の使用可能ヒープメモリは235kBでした。
フォント読み込み後の空きヒープメモリは72kBでフォントを読み込むだけで実にヒープを7割使ってしまうということが発覚しました。
いざ、対策
loadフォントと同等の機能で保存先をヒープ以外に作るとしてもRAM全体が520kBで半分近くはヒープメモリのため難しそうです。そのためメモリ上に展開しないフォント表示ライブラリを探しました。
そして見つけたのがeFontというライブラリでした。
問題発生その2!
eFontというライブラリをコンパイルして書き込もうとした時にまたエラーが発生しました。
Sketch uses 1730217 bytes (132%) of program storage space. Maximum is 1310720 bytes.
Global variables use 46128 bytes (14%) of dynamic memory, leaving 281552 bytes for local variables. Maximum is 327680 bytes.
Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.
text section exceeds available space in board
今度はテキスト領域が足りないようです。
M5Stack basicのフラッシュメモリは4MBあるはずなのに、1.25MBしかテキスト領域に使ってくれていないようです。
解決
ここで、調べてみるとarduino IDEではpartition schemaを使うことでテキスト領域を増やす事ができそうです。
OTA(ネットワーク越しのプログラム更新)をする予定はないので No OTA(Large app)
を設定することで、無事日本語表示ができるようになりました。
めでたし
参考
Discussion