概要
Arduino UNOを使用したセンサーに改良を加えていると、ある時から正常に動作しなくなり原因を調べたところ、SRAMメモリ不足が原因ということが分かりました。
丁度いい機会なので、SRAMメモリについて調べ、今後、同様の問題を早期に発見できるように対策を考えたいと思います。
先に結論を伝えると、空きメモリ容量が残っていても文字が追加できなくなることが分かりましたので、文字列が加算できなくなったタイミングでオーバーフロー判定とすることにしました。
環境
・Arduino UNO
仕様より:https://www.switch-science.com/catalog/789/
→SRAM:2KB(2048Byte)あることが分かります。
・書き込み時のメッセージと仕様が一致していることを確認します。
実行中の空きメモリ容量を調査
下記のサイトのfreeRamメソッドを使用し、空きメモリを調査します。
参考:https://playground.arduino.cc/Code/AvailableMemory
<メソッドを追加した時の書き込みメッセージと空きメモリ出力結果>
# define SERIAL_BAUD 9600
void setup() {
Serial.begin(SERIAL_BAUD);
dispMemory();
}
void loop() {
}
void dispMemory(){
Serial.print(F("Free memory="));
Serial.print(freeRam(), DEC);
Serial.println(F("[bytes]"));
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
メモリオーバー時の動作を確認
メンバ変数に文字を結合していき、メモリオーバーしたときの動作を確認します。
# define SERIAL_BAUD 9600
String m_buf = "a";
void setup() {
Serial.begin(SERIAL_BAUD);
dispMemory();
}
void loop() {
m_buf.concat(F("a"));
Serial.print(F("String Length="));
Serial.println(m_buf.length());
dispMemory();
}
void dispMemory(){
Serial.print(F("Free memory="));
Serial.print(freeRam(), DEC);
Serial.println(F("[bytes]"));
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
・メモリオーバーフロー後の出力結果: ※同じ出力結果が続きます。
文字数が1687バイトを超えたところで、文字列の増加が止まっています。
そして特にエラーにはならず、問題なく動作し続けています。
空きメモリは、140バイトは残っている状態で、文字が追加できなくなっているので、freeRamの結果だけを見て処理が継続できるかの判断はできなさそうです。
調査用メソッド作成
freeRamの結果を元に、オーバーフローを判定することは難しいようなので、今回は文字を加算した値が文字数として反映されているかどうかをチェックし、メモリオーバーフローが発生しているか確認するメソッドを作成しました。
bool isMemory(){
String s = F("");
s.concat(F("a"));
if(s.length() == 1){
return true;
}
return false;
}
文字が1669文字で文字追加が出来なくなっており、その結果(false:0)が表示されています。
まとめ
ArduinoMegaを使った開発が多かったため、ArduinoUnoでSRAMメモリ不足という問題になかなか気づくことが出来ず、時間を使ってしまいました。
今後は同様の問題が発生した場合も上記のコードを使えば素早く判断することが出来ると思います。