Flashメモリに一定間隔で加速度の値を記録する方法


[状況]  
現在、10Hz(100msec)間隔で3軸加速度の値を取得し、SPRESENSEのFlashメモリへtxtファイルに書き込んで記録するプログラムを作成しています。  
しかし、microSDカードに記録することは問題がないのですが、Flashメモリに記録すると時間が経過するにつれセンサ値の取得の間隔時間が大きくなってしまいます。  
この原因はvoid loop()内でファイルオープン→書き込み→ファイルクローズをおこなってしまっているからと考えています。

[質問]  
1.ファイルを毎回オープンクローズせずに、Flashメモリにセンサ値が一定間隔で記録できるような手法がありますでしょうか。  
2.microSDカードとFlashメモリに記録する際になぜ添付した写真のような差が出るのでしょうか。

[環境]  
Arduinoにて開発しており、センサはROHM社のKX126-1063を使用しております。

[![画像の説明をここに入力](https://i.stack.imgur.com/S1uu9.png)](https://i.stack.imgur.com/S1uu9.png)




一般的にフラッシュメモリというのは次の特徴があります

  * 任意のタイミングで任意の１バイトを書くことはできません
  * ブロック消去といって、かなり大きい単位での消去が必要です（例えば 64KiB 単位）
  * 消去済み領域に限り、ページ書き込みが可能です（例えば 2KiB 単位）
  * 消去した回数で寿命が決まります

よってフラッシュメモリ上のファイルに追記してクローズすると、だいたい次のような処理が走ります。

  * ファイルの最終部を保持している領域の現在内容を読みます
  * ファイルの最終部を含む消去領域をブロック消去します
  * ファイルの最終部に、先ほど読んだ内容＋追記したい内容を書き込みます
  * ファイルをクローズすると、ファイルの管理領域（ファイル名やサイズが保管されている部分）を読んで消去して上書きします

同じファイルの末尾に追記を続けるとウエアレベリング（損耗対策）をしていないメモリ装置では同じメモリセルに対して消去・書き込みを繰り返しあっという間に寿命に達してしまいます

A2.  
SPRESENSE の内蔵 SPI フラッシュメモリにアクセスするルーチンはおそらく前述の処理を毎回全部やっているのでしょう（時間が一定なのが根拠）

お使いの microSD
カードのコントローラはウエアレベリングを行っていて、よって同じファイルに書いているつもりでもメモリカード内コントローラが書き込むセルを移動させている。消去済みメモリセルに書き込む場合は高速、メモリセルの消去実施後に書き込む場合は低速と、時間が一定しないわけです（書き込みを継続すると消去済みメモリセルがなくなって時間が余計にかかる）

A1. 毎回 `close()`/`flush()` しなくてもいいのなら `setup()` で `open()` し `loop()` 内部では
`close()`/`flush()` しないことを推奨します。要望に応じて数百回に１回とか適切なタイミングで `flush()` しましょう。

組み込み系の場合、途中で電源が落ちたとか信号線が外れたとか、不慮の事故があった際に直前データをどこまで保証するか、でいろいろ話が変わってくるのですが、前述のとおり

  * 毎回 `close()` する＝事故直前データが後で読める可能性が高い。が、損耗が大きそう。
  * `close()` や `flush()` しない＝事故直前データが失われる可能性が高い。それだけならまだしも、ファイル全部が失われることがありそう。でも損耗は小さい＝長時間保つだろう。

なのであとは案件次第。




一般的にフラッシュメモリというのは次の特徴があります

  * 任意のタイミングで任意の１バイトを書くことはできません
  * ブロック消去といって、かなり大きい単位での消去が必要です（例えば 64KiB 単位）
  * 消去済み領域に限り、ページ書き込みが可能です（例えば 2KiB 単位）
  * 消去した回数で寿命が決まります

よってフラッシュメモリ上のファイルに追記してクローズすると、だいたい次のような処理が走ります。

  * ファイルの最終部を保持している領域の現在内容を読みます
  * ファイルの最終部を含む消去領域をブロック消去します
  * ファイルの最終部に、先ほど読んだ内容＋追記したい内容を書き込みます
  * ファイルをクローズすると、ファイルの管理領域（ファイル名やサイズが保管されている部分）を読んで消去して上書きします

同じファイルの末尾に追記を続けるとウエアレベリング（損耗対策）をしていないメモリ装置では同じメモリセルに対して消去・書き込みを繰り返しあっという間に寿命に達してしまいます

A2.  
SPRESENSE の内蔵 SPI フラッシュメモリにアクセスするルーチンはおそらく前述の処理を毎回全部やっているのでしょう（時間が一定なのが根拠）

お使いの microSD
カードのコントローラはウエアレベリングを行っていて、よって同じファイルに書いているつもりでもメモリカード内コントローラが書き込むセルを移動させている。消去済みメモリセルに書き込む場合は高速、メモリセルの消去実施後に書き込む場合は低速と、時間が一定しないわけです（書き込みを継続すると消去済みメモリセルがなくなって時間が余計にかかる）

A1. 毎回 `close()`/`flush()` しなくてもいいのなら `setup()` で `open()` し `loop()` 内部では
`close()`/`flush()` しないことを推奨します。要望に応じて数百回に１回とか適切なタイミングで `flush()` しましょう。

組み込み系の場合、途中で電源が落ちたとか信号線が外れたとか、不慮の事故があった際に直前データをどこまで保証するか、でいろいろ話が変わってくるのですが、前述のとおり

  * 毎回 `close()` する＝事故直前データが後で読める可能性が高い。が、損耗が大きそう。
  * `close()` や `flush()` しない＝事故直前データが失われる可能性が高い。それだけならまだしも、ファイル全部が失われることがありそう。でも損耗は小さい＝長時間保つだろう。

なのであとは案件次第。

