概要
プログラムの中にバイナリファイルを埋め込む方法を調べてみました。限定的ながら実現可能でした。
一般的な埋め込み方法
上記のサイトなどを利用して、バイナリファイルをC言語の配列形式に置換し、プログラムの中に埋め込みます。

上記のように手元にあった、小さいBMPファイルを変換したところ、ファイルサイズと同じ822バイトの配列に変換されました。
個人的にはこの方法が一番おすすめです。欠点としてはファイルを編集した場合に、もう一度手動で変換をする必要があります。この手のツールはいろいろあるので、バッチファイルなどを実行するとファイルを更新してくれるようにしたほうが本当はおすすめです、、、
.incbinを利用した方法
/* Import a binary file */ #define IMPORT_BIN(sect, file, sym) asm (\ ".section " #sect "\n" /* Change section */\ ".balign 4\n" /* Word alignment */\ ".global " #sym "\n" /* Export the object address to other modules */\ #sym ":\n" /* Define the object label */\ ".incbin \"" file "\"\n" /* Import the file */\ ".global _sizeof_" #sym "\n" /* Export the object size to oher modules */\ ".set _sizeof_" #sym ", . - " #sym "\n" /* Define the object size */\ ".balign 4\n" /* Word alignment */\ ".section \".text\"\n") /* Restore section */ IMPORT_BIN(".rodata", "red.bmp", redBMP); extern uint8_t redBMP[]; void setup() { Serial.begin(115200); delay(1000); } void loop() { Serial.printf("%p\n", redBMP); Serial.printf("%02X %c\n", redBMP[0], redBMP[0]); Serial.printf("%02X %c\n", redBMP[1], redBMP[1]); Serial.printf("%02X %c\n", redBMP[2], redBMP[2]); delay(1000); }
インラインアセンブラを利用して、ファイルを埋め込む方法です。一般的なgccであれば比較的対応している方式です。IMPORT_BIN文で、埋め込み場所とファイル名、変数名を指定して呼び出します。これでコンパイル時にred.bmpのファイルをredBMPという変数に埋め込んでくれます。
0x3f400020 42 B 4D M 36 6
ポインタアドレスは環境によって違う可能性がありますが、こんな感じの出力になりました。BM6ってのはBMPファイルの先頭ですね。サイトで変換したデータの先頭とも一致するのでただしそうです。
ちなみに埋め込む場所ですが、.dodataはリードオンリーのフラッシュ領域になります。.dataとか.bssに設置すればメモリ上に確保されて、編集できる?
前提条件
実は上記のコードは普通に実行すると動かないと思います!

Windows環境の場合、まずスケッチを保存してフォルダを作成します。その中に埋め込みたいファイルを設置します。このときfileなどのフォルダを作成したほうが本当は好ましいです。
そして、このinoファイルをダブルクリックしてArduino IDEを起動します。Arduino IDEは起動した場所のフォルダが読み込みの基準となります。
メニューから実行するとC:\Program Files (x86)\Arduinoなどがカレンドディレクトリになったりします。
この技は上記の.mapファイルを作成する方法を検証していて気が付きました。
まとめ
ちなみにプロジェクトの中じゃなくて、フルパスで記述すればかんたんに埋め込むことが可能です。ただ、環境によって変わるフルパスよりは相対パスの方がいいですよね?
ESP-IDFだと、idf_component_registerとかでも埋め込みが可能です。
まあ、、、フルパスで書くか、特殊な起動方法じゃないとエラーになるかなので、一度配列形式に変換してからのほうがおすすめです、、、
本来は証明証など、プロジェクトの中に含めたくないファイルをフルパスで記述して、プロジェクトから分離するための機能と思われます。
コメント