# FatFsモジュール アプリケーション・ノート

### 移植の際に配慮すべきこと

FatFsモジュールは移植性に関して次の点を前提としています。

- 処理系はANSI C準拠であること。
  FatFsモジュールはANSI C準拠で記述されているので、ANSI C準拠のコンパイラなら特に処理系依存な点はありません。ただし、FATというシステム間でポータブルな構造体を操作するため、プロセッサのエンディアンの違いは意識する必要があります。これは ff.h(tff.h) で定義されているので、最初にこれを適切に設定します(忘れている場合はエラーを出す)。
- char/short/long のサイズは、それぞれ 8/16/32ビット で、intは 16ビット以上 であること。
  これは integer.h 内で typedef されています。整数の型とサイズに関しては、まっとうな処理系なら問題ないはずですが、既存の定義と衝突した場合は矛盾がないように注意しなければなりません。

### メモリ使用量 (R0.04b)

各種環境でのモジュールのメモリ使用量の例を示します。数値の単位はバイトで、Dは論理ドライブ数、Fは同時オープン・ファイル数を示します。最適化オプションは、全てコード・サイズとしています。

| AVR | H8/300H | MSP430 | TLCS-870/C | V850ES | SH2
--- | --- | --- | --- | --- | --- | ---
コンパイラ | gcc | CH38 | CL430 | CC870C | CA850 | SHC
_MCU_ENDIAN | 1 | 2 | 2 | 1 | 1 | 2
FatFs コード (標準, R/W構成) | 8722 | 8776 |  |  | 6402 | 7338
FatFs コード (最小, R/W構成) | 5814 | 5722 |  |  | 4094 | 4906
FatFs コード (標準, R/O構成) | 4248 | 4096 |  |  | 3010 | 3506
FatFs コード (最小, R/O構成) | 3038 | 3110 |  |  | 2210 | 2698
FatFs 静的ワーク | D*2 + 2 | D*4 + 2 |  |  | D*4 + 2 | D*4 + 2
FatFs 動的ワーク | D*554 + F*544 | D*554 + F*550 |  |  | D*554 + F*550 | D*554 + F*550
Tiny-FatFs コード (標準, R/W構成) | 7264 | 7240 | 6634 | 8837 |  |
Tiny-FatFs コード (最小, R/W構成) | 4750 | 4806 | 4366 | 6163 |  |
Tiny-FatFs コード (標準, R/O構成) | 3600 | 3548 | 3212 | 4347 |  |
Tiny-FatFs コード (最小, R/O構成) | 2568 | 2702 | 2394 | 3322 |  |
Tiny-FatFs 静的ワーク | 4 | 6 | 4 | 4 |  |
Tiny-FatFs 動的ワーク | 544 + F*28 | 544 + F*32 | 544 + F*28 | 544 + F*28 |  |

### FatFs vs. Tiny-FatFs

ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。`_FAT32`オプションでFAT32対応を追加できますが、その分コード・サイズが膨らみます。フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。

メモリ容量 | FATタイプ
--- | ---
<= 64MB | FAT12
128MB〜2GB | FAT16
>= 4GB | FAT32

2GBまでのカードに限るなら、FAT32への対応は不要です。右の表にメモリ・カードの容量と規定のFATタイプ(SDメモリの場合)を示します。メモリ・カードの出荷時は、最大のパフォーマンスが出るようにデータ領域の境界が調整されたフォーマットになっています。したがって、PCでフォーマットするなどして規定と違うフォーマットになると、書き込み性能が大幅に低下する場合があるので注意が必要です。

### 効率の良いファイル・アクセスの方法

資源の限られた組み込みシステムで効率よくアクセスするためには、ファイル・アクセスの仕組みをある程度意識した使用が求められます。FatFsモジュールでは、ディスク上のファイル・データは f_read()内で次のような手順で読み出されます。

図1. セクタ・ミスアライメント・リード
図2. セクタ・ミスアライメント・リード
図3. セクタ・アライメント・リード

ここでファイルI/Oバッファとは、データ・セクタの一部を読み書きするための1セクタ長のバッファで、FatFsではそのファイル・オブジェクト内の、Tiny-FatFsではワークエリア内のバッファのことを指しています。

