組み込み系

製品コストを抑える鍵はメモリーの理解から!

SS価格看板

先日、ガソリンスタンド経営の友人より『派手な価格看板を開発してくれ!』という依頼を受け、開発製造したのがこれです。
これは、ここにいる、IoT京都のメンバー達との共同開発品で、今後どんどん欲しい方に受注製造してお届けしようと企画しています。

この開発も実はArduinoを使ったのですが、メモリーについて嵌りました。

かんたんで便利なので、お遊び感覚でやってたのですが、途中でパタっと….
まぁとにかく予算に余裕があったので、大きなボードとArduino3枚使いしましたけど…
やはりマイコン物はメモリーとの勝負です。

そこで、Arduinoのメモリーの使われ方をご参考までに。

Arduinoのメモリーはどのように使われるのか?

比較表に記載した中の下記の部分がArduinoのメモリーです。

ArduinoMemoryまずは、このFlash・SRAMや・EPROMというメモリーがが、Arduino プログラミングでどのように使われているのかを理解します。

Flash

電源を落としても記憶されているメモリーで、Arduinoでは、開発したプログラムと、Arduinoのブートローが配置されます。
また、C言語でいう、#define などで宣言された定数がここに格納されます。
変数などはここには格納されません。

SRAM

電源を落としたと同時に消滅するデータを一時展開するためのメモリーです。
プログラム内で使用する、int やchar等で宣言された一時的な変数が展開されます。
よって、変数を使いすぎるとこの領域がどんどん減ってしまい、動かないプログラムが自然にできあがってしまう可能性があります。
コンパイル結果として、残メモリー容量などが目安として表示され、問題ないように見えても、動作中に一時的に多くのメモリーを使い、メモリー破壊によりあるときから急に挙動不審に陥ることがあります。
変数や特に文字列の使用には気をつけなくてはいけません。

EEPROM

ユーザープログラムによって制御できる、電源が落ちても消滅して欲しくないデータを記憶させておくためのメモリーです。
簡単なコマンドで読み書きが可能ですので、PCのHDDと同じ感覚で使いがちですが、EEPROMの読み書の限界回数があります。
そのため、プログラムから頻繁に読み書きを行う制御をした場合、ある日突然EEPROMの限界数に達成し、動かなくなるという現象に陥る可能性が考えられます。
組込み機器は、一旦出荷してしまえば、結構長い年月使用されるケースが多いため、突然の原因不明の故障を防ぐためにも、EEPROMの扱いには気をつけけなければいけません。
考えられる対策としては、プログラム動作中に書き換えられるデータはSRAMに記憶し、電源OFF前に一気にEEPROMに格納するという処理です。

プログラムによるメモリー使用の確認方法

開発中のプログラムが、どのようにメモリーを使用しているのかは、Arduinoに付属するコマンドラインのプログラム、avr-objdump.exeを利用することで確認することが可能です。
これはArduinoをインストールしたフォルダーに展開されている、コマンドラインで動作するプログラムです。
インストーラなどによってインストールした場合には、一般的には下記のフォルダーに展開されています。

C:Program Files (x86)Arduinohardwaretoolsavrbin

 

コンパイル時に.elfファイルが生成されメモリー使用状況が格納される

Arduinoプログラムのコンパイル時に .elfという拡張子が生成されます。
この .elfファイルをコマンドプログラム[avur-objdump]によって中身を表示することで確認することができます。
この.elfファイルは、バイナリーファイルであるため、テキストエディタなどによって中を見ることはできません。

まずは .elfファイルが生成される場所を確認しておくために

まずは.elfファイルが一時的にどこに作成されるのかを確認しなければなりません。
そのためには、ArduinoのIDEを起動し、[MENU]-[ファイル]-[環境設定]のダイアログにおいて、下記の部分「より詳細な情報を表示する:」にチェックを入れておきます。
Arduino環境設定ダイアログ

こうすることで、Arduino の下段のコンパイル情報部分に詳しく表示されます。
コンパイル後、この情報の中から.elfファイルの存在位置を確認し以下の方法でダンプをします。
例)C:Usersユーザー名AppDataLocalTempbuild21c5289bb87da5bd7776d02aa59a41ae.tmp

 

avr-objdumpを使い確認する方法

avr-objdumpはコマンドプロンプトで操作するプログラムです。
そのため、このプログラムをいつでも使えるようにまずはPathを通しておく必要があります。
例)C:>PATH C:Program Files (x86)Arduinohardwaretoolsavrbin

その後、elfファイルをavr-objdupによってリードします。
c:>avr-objdump -h memorytest.ino.elf

赤文字部分はご自分で作成されたプログラム名称 +.elfとなります。
※今回は、memorytestというスケッチをデスクトップに作成して実験です。
下記が表示されたイメージです。
このなかで、 [0.data] [1.text] [2.bass] という部分を確認することでメモリー使用を確認できます。

int

arduino memory

できるだけ#define等の定数を利用する

それでは、定数と変数の使用によってどのくらいメモリー使用が変わるか簡単なプログラムを作り実験をして見ます。
#defineによる定数と、intによる変数でのコーディングにより、コンパイル時にコメントアウトを切り替えてその結果を見てみます。

sample

#define p2 13
#define p3 13
#define p4 13
#define p5 13
#define p6 13
#define p7 13
#define p8 13
#define p9 13
/*
int p1= 0;
int p2= 1;
int p3= 2;
int p4= 3;
int p5= 4;
int p6= 5;
int p7= 6;
int p8= 7;
int p9= 8;
*/
void setup() {
    pinMode(p1,OUTPUT);
    pinMode(p2,OUTPUT);
    pinMode(p3,OUTPUT);
    pinMode(p4,OUTPUT);
    pinMode(p5,OUTPUT);
    pinMode(p6,OUTPUT);
    pinMode(p7,OUTPUT);
    pinMode(p8,OUTPUT);
    pinMode(p9,OUTPUT);
}
void loop() {
    digitalWrite(p1,OUTPUT);
    digitalWrite(p2,OUTPUT);
    digitalWrite(p3,OUTPUT);
    digitalWrite(p4,OUTPUT);
    digitalWrite(p5,OUTPUT);
    digitalWrite(p6,OUTPUT);
    digitalWrite(p7,OUTPUT);
    digitalWrite(p8,OUTPUT);
    digitalWrite(p9,OUTPUT);
}

#defineによる結果

define

0.data  1.textのサイズがメモリーに関する結果です。
ここでは dataは24 textは000011a0という値になっています。

intによる結果

int

ここでは dataは34 testは000011c4です。

結果

#defineで宣言した場合より明らかにおおきな数字になっています

最後に….

これだけでもメモリー使用はこれだけ変化します。
そのほか、メモリー節約プログラミングにはいろいろなコマンドがありますが、技術の深い面になってきますので、ここでは割愛しておきます。
とにかく、組込みはメモリーとの戦いとなります。
この先ご紹介するIO制御の関数の使い方でも、メモリーや処理速度に影響しますので、製品化を考えた場合、このあたりをきっちり押さえておく必要があります。

まぁそれでもボードもCPUも安いので、あまりごちゃごちゃ考えず、思いっきり使いまくる!足らなきゃ足す!でもいいかもしれません。

Arduinoでの試作はいつでもご相談ください!

2016.2.03 吉川

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