マイコン - FatFs
概要
FatFsは、elm-chanによって開発された汎用の軽量FAT/exFATファイルシステムモジュールである。
小規模な組み込みシステムやマイコン向けに設計されており、現在のバージョンはR0.16、BSDライセンスで配布されている。
対応するファイルシステムは、FAT12、FAT16、FAT32、exFATである。
ANSI C準拠で実装されているため、移植性が非常に高く、多様なアーキテクチャやコンパイラ環境で使用できる。
組み込みシステムにおける主な用途として、以下が挙げられる。
- SDカード
- SPI接続またはSDIOインターフェース経由でのSDカードアクセス
- USBメモリ
- USB Mass Storage Class (MSC) デバイスのファイルアクセス
- NANDフラッシュ / NORフラッシュ
- 各種フラッシュメモリデバイスへのファイルシステム構築
FatFsは、ファイルシステムロジックとストレージデバイスへのアクセス層を明確に分離した設計を採用している。
ユーザはディスクI/O層のみを実装することで、対象ハードウェアへの移植が完了する。
ロングファイルネーム (LFN) サポート、Unicode対応、マルチボリューム対応、リエントラント (スレッドセーフ) 動作等、多くのオプション機能をffconf.hで有効化できる。
モジュール構成
アーキテクチャの階層構造
FatFsは、4層構造のアーキテクチャを採用している。
各層の役割が明確に分離されており、ハードウェア依存部分の実装のみで移植が完了する。
- アプリケーション層
- ユーザコードがFatFsのAPI関数 (f_open、f_read、f_write等) を呼び出す層である。
- ファイルシステムの詳細を意識せずに、ファイル操作を記述できる。
- FatFs層 (ff.c / ff.h)
- ファイルシステムロジック全般を実装する層である。
- ファイル操作、ディレクトリ操作、ボリューム管理の処理が含まれる。
- ユーザが変更する必要はなく、そのまま使用する。
- ディスクI/O層 (diskio.c / diskio.h)
- ストレージデバイスへの読み書きを抽象化する層である。
- ユーザが対象ハードウェアに合わせて実装する必要がある。
- FatFs層とメディアアクセス層の橋渡し役を担う。
- メディアアクセス層
- 実際のストレージ (SDカード、フラッシュメモリ等) へのハードウェアアクセスを行う層である。
- SPIドライバ、UARTドライバ、フラッシュドライバ等が該当する。
ソースファイル構成
FatFsを使用する際に必要なソースファイルを以下に示す。
| ファイル名 | 説明 |
|---|---|
| ff.c | FatFsモジュール本体 ファイルシステムロジックを実装する。 通常、変更は不要である。 |
| ff.h | FatFsモジュールのヘッダファイル API関数のプロトタイプ、構造体定義、型定義が含まれる。 |
| ffconf.h | FatFsモジュールの設定ファイル 機能の有効 / 無効化、メモリ設定、ロケール設定等をマクロで定義する。 |
| diskio.c | ディスクI/O層の実装ファイル ユーザが対象ハードウェアに合わせて実装する。 |
| diskio.h | ディスクI/O層のヘッダファイル 関数プロトタイプとステータス定義が含まれる。 |
| ffunicode.c | Unicode変換テーブル ロングファイルネーム (LFN) 使用時に必要となる。 |
リソース要件
ROM使用量
FatFsのROM使用量は、有効化する機能によって大きく変化する。
| 構成 | ROM使用量 |
|---|---|
| 最小構成 (読み取り専用、機能最小) | 約2.1[KB] |
| 基本構成 (読み書き、LFNなし) | 約6〜8[KB] |
| 標準構成 (読み書き、LFNあり) | 約8〜10[KB] |
| フル構成 (全機能有効) | 約13.0[KB] |
ROM使用量は、アーキテクチャとコンパイラの最適化レベルに依存する。
RAM使用量
FatFsのRAM使用量は、ボリューム数とオープンファイル数によって決定される。
| 構成要素 | 計算式 | 備考 |
|---|---|---|
| FATFS構造体 (ボリューム管理) | 約564バイト × V | Vはボリューム数 |
| FIL構造体 (ファイルオブジェクト) | 約552バイト × F | Fはオープンファイル数 |
| FIL構造体 (FF_FS_TINY=1時) | 約40バイト × F | セクタバッファをFATFS構造体と共有する。 |
| セクタバッファ | 512バイト | FATFS構造体に含まれる |
1ボリューム、1ファイルオープン時のRAM使用量の計算例を以下に示す。
- 通常モード (FF_FS_TINY = 0)
- 564バイト + 552バイト = 1,116バイト
- TINYモード (FF_FS_TINY = 1)
- 564バイト + 40バイト = 604バイト
ファイルアクセスAPI
ファイルオープン・クローズ
ファイルのオープンとクローズを行う関数を以下に示す。
f_open関数- ファイルをオープンまたは作成する。
- プロトタイプ:
FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode) fpはファイルオブジェクトへのポインタである。pathはファイルパスである。modeはアクセスモードであり、FA_READ、FA_WRITE、FA_CREATE_NEW、FA_CREATE_ALWAYS、FA_OPEN_ALWAYS、FA_OPEN_APPEND を指定できる。
f_close関数- オープンしたファイルをクローズする。
- バッファ内のデータがメディアに書き出される。
- プロトタイプ:
FRESULT f_close(FIL* fp)
ファイルのマウントからオープン、クローズまでの基本的な使用例を以下に示す。
FATFS fs;
FIL fil;
FRESULT res;
res = f_mount(&fs, "", 1);
if (res != FR_OK) return res;
res = f_open(&fil, "test.txt", FA_READ);
if (res != FR_OK) return res;
// ファイル操作...
f_close(&fil);
ファイル読み書き
ファイルへの読み込みと書き込みを行う関数を以下に示す。
f_read関数- オープンされたファイルからデータを読み込む。
- プロトタイプ:
FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT* br) btrは読み込むバイト数である。brは実際に読み込まれたバイト数が格納される。
f_write関数- 書き込みモードでオープンされたファイルにデータを書き込む。
- プロトタイプ:
FRESULT f_write(FIL* fp, const void* buff, UINT btw, UINT* bw) btwは書き込むバイト数である。bwは実際に書き込まれたバイト数が格納される。
読み込みと書き込みの使用例を以下に示す。
UINT br, bw;
char buffer[64];
// 読み込み
res = f_read(&fil, buffer, sizeof(buffer), &br);
// 書き込み
const char *text = "Hello, FatFs!";
res = f_write(&fil, text, strlen(text), &bw);
ファイルポインタ操作
ファイルポインタの位置を操作・取得する関数を以下に示す。
f_lseek関数- ファイル内の読み書き位置を移動する。
- プロトタイプ:
FRESULT f_lseek(FIL* fp, FSIZE_t ofs)
f_tell関数- 現在のファイルポインタ位置を取得する。(マクロ)
- プロトタイプ:
FSIZE_t f_tell(FIL* fp)
f_eof関数- ファイルが終端に達したか判定する。(マクロ)
- プロトタイプ:
int f_eof(FIL* fp)
f_size関数- ファイルサイズを取得する。(マクロ)
- プロトタイプ:
FSIZE_t f_size(FIL* fp)
ファイル同期・切り詰め
データの確実な書き出しとファイルサイズ変更を行う関数を以下に示す。
f_sync関数- バッファに保持されているデータをメディアに書き出す。
- プロトタイプ:
FRESULT f_sync(FIL* fp) - 書き込み中のデータ消失リスクを低減するために、定期的に呼び出すことを推奨する。
f_truncate関数- ファイルを現在のファイルポインタ位置で切り詰める。
- プロトタイプ:
FRESULT f_truncate(FIL* fp)
ボリューム管理API
マウント・アンマウント
ファイルシステムのマウントとアンマウントを行う関数を以下に示す。
f_mount関数- ファイルシステムを論理ドライブにマウントする。
- プロトタイプ:
FRESULT f_mount(FATFS* fs, const TCHAR* path, BYTE opt) opt=0を指定すると、マウントが遅延される (最初のアクセス時に実マウントが行われる)。opt=1を指定すると、即時マウントが行われる。
マウントおよびアンマウントの使用例を以下に示す。
FATFS fs;
FRESULT res;
// 即時マウント
res = f_mount(&fs, "", 1);
if (res == FR_OK) {
// マウント成功
}
// アンマウント
f_mount(NULL, "", 0);
ボリューム情報取得
ボリュームの空き容量を取得する関数を以下に示す。
f_getfree関数- ボリュームの空きクラスタ数を取得する。
- プロトタイプ:
FRESULT f_getfree(const TCHAR* path, DWORD* nclst, FATFS** fatfs)
フォーマット
ボリュームをフォーマットする関数を以下に示す。
f_mkfs- ボリュームをFATまたはexFATでフォーマットする。
FF_USE_MKFS=1時に有効となる。- プロトタイプ:
FRESULT f_mkfs(const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len)
ディレクトリ操作API
ディレクトリの作成・変更
ディレクトリの作成とカレントディレクトリの変更を行う関数を以下に示す。
f_mkdir関数- 新しいディレクトリを作成する。
- プロトタイプ:
FRESULT f_mkdir(const TCHAR* path)
f_chdir関数- カレントディレクトリを変更する。
FF_FS_RPATH >= 1時に有効となる。- プロトタイプ:
FRESULT f_chdir(const TCHAR* path)
f_chdrive関数- カレントドライブを変更する。
FF_FS_RPATH >= 1時に有効となる。- プロトタイプ:
FRESULT f_chdrive(const TCHAR* path)
ディレクトリの読み取り
ディレクトリのオープン・エントリ読み取り・クローズを行う関数を以下に示す。
f_opendir関数- ディレクトリをオープンする。
- プロトタイプ:
FRESULT f_opendir(DIR* dp, const TCHAR* path)
f_readdir関数- ディレクトリの次のエントリを読み取る。
fnoにNULLを渡すと、ディレクトリを先頭に巻き戻す。- プロトタイプ:
FRESULT f_readdir(DIR* dp, FILINFO* fno)
f_closedir関数- ディレクトリをクローズする。
- プロトタイプ:
FRESULT f_closedir(DIR* dp)
f_findfirst関数- パターンマッチでディレクトリ検索を開始する。
FF_USE_FIND >= 1時に有効となる。- プロトタイプ:
FRESULT f_findfirst(DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern)
f_findnext関数- 次の一致エントリを検索する。
- プロトタイプ:
FRESULT f_findnext(DIR* dp, FILINFO* fno)
ファイル・ディレクトリ管理API
ファイル操作
ファイルおよびディレクトリの情報取得・削除・名前変更・属性変更を行う関数を以下に示す。
f_stat関数- ファイルまたはディレクトリの情報を取得する。
- プロトタイプ:
FRESULT f_stat(const TCHAR* path, FILINFO* fno)
f_unlink関数- ファイルまたは空のディレクトリを削除する。
- プロトタイプ:
FRESULT f_unlink(const TCHAR* path)
f_rename関数- ファイルまたはディレクトリの名前を変更する。
- 異なるディレクトリへの移動も可能である。
- プロトタイプ:
FRESULT f_rename(const TCHAR* path_old, const TCHAR* path_new)
f_chmod関数- ファイルまたはディレクトリの属性を変更する。
FF_USE_CHMOD=1時に有効となる。- プロトタイプ:
FRESULT f_chmod(const TCHAR* path, BYTE attr, BYTE mask)
f_utime関数- ファイルまたはディレクトリのタイムスタンプを変更する。
FF_USE_CHMOD=1時に有効となる。- プロトタイプ:
FRESULT f_utime(const TCHAR* path, const FILINFO* fno)
ディスクI/Oインターフェース
必須関数
ディスクI/O層として実装が必要な関数を以下に示す。
| 関数名 | プロトタイプ | 説明 |
|---|---|---|
disk_status |
DSTATUS disk_status(BYTE pdrv) |
ストレージメディアの状態を返す。 |
disk_initialize |
DSTATUS disk_initialize(BYTE pdrv) |
ストレージメディアとコントローラを初期化する。 |
disk_read |
DRESULT disk_read(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) |
メディアからセクタデータを読み込む。 |
disk_write |
DRESULT disk_write(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) |
メディアにセクタデータを書き込む。 |
disk_ioctl |
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) |
デバイス固有の制御コマンドを実行する。 |
get_fattime |
DWORD get_fattime(void) |
現在の日時を返す。 タイムスタンプ用途に使用される。 |
各関数の実装上の補足事項を以下に示す。
disk_status関数- 戻り値は STA_NOINIT (未初期化)、STA_NODISK (メディアなし)、STA_PROTECT (書込保護)、0 (正常) のビット組み合わせである。
disk_initialize関数- SDカードの場合、SPIモードの初期化として CMD0、CMD8、CMD55+ACMD41 等のコマンドシーケンスを実行する。
disk_read関数- シングルブロック読み込みは CMD17、マルチブロック読み込みは CMD18 を使用する。
disk_write関数- シングルブロック書き込みは CMD24、マルチブロック書き込みは CMD25 を使用する。
get_fattime関数- 32ビット値で年 (YYYY)、月 (MM)、日 (DD)、時 (hh)、分 (mm)、秒 (ss) をビットパックした値を返す。
ディスクI/O関数のプロトタイプを以下に示す。
#include "diskio.h"
DSTATUS disk_status(BYTE pdrv);
DSTATUS disk_initialize(BYTE pdrv);
DRESULT disk_read(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff);
DWORD get_fattime(void);
disk_ioctlコマンド
disk_ioctl 関数で使用できる制御コマンドを以下に示す。
| コマンド | 説明 |
|---|---|
CTRL_SYNC |
保留中の書き込み処理の完了を待つ。書き込みキャッシュを持つデバイスで使用する。 |
GET_SECTOR_COUNT |
メディアの総セクタ数を取得する。f_mkfs 使用時に必要となる。 |
GET_SECTOR_SIZE |
セクタサイズを取得する。対応サイズは 512 / 1024 / 2048 / 4096 バイトである。 |
GET_BLOCK_SIZE |
フラッシュメモリの消去ブロックサイズを取得する。f_mkfs 使用時に最適化に利用される。 |
CTRL_TRIM |
不要セクタの消去を通知する。TRIM対応デバイスで使用する。 |
エラーコード
FatFsのAPI関数が返すエラーコード (FRESULT型) の一覧を以下に示す。
| エラーコード | 値 | 説明 |
|---|---|---|
FR_OK |
0 | 成功 |
FR_DISK_ERR |
1 | ディスクI/Oレイヤでエラーが発生した |
FR_INT_ERR |
2 | 内部エラー (FatFs内部のアサーション失敗) |
FR_NOT_READY |
3 | ストレージデバイスが準備できていない |
FR_NO_FILE |
4 | 指定されたファイルが見つからない |
FR_NO_PATH |
5 | 指定されたパスが見つからない |
FR_INVALID_NAME |
6 | ファイル名の形式が不正 |
FR_DENIED |
7 | アクセスが拒否された (読み取り専用、ディレクトリが空でない等) |
FR_EXIST |
8 | 同名のファイルまたはディレクトリが既に存在する |
FR_INVALID_OBJECT |
9 | ファイルオブジェクトが無効 |
FR_WRITE_PROTECTED |
10 | メディアが書き込み保護されている |
FR_INVALID_DRIVE |
11 | 論理ドライブ番号が無効 |
FR_NOT_ENABLED |
12 | ボリュームがマウントされていない |
FR_NO_FILESYSTEM |
13 | 有効なFATボリュームが見つからない |
FR_MKFS_ABORTED |
14 | フォーマットが中断された |
FR_TIMEOUT |
15 | 操作がタイムアウトした |
FR_LOCKED |
16 | ファイルがロックされている |
FR_NOT_ENOUGH_CORE |
17 | メモリ不足 (LFNバッファ等) |
FR_TOO_MANY_OPEN_FILES |
18 | オープンファイル数が上限に達した |
FR_INVALID_PARAMETER |
19 | パラメータが無効 |
参考リンク
- FatFs公式ページ
- FatFsモジュールのダウンロード、ドキュメント
- FatFs公式ページ (日本語)
- 日本語版のドキュメント
- FatFs Application Note
- アプリケーションノート、移植ガイド
- Petit FatFS
- 超軽量版FatFsモジュール
- 関連ページ
- マイコン - FatFsの設定 - ffconf.hの設定項目詳細
- MSP430F149 - FatFs - MSP430F149でのハードウェア接続とドライバ実装
- MSP430F149 - FatFsの応用 - アプリケーション実装例とトラブルシューティング