Tiny-FatFsでは、全てのデータ転送とFATやディレクトリへのアクセスをただ一つのセクタ・バッファで行っているため、データ転送によりFATのキャッシュが失われ、クラスタ境界を通過するたびにFATセクタを読み直す必要があります。FatFsの場合は、データ用バッファはFAT用とは別なので、FATセクタを読む頻度はTiny-FatFsの 1/341, 1/256 または 1/128で済みます(クラスタが連続している場合)。つまり、Tiny-FatFsは性能低下の代償を払ってRAM使用量を削減しているわけです。

転送領域のうちセクタ全体を含む部分は(図2)のようにファイルI/Oバッファを介さず、ディスクとの間で直接転送されます。完全なセクタ・アライメント・アクセスの場合(図3)は、ファイルI/Oバッファは全く使用されません。直接転送では、可能ならdisk_read()に複数セクタを指定して最大限のマルチ・セクタ転送が行われます。ただし、クラスタ境界をまたぐときはクラスタが隣接していたとしても転送は分割されます。

このように、極力セクタ・アライメント・アクセスになるように配慮すれば、無駄なメモリ・コピーが減って性能が向上します。さらに、Tiny-FatFsではFATのキャッシュが生きるようになり、省メモリ特性とFatFsの性能とが同時に得られます。

### クリチカル・セクション

ディスク上のFAT構造を操作している途中で、停電、不正なメディアの取り外し、回復不能なデータ・エラー等の障害が発生すると、処理が中途半端な状態で中断され、その結果としてFAT構造が破壊される可能性があります。次にFatFsモジュールにおけるクリチカル・セクションと、その間の障害により起きうるエラーの状態を示します。

図4. 長いクリチカル・セクション
図5. 短くしたクリチカル・セクション

赤で示したセクションを実行中に障害が発生した場合、クロス・リンクが発生して操作対象のファイル・ディレクトリが失われる可能性があります。黄色で示したセクションを実行中に障害が発生した場合、つぎのうちいずれかまたは複数の結果が生じる可能性があります。

- 書き換え中のファイルの内容が破壊される。
- 追記中のファイルがオープン前の状態に戻る。
- 新規に作成されたファイルが消える。
- 新規または上書きで作成されたファイルの長さがゼロになって残る。
- ロストチェーンの発生によりディスクの利用効率が悪化する。

いずれも書き込み中や操作対象でないファイルには影響はありません。これらのクリチカル・セクションは、ファイルを書き込みモードで開いている時間を最小限にするか、f_sync()を適宜使用することで図5のようにリスクを最小化することができます。

### 現リビジョンの問題点とその改善案

- ファイル・オブジェクトの抽象化
  現在はファイル・オブジェクトの実体をアプリケーション側で管理しているので、アプリケーション・モジュールでのスタック消費量が多くなります(Tiny-FatFsでは問題にならない)。これをハンドルで管理するなどより抽象化すればアプリケーション・モジュールでのスタック消費量を減らせるし、他のファイル・システムへの対応も容易になります。この場合、FatFs内でファイル・オブジェクトの領域を静的に確保しておくか、malloc()することになります。ただし、このようにするとファイル・オブジェクトを直接参照できなくなり、feofやftellなどムダな関数が新たに必要になります。
- セクタ・バッファ管理の改善
  現在はセクタ・バッファを固定して使用しているため、無駄なディスクアクセスが多く効率が悪い。メモリの潤沢なシステムでは、複数のセクタ・バッファを使用してディスク・キャッシュを構成すれば性能を向上させることができます。
- 長いファイル名への対応
  FATの拡張仕様ではMS-DOSの8.3形式ファイル名に加え、255文字までの長いファイル名(LFN)を扱えるようになっていますが、現リビジョンでは未対応で8.3形式しか使用できません。これに対応するには、ファイル名だけでも500バイト以上のバッファが必要になったり、UCS-2とShift_JISの相互変換(巨大な変換テーブルを使う)が必要となるなど、メモリの消費が爆発的に増えてしまいます。なお、LFNの機能はMicrosoft社の特許になっているため、これを製品に使うにはライセンス契約が必要です。
- RTOSへの対応
  FatFsモジュールを使用するタスクを一つに限るなら特に意識する必要はありませんが、同じ論理ドライブに複数のタスクから同時アクセスするには、何らかの排他制御が必要になってきます。FatFsモジュールのRTOSへの対応作業は、TOPPERSプロジェクトで行われています。

そして、これらの機能拡張を行うとそれだけ多くのリソースが要求されるようになり、このプロジェクトの対象とする8/16ビット・マイコンのシステムに載せられなくなってしまうという問題もあります(これが一番の問題かも知れません)。

戻る