マイコン - FatFs

提供: MochiuWiki : SUSE, EC, PCB

概要

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を使用する際に必要なソースファイルを以下に示す。

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使用量の目安
構成 ROM使用量
最小構成 (読み取り専用、機能最小) 約2.1[KB]
基本構成 (読み書き、LFNなし) 約6〜8[KB]
標準構成 (読み書き、LFNあり) 約8〜10[KB]
フル構成 (全機能有効) 約13.0[KB]


ROM使用量は、アーキテクチャとコンパイラの最適化レベルに依存する。

RAM使用量

FatFsのRAM使用量は、ボリューム数とオープンファイル数によって決定される。

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層として実装が必要な関数を以下に示す。

ディスク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 関数で使用できる制御コマンドを以下に示す。

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型) の一覧を以下に示す。

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 パラメータが無効



参考リンク