## FTFS
文件系统是操作系统用于明确存储设备或分区上的文件的方法和数据结构（即在存储设备上组织文件的方法）。
操作系统中负责管理和存储文件信息的软件机构称为文件管理系统，简称文件系统；不带文件系统的SD卡仅能实现简单的读写扇区操作，要真正应用SD卡必须要使用文件系统
 

***写注意事项***
可以调用不检查写
如果不确认是否写过，需要读出来判断
续预先封装以上函数

***注意堆栈大小***
***注意修改SD 4B-1B  目的初始化****

### FATFS文件系统
操作系统DBR
保留扇区
FAT1
FAT2
数据区--根目录
剩余扇区

保留扇区为31

簇是文件最小存储单元
< 8G, 簇空间  4KB
 8-16G, 簇空间  8KB
16-32G, 簇空间  16KB
>=32G, 簇空间  32KB

例如：创建一个50字节的test.txt文件，文件大小是50字节，但是占用磁盘空间为4096字节（一个簇）
空间浪费严重

### FATFS 模块层次
应用层  -- 应用接口函数（如f_open, f_read, f_write和f_close等）
中间层FATFS模块：实现了FAT文件读写协议；它提供了ff.c和ff.h文件，一般情况下不用修改
最底层是FATFS模块的底层接口：包括存储媒介读写接口和供给文件创建修改时间的实时时钟，需要在移植时编写对应的代码

FATFS源码相关文件介绍如下表示；移植FATFS模块时，一般只需要修改2个文件（即ffconf.h和diskio.c）
与平台无关
ffconf.h  FATFS模块配置文件
ff.h  FATFS和应用模块公用的包含文件
ff.c  FATFS模块
diskio.h FATFS和disk I/O模块公用的包含文件
interger.h  数据类型定义
option  可选的外部功能（比如支持中文）

与平台相关
diskio.c  FATFS和disk I/O模块接口层文件

### 移植
数据类型：在integer.h里面去定义好数据的类型
配置：通过ffconf.h配置FATFS相关功能
函数编写：在diskio.c文件中进行底层驱动编写（6个接口函数disk_initialize、disk_status、disk_read、disk_write、disk_ioctl、get_fattime）


程序移植问题
FatFs 既不关心使用何种存储设备，也不关心如何实现。
唯一的要求是：它是一个以固定大小的块读取/写入的块设备，可以通过定义的磁盘I/O功能访问。

ffconf.h 宏修改定义
diskio.c 需要自己写 ，需要改的函数如下：
    disk_status	设备状态获取
    disk_initialize	设备初始化
    disk_read	扇区读取
    disk_write	扇区写入
    get_fattime	获取当前时间
    disk_ioctl（CTRL_SYNC）	控制设备的其他杂项

***以上数据调用 SDIO WQ25 进行初始化  状态 写入等***

### 操作CubeMX
MiddleWare  FATFS  选项

如果配置好 SD  可以选 SD卡
如果Flash  就要选用户定义了

#### SD卡
使用SDIO总线SDIO卡时，需要用户自定义

设置参数，对应ffconf.h的设置

#### Flash
CODE_PAGE U.S.(OEM)  使用英文
USE_LFN   Disable   不使用长文件名
MAX_SS (Maximum Sector Size)   Flash最小擦除单位
MIN_SS (Maximum Sector Size)


### 原始文件


#### 目录比较
系统多出目录   
Middlewares\Third_Party\FatFs
FatFs\APP
FatFs\Target

MakeFile 文件增加的编译文件
FATFS/Target/user_diskio.c \
FATFS/App/fatfs.c \
Middlewares/Third_Party/FatFs/src/diskio.c \
Middlewares/Third_Party/FatFs/src/ff.c \
Middlewares/Third_Party/FatFs/src/ff_gen_drv.c \
Middlewares/Third_Party/FatFs/src/option/syscall.c

文件结构
FATFS/App/fatfs.c  负责挂在链接设备驱动, 进行FAFS初始化 供main调用
    -> Middlewares/Third_Party/FatFs/src/ff_gen_drv.c  -- 定义设备驱动结构体
    -> Middlewares/Third_Party/FatFs/src/diskio.c  -- 提供函数指针设备初始化、读写、IO控制函数接口
    -> FATFS/Target/user_diskio.c   实例化设备结构体，提供存储器底层初始化、读写函数
Middlewares/Third_Party/FatFs/src/ff.c  提供读写挂载开关接口

Target目录      sd_disk.h, bsp_driver_sd.h
bsp_driver_sd   接管了原先SD的初始化

### 重新初始化
因为关联SD  FTFS, SD没有真正初始化
bsp_driver_sd 重新初始化带文件系统的
  BSP_SD_Init();   --系统可以正常跑了

  系统运行,需要多加载几次,以免文件系统加载不成功

