更新履歴:
2004/12/23 新規作成
2005/07/24 ファームの全関数を公開
法人向けのETC専用カード


ノートPCでPCカーナビをやっていますが、使うときのセッティングが面倒なのです。
そのため使用するのは遠出の時くらいでした。

せっかくGPSモジュールがあるのに、眠らせておくのはもったいない。
しかし使うにはPCが必要、というジレンマがありました。

そこで、日常的にナビはできなくても、最低限トラックログは記録しておきたいと思うようになり、PCが不要の単体で動くロガーを作ってみることにしました。
製作目標は毎日の通勤にもストレスなく使えることです。

記録メディアは SDカードの制御を勉強した こともあり、このカードを選びました。

また、カードへの記録はFATに対応するため、FATファイルシステムを実装します。
これは、カードをWindowsのエクスプローラなどから読めるようにするためです。


仕様は下記のようになっています。
マイコン PIC16F877 20MHz 3.3V駆動
一時記憶 日立 HM62256LP-10(256Kbits SRAM)
PICのポートに直結
記録メディア SD/MMCカード
現在は松下の64MBのSDで確認済み
ファイルシステム FAT16
ファイルフォーマット 似非NMEA
$GPRMCセンテンスを加工して記録。
このセンテンスを64バイトに収めて1レコードとし、固定長で記録。
ファイル名 ログ記録を開始するごとに、ルートディレクトリへ NMEA0000.LOG、NMEA0001.LOG、‥‥と連番で作成。
記録ポイント数 64MBのSDカードで約104万ポイント≒288時間≒12日間
電源 5V
GPSモジュールはそのまま5Vを供給
マイコンはレギュレータで3.3Vを生成して供給
動作状態の表示 ・電源LED
・センテンス受信LED
・カードアクセスLED


ファイルフォーマット

GPSから受信したNMEAデータのうち、GPRMCセンテンスを保存します。
が、GPRMCの行全てを保存するとサイズが中途半端なため、SDカードへの保存効率が悪いです。
よって、先頭の"$GPRMC,"を削除して1レコードを64バイトに収めます。

圧縮や独自フォーマット化すれば記録ポイントを増やせますが、チープなマイコンでは荷が重いです。

記録したログはツールを使用して完全なNMEAフォーマットに戻します。
その後は gigo さんの汎用ログコンバータが使えます。

カードへのアクセス方法

カードのI/Fは、通信が簡単に実現できるSPIモードで行うことにしました。
SPIモードでは、1ビット単位でシリアルにデータをやり取りします。
1ビットのタイミングは、ホスト(マイコン)からクロックを与えることでカードに知らせることができます。

カードへ1バイトを送信する場合は、1ビットずつシリアルに送信します。
SD/MMCはクロックの立ち上がりでデータを扱うため、1を送るときはData INをHighにしたあと、クロックを送ります。
下記はカードに 0x95 を送るときの例です。

 

カードからのデータ受信についても、クロックの立ち上がりでData OUTからデータが出力されます。
下記はカードから 0xFE を受信したときの例です。

 

これらを覚えてしまえば、あとはどうにでもなります。
カードとのプロトコルをデータシートから読んで実装します。

カードのプロトコルについては、ルネサスのMMC関連PDFに書いてありますので省略します。

FATシステムのデータ書き込み方法

FATファイルシステムのファイル書き込みについては、ググってみましたが参考記事が見つかりませんでした。
ということで自力で解決しなければなりませんが、読み込み方法は後述の資料を参照すれば分かるので、それを考えて逆の手順で書けばいいだけのことです。

ただし、読み込みはFATテーブルのポインタを読んでいけば目当てのデータクラスタが特定できます。
その反面、書き込みの場合はディレクトリエントリや空きクラスタの検索を行わなければならないため、多少複雑になって実行時間もかかります。

色々と考えた結果、今回は下記のような手順で書くことにしました。
■記録開始(ファイルの新規作成)
 1.FATテーブルの空きクラスタを検索し、0xFFFF書き込み(予約する)
 2.ディレクトリエントリの空き検索
 3.空きエントリにクラスタNo、ファイル名、属性などを書き込み

■データ書き込みループ
 1.1クラスタ分のデータ書き込み
 2.FATテーブルの空きクラスタを検索し、0xFFFF書き込み(次のクラスタを予約)
 3.前回のFATテーブルに今回のクラスタNoを書き込み
 4.ディレクトリエントリのファイルサイズ(暫定)を更新

■終了時
 1.ディレクトリエントリのファイルサイズを正しいものに更新

終了指示が来るまでデータ書き込みループを続け、FATチェーンを繋いでいきます。


(クリックで拡大)

こんな感じになります。
この例ではFATの5番目でデータが終了しています。

