ファイルシステムの概要
イントロダクションをスキップして、移行手順を直接確認することができます。
ファイル システムは、アプリケーション層と最下位層の間のあいまいな層です。最下層は、SDIO や SPI を使用してバイトを読み書きするなどの API を提供します。ファイル システムは、これらの API の組み合わせをラップし、ストレージ デバイス上でさらなる操作を実行するために使用できる一連の関数を提供します。
最下層: マイクロコントローラーの周辺機器を操作し、読み取りと書き込みを行います。それを設定する必要があります。
中間層: 中間層 FATFS モジュールは、FAT ファイル読み取り/書き込みプロトコルを実装します。
一般に、トップレベル、つまりファイルシステムによって提供される関数ライブラリに関係なく、これらを使用したいだけです。
FATFS の実装プロセス (白いボックスの内容は自分たちで実装する必要があるもの、つまり、基盤となるデバイスとユーザー アプリケーションの最上位レベルの入出力、青いボックスは fatfs によって提供されます)
ソースコードの取得
FATFS のソース コードと英語の説明は、Web サイト http://elm-chan.org/fsw/ff/00index_e.html からダウンロードできます。ダウンロードして解凍すると、ルート ディレクトリにソース コードとヘルプ ドキュメントの 2 つのフォルダーが存在します。
Fatfs が提供する固有の機能が DOC フォルダ内にあり、
SRC ファイルの構成は次のとおりです。
Fatfsのソースコードの読み方については「STM32F103を死角ゼロで遊ぶ ザ・ガイド」の読み方のヒントを参照してください、ただ使いたいだけであれば移植方法だけを見れば大丈夫です。
FATFS移植の準備
背景: 2 つのファイルffconf.h
diskio.c
ffconf.h
FATFS モジュールを移植する場合、通常はと の2 つのファイルを変更するだけで済みます: diskio.c
ffconf.h
FATFS モジュールのすべての設定項目は ffconf.h に保存されます。その中でいくつかのオプションを設定することで独自のニーズを満たすことができます。詳細についてはドキュメントで説明します。
spi のフラッシュの読み書きを例に挙げると、フラッシュ内の 1 バイトの spi の読み書きの基礎となるコードを認識した後、fatfs を移植できます。
0. 新しいプロジェクトを作成し、簡単なライティング、spi 操作、その他の機能を実装します。
1. SPI-FatFs というプロジェクトのソースコードを準備します。意思。FatFs ソース コード内の src フォルダー全体を「SPI—FatFs File System\USER\」フォルダーにコピーし、名前を「FATFS」に変更します。フォルダー名に決まった名前はなく、単に書きやすいように付けられています。
2. プロジェクト ファイルを開き、FatFs コンポーネント ファイルをプロジェクトに追加します。ff.c、diskio.c、cc936.c の 3 つのファイルを追加する必要があります。 3.
FATFS フォルダーをプロジェクトのインクルード オプションに追加します。プロジェクト オプション ダイアログ ボックスを開き、[C/C++] オプションの下の [パスを含める] 項目を選択し、ポップアップ パス設定ダイアログ ボックスで [FATFS] フォルダーを追加することを選択します。 4. diskio.c ファイルを変更し、 ffconf.h ファイル、diskio
。c ファイルの内容は、基礎となるデバイスの入出力インターフェイス関数ファイルです。ハードウェア設計ドライバーが異なれば、必要なファイルも異なります。FatFs はデフォルトで日本語を使用します。必要な場合は、簡体字中国語をサポートするには、FatFs の構成を変更する必要があります。つまり、ffconf.h ファイルを変更する必要があります
。
FatFs の基礎となるデバイス ドライバー関数
ファイル システムは中間のファジー層を実装し、ユーザーが使用できる上位層の機能を提供します。ユーザーは基礎となるインターフェイスを実装する必要があります。diskio.c ファイルの内容は、基礎となるインターフェイスに関連しています。
移行にはユーザー サポート機能が必要です。disk_status 一般只有前六个需要使用
、disk_initialize、disk_read の設定が必要です。
ファイルの作成と変更には、disk_write、get_fattime、disk_ioctl (CTRL_SYNC) が必要です。
簡体字中国語の長いファイル名をサポートするには、関数 ff_convert と ff_wtoupper を追加する必要があります。実際、これら 2 つの関数は cc936.c ファイルに実装されています。必要なのは、cc936.c ファイルをプロジェクト。
FATFS を移行する主な手順
1. データ型を設定します。 integer.h でデータ型を定義します。ここでは、使用しているコンパイラのデータ型を理解し、コンパイラに応じてデータ型を定義する必要があります。
2. 設定: ニーズに合わせて、ffconf.h を通じて FATFS の関連機能を設定します。
3. 関数の作成: diskio.c を開き、基礎となるドライバーを作成します。5 つのインターフェイス関数を作成する必要があります。
データ型を定義するために integer.h を構成します (通常は必要ありません)
MDK5.34 コンパイラを使用しており、データ型は integer.h で定義されているものと一致しているため、このステップでは変更を加える必要はありません。
ffconf.h 選択モードを構成する
ffconf.h 内の関連する設定に関しては、必要な値に設定を変更するだけで、他の設定にはデフォルトの設定を使用します。
1 #define _USE_MKFS 1 //格式化功能选择,为使用 FatFs 格式化功能,需要把它设置为 1。
2 #define _CODE_PAGE 936 //语言功能选择,并要求把相关语言文件添加到工程宏。为支持简体中文文件名需要使用“936” 指的是把 cc936.c 文件添加到工程中
3 #define _USE_LFN 2 //长文件名支持,默认不支持长文件名,这里配置为 2,支持长文件名,并指定使用栈空间为缓冲区。
4 #define _VOLUMES 2 //指定物理设备数量
5 #define _MIN_SS 512 //指定扇区大小的最小值和最大值。SD 卡扇区大小一般都为 512字节,SPI Flash芯片扇区大小一般设置为 4096字节
6 #define _MAX_SS 4096 //指定扇区大小的最小值和最大值
各デバイスの物理番号を定義する
#define ATA 0 // 预留 SD 卡使用
#define SPI_FLASH 1 // 外部 SPI Flash
5つの機能を実装
デバイス状態取得(disk_status)、デバイス初期化(disk_initialize)、セクタ読み出し(disk_read)、セクタ書き込み(disk_write)、その他の制御(disk_ioctl)。
ディスク初期化
関数名 | ディスク初期化 |
---|---|
関数プロトタイプ | DSTATUS ディスク初期化(BYTE ドライブ) |
機能説明 | ディスクドライブの初期化 |
関数パラメータ | ドライブ: 初期化する論理ドライブ番号、つまりドライブ文字を 0 ~ 9 の範囲で指定します。 |
戻り値 | この関数は結果としてディスクのステータスを返します。ディスクのステータスの詳細については、disk_status 関数を参照してください。 |
ファイル | ff.c |
例 | disc_initialize(0); /* ドライブ 0 を初期化します */ |
予防 | disk_initialize 関数は、論理ドライブを初期化して読み取り/書き込みの準備をします。関数が成功すると、戻り値の STA_NOINIT フラグがクリアされます。アプリケーションはこの関数を呼び出さないでください。呼び出さないと、ボリューム上の FAT 構造が破損する可能性があります。ファイル システムを再初期化する必要がある場合は、f_mount 関数を使用できます。FatFs モジュールでのボリューム登録処理中にこの関数を呼び出すと、デバイスの変更を制御できます。この関数は、FatFs がボリュームにマウントされるときに呼び出されるため、アプリケーションはこの関数を使用しないでください。 FatFs がアクティブな場合。 |
DSTATUS disk_status (BYTE pdrv /* 物理编号 */)
{
DSTATUS status = STA_NOINIT;
switch (pdrv) {
case ATA: /* SD CARD 预留,也可以*/
break;
case SPI_FLASH: /* SPI Flash 状态检测:读取 SPI Flash 设备 ID */
if (sFLASH_ID == SPI_FLASH_ReadID()) {
/* 设备 ID 读取结果正确 */
status &= ~STA_NOINIT;
} else {
/* 设备 ID 读取结果错误 */
status = STA_NOINIT;
}
break;
default:
status = STA_NOINIT;
}
return status;
}
SPI_FLASH_ReadID 関数は、デバイスの準備ができているかどうかを検出するためにユーザー自身によって実装されることに注意してください。
ディスクステータス
関数名 | ディスクステータス |
---|---|
関数プロトタイプ | DRESULT ディスクステータス (バイトドライブ) |
機能説明 | ディスクドライブの現在のステータスを返します。 |
関数パラメータ | ドライブ: 確認する論理ドライブ番号、つまりドライブ文字を 0 ~ 9 の範囲で指定します。 |
戻り値 | ディスク ステータスは次のフラグの組み合わせを返します。FatFs は STA_NOINIT と STA_PROTECTEDSTA_NOINIT のみを使用します。ディスク ドライバーが初期化されていないことを示します。このフラグがセットまたはクリアされる理由のリストは次のとおりです。セット: システム リセット、ディスクの取り外し、およびディスク初期化機能が失敗しました。クリア: ディスクの初期化機能が成功したことを示します。STA_NODISK : ドライブにデバイスが存在しないことを示します。ディスク ドライブの取り付け後は常に 0 になります。STA_PROTECTED : デバイスが書き込み保護されていることを示します。書き込み保護をサポートしていないデバイスは常に書き込み保護されています。 0. STA_NODISK が設定されている場合は不正です。 |
ファイル | ff.c |
例 | disc_status(0); /* ドライブ 0 のステータスを取得します*/ |
DSTATUS disk_initialize (BYTE pdrv /* 物理编号 */)
{
uint16_t i;
DSTATUS status = STA_NOINIT;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH: /* SPI Flash */
SPI_FLASH_Init(); /* 初始化 SPI Flash */
i=500;/* 延时一小段时间 */
while (--i);
SPI_Flash_WAKEUP();/* 唤醒 SPI Flash */
status = disk_status(SPI_FLASH);/* 获取 SPI Flash 芯片状态 */
break;
default:
status = STA_NOINIT;
}
return status;
}
SPI_FLASH_Init();SPI_Flash_WAKEUP(); はユーザー自身によって実装される基礎となる関数であり、フラッシュの対応する要件に従って記述する必要があることに注意
してください (通常、データ バイトは特定のルールに従って送信されるため、一般的なプログラミングはシーケンスは、シングルバイト spi トランシーバーを実装する行、次に必要に応じてマルチバイト関数を記述し、ファイル システムに埋め込むことです)
ディスク読み取り
関数名 | ディスク読み取り |
---|---|
関数プロトタイプ | DRESULT ディスク読み取り (BYTE ドライブ、BYTE* バッファ、DWORD セクター番号、BYTE セクター数) |
機能説明 | ディスクドライブからセクターを読み取ります |
関数パラメータ | Drive: 論理ドライブ番号、つまりドライブ文字を指定します。0 ~ 9 の値を取る必要があります。 Buffer: 読み取ったデータのバイト配列を格納するポインタを指します。数値のサイズである必要があります。セクタ統計のセクタ サイズが必要です (注: FaFts で指定されるメモリ アドレスは必ずしもワード アラインメントされているわけではありません。ハードウェアがアラインされていないデータ送信をサポートしていない場合は、関数内で処理する必要があります) SectorNumber: 開始セクタの論理ブロック (LBA) 上のアドレス SectorCount を指定します。 : 読み取るセクタ数を 1 ~ 128 の範囲で指定します。 |
戻り値 | RES_OK(0): 関数は成功しました。 RES_ERROR: 読み取り操作中にエラーが発生し、回復できません。 RES_PARERR: 不正なパラメータです。 RES_NOTRDY: ディスクドライブが初期化されていません。 |
ファイル | ff.c |
DRESULT disk_read (
BYTE pdrv, /* 设备物理编号(0..) */
BYTE *buff, /* 数据缓存区 */
DWORD sector, /* 扇区首地址 */
UINT count /* 扇区个数(1..128) */
)
{
DRESULT status = RES_PARERR;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
sector+=512;/* 扇区偏移 2MB,外部 Flash 文件系统空间放在 SPI Flash 后面 6MB 空间 */
SPI_FLASH_BufferRead(buff, sector <<12, count<<12);
status = RES_OK;
break;
default:
status = RES_PARERR;
}
return status;
}
注
参数
:pdrv
デバイスの物理番号であり、ユーザー定義のbuff
:BYTE 型ポインタ変数であり、buff は読み出したデータを格納するために使用される記憶領域の先頭アドレスを指し、sector
DWORD 型変数であり、その先頭アドレスを指定します。データを読み取るセクター。count
セクタ数を指定するUINT型変数です。
数据类型
: BYTE 型は実際には unsigned char 型、DWORD 型は実際には unsigned long 型、UINT 型は実際には unsigned int 型であり、これらの型は integer.h ファイルで定義されています。
偏移
: ボードで使用されている SPI フラッシュ チップ モデルは W25Q64FV、各セクター サイズは 4096 バイト (4KB)、合計 8M バイトのスペースがあります。ファイル システムは、フラッシュの最初のアドレスから保存する必要があります则不需要偏移
。最後の 6MB スペースのみが FatFs に割り当てられます。つまり、FatFs は 2MB スペースから始まります。この効果を達成するには、すべての読み取りおよび書き込みアドレスが 512 セクター スペースによってオフセットされる必要があります。フラッシュ読み取り用の基礎となるプログラムは、指定されたアドレスでの読み取りを実現します
SPI_FLASH_BufferRead()
。 . 指定した長さのデータを取得する (例)
/**
* @brief 读取 FLASH 数据
* @param pBuffer,存储读出数据的指针
* @param ReadAddr,读取地址
* @param NumByteToRead,读取数据长度
* @retval 无
*/
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
SPI_FLASH_CS_LOW(); /* 选择 FLASH: CS 低电平 */
SPI_FLASH_SendByte(W25X_ReadData); /* 发送 读 指令 */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16) /* 发送 读 地址高位 */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8); /* 发送 读 地址中位 */
SPI_FLASH_SendByte(ReadAddr & 0xFF); /* 发送 读 地址低位 */
while (NumByteToRead--)/* 读取数据 */
{
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);/* 读取一个字节*/
pBuffer++;/* 指向下一个字节缓冲区 */
}
SPI_FLASH_CS_HIGH();/* 停止信号 FLASH: CS 高电平 */
}
ディスク書き込み
関数名 | ディスク書き込み |
---|---|
関数プロトタイプ | DRESULT disk_write (BYTE Drive, const BYTE* Buffer, DWORD SectorNumber, BYTE SectorCount) |
功能描述 | 向磁盘写入一个或多个扇区 |
函数参数 | Drive:指定逻辑驱动器号,即盘符,应当取值 0~9Buffer:指向要写入字节数组的指针(注:FaFts 指定的内存地址并不总是字对齐的,如果硬件不支持不对齐的数据传输,函数里需要进行处理)SectorNumber:指定起始扇区的逻辑块(LBA)上的地址SectorCount:指定要写入的扇区数,取值 1~128 |
返回值 | RES_OK(0):函数成功RES_ERROR:写操作期间产生了任何错误且不能恢复它RES_WRPER:媒体被写保护RES_PARERR:非法参数RES_NOTRDY:磁盘驱动器没有初始化 |
所在文件 | ff.c |
注意事项 | 只读配置中不需要此函数 |
DRESULT disk_write (
BYTE pdrv, /* 设备物理编号(0..) */
const BYTE *buff, /* 欲写入数据的缓存区 */
DWORD sector, /* 扇区首地址 */
UINT count /* 扇区个数(1..128) */
)
{
uint32_t write_addr;
DRESULT status = RES_PARERR;
if (!count) {
return RES_PARERR; /* Check parameter */
}
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
/* 扇区偏移 2MB,外部 Flash 文件系统空间放在 SPI Flash 后面 6MB 空间 */
sector+=512;
write_addr = sector<<12;
SPI_FLASH_SectorErase(write_addr);//对于Flash 先擦除再写
SPI_FLASH_BufferWrite((u8 *)buff,write_addr,count<<12);//写
status = RES_OK;
break;
default:
status = RES_PARERR;
}
return status;
}
SPI_FLASH_SectorErase
SPI_FLASH_BufferWrite
用户实现
disk_ioctl
函数名称 | disk_ioctl |
---|---|
函数原型 | DRESULT disk_ioctl (BYTE Drive, BYTE Command, void* Buffer) |
功能描述 | 控制设备指定特性和除了读/写外的杂项功能 |
函数参数 | Drive:指定逻辑驱动器号,即盘符,应当取值 0~9Command:指定命令代码Buffer:指向参数缓冲区的指针,取决于命令代码,不使用时,指定一个 NULL指针 |
返回值 | RES_OK(0):函数成功RES_ERROR:写操作期间产生了任何错误且不能恢复它RES_PARERR:非法参数RES_NOTRDY:磁盘驱动器没有初始化 |
所在文件 | ff.c |
注意事项 | CTRL_SYNC: ディスク ドライブが書き込みプロセスを完了していることを確認します。ディスク I/O にライトバック キャッシュがある場合は、元のセクターをすぐにリフレッシュします。このコマンドは読み取り専用構成には適用されません。GET_SECTOR_SIZE: セクター サイズを返します。ディスク、f_mkfs( ) にのみ使用されます。 GET_SECTOR_COUNT: 使用可能なセクターの数を返します。_MAX_SS ≥ 1024 の場合に使用可能です。 GET_BLOCK_SIZE: 消去ブロック サイズを取得します。f_mkfs() にのみ使用されます。 CTRL_ERASE_SECTOR: セクターを強制的に消去します。_USE_ERASE > 0 の場合に使用可能です。 |
DRESULT disk_ioctl (
BYTE pdrv, /* 物理编号 */
BYTE cmd, /* 控制指令 */
void *buff /* 写入或者读取数据地址指针 */
)
{
DRESULT status = RES_PARERR;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
switch (cmd) {
/* 扇区数量:1536*4096/1024/1024=6(MB) */
case GET_SECTOR_COUNT:
*(DWORD * )buff = 1536;
break;
/* 扇区大小 */
case GET_SECTOR_SIZE :
*(WORD * )buff = 4096;
break;
/* 同时擦除扇区个数 */
case GET_BLOCK_SIZE :
*(DWORD * )buff = 1;
break;
}
status = RES_OK;
break;
default:
status = RES_PARERR;
}
return status;
}
参数
:pdrv
デバイスの物理番号であり、cmd
同期信号の送信、セクタ数の取得、セクタサイズの取得、消去ブロック数の取得などの命令を含む制御命令です。データポインタに対応しますbuff
。指示に。
cmd
:SPI Flash チップの場合、FatFs フォーマット機能をサポートするには、セクター番号取得 (GET_SECTOR_COUNT) コマンドを使用して、消去ブロック番号 (GET_BLOCK_SIZE) を取得する必要があります。さらに、SD カードのセクタ サイズは 512 バイトで、SPI フラッシュ チップは通常セクタ サイズを 4096 バイトに設定するため、セクタ サイズの取得 (GET_SECTOR_SIZE) コマンドを使用する必要があります。