### diskio.c
参考正点原子 或   野火
```C

#define SD_CARD 0 //SD 卡,卷标为 0
#define EX_FLASH 1 //外部 flash,卷标为 1
#define FLASH_SECTOR_SIZE 512 
//对于 W25Q128
//前 12M 字节给 fatfs 用,12M 字节后,用于存放字库,字库占用 3.09M. 剩余部分,
//给客户自己用 
u16 FLASH_SECTOR_COUNT=2048*12; //W25Q1218,前 12M 字节给 FATFS 占用
#define FLASH_BLOCK_SIZE 8 //每个 BLOCK 有 8 个扇区
//初始化磁盘
```

选择性初始化   SD_Init()   W25QXX_Init()
```C
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber (0..) */
)
{
u8 res=0; 
switch(pdrv)
{
case SD_CARD://SD 卡
res=SD_Init();//SD 卡初始化
 break;
case EX_FLASH://外部 flash
W25QXX_Init();
FLASH_SECTOR_COUNT=2048*12;//W25Q1218,前 12M 字节给 FATFS 占用
break;
default:
res=1; 
}
if(res)return STA_NOINIT;
else return 0; //初始化成功
} 


```

### CubeMX 产生文件目录


###  main调用方法
 char SDPath[4];             /* SD逻辑驱动器路径 */
 FATFS fs;                         /* FatFs文件系统对象 */
 FIL fnew;                         /* 文件对象 */
 FRESULT res_sd;                /* 文件操作结果 */
 UINT fnum;                    /* 文件成功读写数量 */
 BYTE ReadBuffer[1024]= {0};       /* 读缓冲区 */
 BYTE WriteBuffer[] =              /* 写缓冲区*/

     //在外部SD卡挂载文件系统，文件系统挂载时会对SD卡初始化
     res_sd = f_mount(&fs,"0:",1);
      if (res_sd == FR_NO_FILESYSTEM) {
         printf("》SD卡还没有文件系统，即将进行格式化...\r\n");
      }else if (res_sd!=FR_OK) {
         printf("！！SD卡挂载文件系统失败。(%d)\r\n",res_sd);
         printf("！！可能原因：SD卡初始化不成功。\r\n");
         while (1);
     } else {
         printf("》文件系统挂载成功，可以进行读写测试\r\n");
     }
          res_sd = f_open(&fnew, "0:FatFs读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
 



 static void printf_fatfs_error(FRESULT fresult)
{
  switch(fresult)
  {
    case FR_OK:                   //(0)
      printf("》操作成功。\r\n");
    break;
    case FR_DISK_ERR:             //(1)
      printf("！！硬件输入输出驱动出错。\r\n");
    break;
    case FR_INT_ERR:              //(2)
      printf("！！断言错误。\r\n");
    break;
    case FR_NOT_READY:            //(3)
      printf("！！物理设备无法工作。\r\n");
    break;
    case FR_NO_FILE:              //(4)
      printf("！！无法找到文件。\r\n");
    break;
    case FR_NO_PATH:              //(5)
      printf("！！无法找到路径。\r\n");
    break;
    case FR_INVALID_NAME:         //(6)
      printf("！！无效的路径名。\r\n");
    break;
    case FR_DENIED:               //(7)
    case FR_EXIST:                //(8)
      printf("！！拒绝访问。\r\n");
    break;
    case FR_INVALID_OBJECT:       //(9)
      printf("！！无效的文件或路径。\r\n");
    break;
    case FR_WRITE_PROTECTED:      //(10)
      printf("！！逻辑设备写保护。\r\n");
    break;
    case FR_INVALID_DRIVE:        //(11)
      printf("！！无效的逻辑设备。\r\n");
    break;
    case FR_NOT_ENABLED:          //(12)
      printf("！！无效的工作区。\r\n");
    break;
    case FR_NO_FILESYSTEM:        //(13)
      printf("！！无效的文件系统。\r\n");
    break;
    case FR_MKFS_ABORTED:         //(14)
      printf("！！因函数参数问题导致f_mkfs函数操作失败。\r\n");
    break;
    case FR_TIMEOUT:              //(15)
      printf("！！操作超时。\r\n");
    break;
    case FR_LOCKED:               //(16)
      printf("！！文件被保护。\r\n");
    break;
    case FR_NOT_ENOUGH_CORE:      //(17)
      printf("！！长文件名支持获取堆空间失败。\r\n");
    break;
    case FR_TOO_MANY_OPEN_FILES:  //(18)
      printf("！！打开太多文件。\r\n");
    break;
    case FR_INVALID_PARAMETER:    // (19)
      printf("！！参数无效。\r\n");
    break;
  }
}