ディスクが断片化していると、空きクラスタの検索に時間がかかり、書き込み効率が悪くなります。
特に、次の空き相対クラスタがずっと先のセクタにあると最悪です(;´Д`)
できればログ取りに使うカードは、フォーマットした後にファイルの削除は行わないほうがいいと思います。

SRAMの扱い


SRAMの割り当ては上の図のようになっています。
256KbitのSRAMなので、32KBytesになります。
ただしアドレスに11bit分しか接続していないので、実質は2048バイトのメモリ空間を使用できます。

Card R/W Buffer:
 カードのアクセス用に、R/Wバッファとして使用します。

NMEA Data Buffer:
 NMEAのデータを1セクタ分保存するために使用します。

DirectoryEntry Cache:
 ディレクトリエントリのキャッシュとして使用し、ファイル属性をアップデートするときの効率化を狙います。

SRAMへの書き込みは、アドレスバスへ書き込みたいアドレス、データバスへ書き込むデータを出力します。その後にWEをLowにするとメモリに書き込まれます。

読み込みは、アドレスバスへ読み込みたいアドレスを出力し、OEをLowにします。
するとデータバスに指定したアドレスのデータが出力されます。

今回は日立のHM62256LP(256KBitのSRAM)を使用しましたが、もう出回ってないと思います。よって代替品でOKです。
10年くらい前にスーファミのRAMを増設するために買ったものですので‥

似非NMEA→NMEA変換ツール

SDカードに記録したログファイルをNMEAに変換します。

似非NMEAフォーマットから、完全なNMEAの$GPRMCセンテンスに変換します。
また、日時の世界標準時と日本の標準時との変換を行うため、チェックサムの再計算を行います。

変換元のファイルは必ずバックアップを取っておいてください。
万が一バグなどによって貴重なトラックログが壊れたりしても当方は責任を負いません。

sdlogcv.lzh 5KBytes

ファームウェア

CCSコンパイラ用です。
シリアル送受信はCCSの組み込み関数を使っています。
これ以外にコンパイラ依存のところは無いと思うので、他のコンパイラへの移植も容易かもしれません。

また、read_VFAT_info()の中身は空ですので、後述のゆきさんのAVR向けソースから移植してください。
(改変したものを勝手に再配布できないので)
(2005.07.24)BSDライセンスとのことで、公開させていただきます。

常に使うカードが同じなら、決めうちの値をグローバル変数にセットするだけでOKです。

mmc.c 33KBytes

#デバッグ用のコードが大量に残っているので見づらいと思います(w

回路図

SRAMへのアドレスとデータバスの配線が面倒ですが、普通に接続していけば問題ないと思います。

また、SDのプルアップ抵抗値やパスコンの容量は適当なため、ちゃんと調べて規格内の値にしてください。
とりあえず自分の環境では動いていますが、カードのメーカが違うと動かない可能性があります。

ちなみにRS-232Cのレベルコンバータはライブラリが無かったため手抜きです(w

gpslog.gif 20KBytes

#実際はISP端子のVccは接続せず、ターゲットに直接給電して書き込みを行っています。

参考資料

FAT16の扱いについては Kunioさん のページの「FATについて」が参考になります。
非常に分かりやすく書かれています。
ルートディレクトリに対して読み書きをする場合は、ここで全ての基礎知識が学べます。

FAT情報の読み方は ゆきさん のAVRによるMP3プレイヤー製作記事が参考になります。
BPBの情報判別モジュールは、ほとんどそのままPICに移植させていただきました。
有用なソースを公開していただきありがとうございます。

ルネサス からMMCカードの仕様やマニュアル類などをダウンロードできます。
これらのPDFは必携です。
私は穴があくほど何度も読み返しました。‥‥‥って、電子媒体に穴が空くかは別にして(w

例によって PCカード/メモリカードの徹底研究 を買いましたが、私にとってはあまり役に立ちませんでした(;´Д`)
実際のカードアクセスやFATの実装はググって資料を探したほうがいいかもしれません。
まあ、初期にググるキーワードの抽出や、とっかかりとして持っていて損はないと思います。

今後やること

音を出す。
目に付かない場所に設置した場合、LEDだけだと動いているか不安。
実際に車で走行テストしてみたところ、日中だと周りが明るく、LEDの点滅が分かりませんでした‥
圧電素子をつけてNMEAセンテンス受信時に鳴るようにしたい。

処理が冗長なところがあるので直したい。
同じようなことをやってる関数があるので共通化を‥

SRAMの接続に、アドレスとデータバスだけで19本もポートを占有されているので、どうにかしたい。
もうポートがいっぱいいっぱいなので拡張できません(w
ラッチのロジックICを使えば大幅に削減できますが、ラッチを行う手順が増えるため処理が遅くなる欠点が‥

その他

まだケースに入れてませんが、とりあえず動作テストは良好です。
途中でデータが壊れたりといったことは発生してません。





というか、素直にeTrexとか買えばいいのでしょうか?(;´Д`)


当サイト内の検索