公開日:2025/04/05
title.png

34th Season


#34-4 EEPROMをログストレージとして使う

 前回購入したEEPROMモジュールをログストレージとして使う環境を整備して行こうと思います。

ログストレージ

 他のセンサなどで計測したデータのログを取るために、前回購入したEEPROMモジュールを使おうと考えています(下図)。

a343_i2ceep.jpg

 本節では、データログを記録するための形式について考案したいと考えます。

ログに残す情報

 ログとして残したい情報を考えてみると、日付、時間、測定データ、等、様々であり、かつ、状況によってデータ種は多岐に渡ることが判ります。

 ログとして残すデータに関しては、柔軟に対応できるようにしておかなくては、ならない様です。

レコード

 1回分のデータを記憶する最小単位をレコードと呼ぶ事とします。
 前節で考察した様に、ログに残したい情報は様々なため、汎用的な形式だけを決めておき、個別のデータ形式については、用途毎に柔軟に決定できる事にしたいと思います。

 まず、レコードサイズを決めてしまいましょう。「柔軟」と言う意味では、レコードサイズも「可変長」にしておいた方が、より柔軟ではあります。しかし、可変長データを選択してしまうと、レコードの始まりを探索したり、次にログデータを書き込む位置を探索したりすることが困難となることが予想できます。
 処理の「容易さ」まで考慮に入れると、レコードサイズは固定しておいた方が良いでしょう。

  例)日時について考えてみよう。

 今回使うEEPROM(24C256)は?と言うと、ページ書き込みが可能で1ページ=64バイトなので、レコードサイズは64の約数(または倍数)であることが望ましいです。よって、レコードサイズの候補は、1,2,4,8,16,32,64,128,……です。
 もし、日付+時間+データを一気に記録する用途では、16バイト未満のレコードサイズでは小さすぎます。
 逆に、64バイト以上では冗長に思われます。EEPROMは容量が小さいので、レコードサイズを大きくし過ぎると、記録可能なレコード数が制限されてしまうからです。

 残ったのは、レコードサイズ16バイトまたは32バイトなのですが、WireライブラリのBUFFER_LENGTH=32問題がありました。
 24C256への書き込みには、レコードデータ以外に、書き込みアドレス2バイトを送信する必要があります。この2バイトもBUFFER_LENGTH=32に含まれるため、レコードサイズ32バイトを選択してしまうと、Wireライブラリでは1回で送信することができません。
 Wireライブラリに依存しない、Arduino以外の環境(例えばBlockly for Moscoviumなど)では、32バイトのレコードを一度に書き込む事が可能ですが、Arduinoでも使いたいですからね……。

 Wireライブラリの糞仕様に制限されるのは不本意ですが、致し方ありません。レコードサイズは16バイトに決定します。

レコード仕様

 前節の考察を踏まえて、レコード仕様を以下の通り決定します。

  レコード仕様:

 レコード索引とレコード形式で整合性を確認する事で、前回記録した最終データ位置を見つけ出し、その続きから再開可能な仕様と、なっています。また、他の用途に使用していたEEPROMであっても、消去せずにログストレージとして流用可能な仕様でもあります。

※残っていた前のデータが、たまたま、整合性の取れるデータであった場合、その部分だけ、ごみデータが残ってしまうが、それはEEPROMの書き換え回数節約のため許容する。

 24C256の場合、256Kビット=32Kバイトなので、レコードサイズ16バイトであれば、2,048個のレコードを記録可能です。

 なお、書き込み時間tWR=10ms(MAX)なので、1秒未満の高速なデータロギングが目的の場合は、書き込み時間にも注意してください。

ソフトウェア設計

 レコード仕様に合わせて、EEPROMへレコードを書き込むためのAPI関数仕様を以下の通り制定します。

  API関数仕様:

 簡素に2つの関数だけとしました。

プログラム

 完成したプログラムを以下にリンクします。

  完成プログラム:eep_storage.ino

 Arduino UNOとDUEM5StickC Plusで動作確認してあります。

 コンパイルしてArduinoへ書き込むと、シリアルモニタから以下のコマンドを受け付けています。

  シリアルモニタコマンド仕様:

 前回の予備実験を始めとして、今回制定したAPI関数群の動作検証を兼ねたプログラムです。

追加の実験

 実験の準備は前回と同様なので、こちらをご参照ください。以下、実験中の様子も、前回の予備実験と同様です(下図)。

a343_expr.jpg

 実験を進めましょう。

  実験サンプル:【 】内はシリアルモニタからの送信データ
  【wrec,TX,hello, world】
  OK+ eep_radr=0x0000, eep_ridx=0x7fcd
  OK: wrec

  【wrec,DT,\x20\x25\x03\x29\x10\x32\x54】
  OK: wrec

 早速、ログレコード×2個をEEPROMへ書き込んでみました。プログラムとしては、eep_rec_write()関数が実行されました。
 2つの目のサンプル(DTレコード)は、「2025年03月29日10時32分54秒」を、BCD(バイナリ値)で記録する例です。


  【dump,0000,48】
  OK+  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f : 0123456789abcdef
  0000: 7f cd 54 58 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 : ..TXhello, world
  0010: 7f ce 44 54 20 25 03 29 10 32 54 ff ff ff ff ff : ..DT %.).2T.....
  0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff : ................
  OK: dump 0x0000 ~ 48


 【wrec】コマンドを実行した時点で、EEPROMが購入したままのまっさらな状態なら、上の様な結果が表示されるはずです。なお、先頭レコードのレコード索引(最初の2バイト、上例では0x7fcd)は乱数で決定しているため、皆様の実験では異なる値が読めるはずです。2個目以降のレコード索引は、直前のレコード索引+1で増加して行きます。


  【list】
  LOG+ 0x0000: 0x7fcd,'TX',hello, world
  LOG+ 0x0010: 0x7fce,'DT', %\x03)\x102T\xff\xff\xff\xff\xff
  LOG: found 2 records
  OK: list: eep_radr=0x0020, eep_ridx=0x7fcf

 eep_next_record()関数を引数無しで呼び出すと、上に示した結果の様に、EEPROMに記録されたレコードがシリアルモニタへ送信されてきます。簡易ビュアとしても使用可能な事が確認できました。以上をもって、作成したAPI関数の動作確認完了です。


 Arduinoを使ってログを取得する場合は、こちらの関数群を使用できますし、仮に、別な環境を使ってログを取得する場合でも、こちらのレコード仕様に合わせておけば、今回作成したツールでログを閲覧することも可能です。そういう意味で、広く汎用的な仕様を策定して見ました。


btn_arduino.png

btn_prev.png btn_next.png

home