esp8266 ArduinoのPROGMEM
HSES-LCD24での日本語表示を試みる際に、PROGMEMを調べた。
ArduinoのPROGMEMとは、データをROM領域に格納する仕組み。(reference,日本語)
C(C++)言語だとconst修飾子を付ければ、十分な気がするが、AVR等の小型のCPUだと、そうはならない。命令用のROMとデータ用のRAMのアクセス経路を分離し、回路を節約しているためだ。ATmegaとかだとROMのデータを読み込むには、専用の機械語があった気がする。
このためCのプログラムでは、起動前の初期化部(crt.Sとか)でROMにある変数の初期値を一旦RAMにコピーし、その後のプログラムでは全てRAM部をアクセスして処理を行う。これはconst宣言してあっても同じだし、”foo”などのような文字列定数であっても同じ。
RAMの容量が足りていれば問題無いが、RAMの使用を節約したい時や、大きなデータを扱いたい時は問題になる。PROGMEMおよび関連のマクロ、関数を使用するとRAMを消費せず、データをプログラムに格納できるようになる。具体的には、ROMに格納されているデータはpgm_read_byte()等でアクセスするようになるのだが、Arduinoでは、多くのライブラリー関数に ROM上のデータ(多くは文字列)用のインターフェースが準備されているので、若干のマクロをかませる程度で使用できる。
でも、こんなのは、小さなCPUを使っているからで、ESP8266ならconstで十分ではなかろうか、と思っていたのだが甘かった。
まず fontxのデータを .rodataセクションに埋め込んでみる。リンク時にエラー。RAM領域が足りないそうだ。そこでPROGMEMの定義を探す。
./hardware/esp8266/2.3.0/cores/esp8266/pgmspace.h:
#define PROGMEM ICACHE_RODATA_ATTR
./hardware/esp8266/2.3.0/tools/sdk/include/c_types.h:
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
埋込先を .irom.textに変更し、リンクできた。プログラムを実行させると例外が発生。いつものWatchDogTimerかと思ったがそうではない。いろいろ試すと、ROMデータをアクセスするところで発生している。
どうすりゃ良いの?と、いろいろ調べて以下の行を発見。
./hardware/esp8266/2.3.0/cores/esp8266/pgmspace.h
// flash memory must be read using 32 bit aligned addresses else a processor // exception will be triggered // order within the 32 bit values are // -------------- // b3, b2, b1, b0 // w1, w0
flashメモリーは32bit-alignでないアクセスでないと例外が発生する!? なるほど、そこをケチったか。だったら例外のハンドラを準備すれば対応できそう..とも思うが大変そうなので、pgm_read_byte()を使って、漢字をLCDに表示できるようになった。
プログラムは、整理して、公開したいと思う。うまくAdafruit_GFXに統合できるか?
最近のコメント