代码改变世界

FATFS 初学之 f_mkfs

2014-08-14 10:40  Danhuise  阅读(7892)  评论(0编辑  收藏  举报
  1 /*-----------------------------------------------------------------------*/
  2 /* Create File System on the Drive                                       */
  3 /*-----------------------------------------------------------------------*/
  4 
  5 FRESULT f_mkfs (
  6     BYTE drv,        /* Logical drive number */
  7     BYTE sfd,        /* Partitioning rule 0:FDISK, 1:SFD */
  8     UINT au            /* Allocation unit size [bytes] */
  9 )
 10 {
 11     static const WORD vst[] = { 1024,   512,  256,  128,   64,    32,   16,    8,    4,    2,   0};
 12     static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
 13     BYTE fmt, md, sys, *tbl, pdrv, part;
 14     DWORD n_clst, vs, n, wsect;
 15     UINT i;
 16     DWORD b_vol, b_fat, b_dir, b_data;    /* LBA */
 17     DWORD n_vol, n_rsv, n_fat, n_dir;    /* Size */
 18     FATFS *fs;
 19     DSTATUS stat;
 20 
 21 
 22     /* Check mounted drive and clear work area */
 23     if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
 24     if (sfd > 1) return FR_INVALID_PARAMETER;
 25     if (au & (au - 1)) return FR_INVALID_PARAMETER;
 26     fs = FatFs[drv];
 27     if (!fs) return FR_NOT_ENABLED;
 28     fs->fs_type = 0;
 29     pdrv = LD2PD(drv);    /* Physical drive */
 30     part = LD2PT(drv);    /* Partition (0:auto detect, 1-4:get from partition table)*/
 31 
 32     /* Get disk statics */
 33     stat = disk_initialize(pdrv);
 34     if (stat & STA_NOINIT) return FR_NOT_READY;
 35     if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
 36 #if _MAX_SS != 512                    /* Get disk sector size */
 37     if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
 38         return FR_DISK_ERR;
 39 #endif
 40     if (_MULTI_PARTITION && part) {
 41         /* Get partition information from partition table in the MBR */
 42         if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
 43         if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
 44         tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
 45         if (!tbl[4]) return FR_MKFS_ABORTED;    /* No partition? */
 46         b_vol = LD_DWORD(tbl+8);    /* Volume start sector */
 47         n_vol = LD_DWORD(tbl+12);    /* Volume size */
 48     } else {
 49         /* Create a partition in this function */
 50         if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
 51             return FR_DISK_ERR;
 52         b_vol = (sfd) ? 0 : 63;        /* Volume start sector */
 53         n_vol -= b_vol;                /* Volume size */
 54     }
 55 
 56     if (!au) {                /* AU auto selection */
 57         vs = n_vol / (2000 / (SS(fs) / 512));
 58         for (i = 0; vs < vst[i]; i++) ;
 59         au = cst[i];
 60     }
 61     au /= SS(fs);        /* Number of sectors per cluster */
 62     if (au == 0) au = 1;
 63     if (au > 128) au = 128;
 64 
 65     /* Pre-compute number of clusters and FAT syb-type */
 66     n_clst = n_vol / au;
 67     fmt = FS_FAT12;
 68     if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
 69     if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
 70 
 71     /* Determine offset and size of FAT structure */
 72     if (fmt == FS_FAT32) {
 73         n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
 74         n_rsv = 32;
 75         n_dir = 0;
 76     } else {
 77         n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
 78         n_fat = (n_fat + SS(fs) - 1) / SS(fs);
 79         n_rsv = 1;
 80         n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
 81     }
 82     b_fat = b_vol + n_rsv;                /* FAT area start sector */
 83     b_dir = b_fat + n_fat * N_FATS;        /* Directory area start sector */
 84     b_data = b_dir + n_dir;                /* Data area start sector */
 85     if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED;    /* Too small volume */
 86 
 87     /* Align data start sector to erase block boundary (for flash memory media) */
 88     if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
 89     n = (b_data + n - 1) & ~(n - 1);    /* Next nearest erase block from current data start */
 90     n = (n - b_data) / N_FATS;
 91     if (fmt == FS_FAT32) {        /* FAT32: Move FAT offset */
 92         n_rsv += n;
 93         b_fat += n;
 94     } else {                    /* FAT12/16: Expand FAT size */
 95         n_fat += n;
 96     }
 97 
 98     /* Determine number of clusters and final check of validity of the FAT sub-type */
 99     n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
100     if (   (fmt == FS_FAT16 && n_clst < MIN_FAT16)
101         || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
102         return FR_MKFS_ABORTED;
103 
104     switch (fmt) {    /* Determine system ID for partition table */
105     case FS_FAT12:    sys = 0x01; break;
106     case FS_FAT16:    sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
107     default:         sys = 0x0C;
108     }
109 
110     if (_MULTI_PARTITION && part) {
111         /* Update system ID in the partition table */
112         tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
113         tbl[4] = sys;
114         if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
115         md = 0xF8;
116     } else {
117         if (sfd) {    /* No patition table (SFD) */
118             md = 0xF0;
119         } else {    /* Create partition table (FDISK) */
120             mem_set(fs->win, 0, SS(fs));
121             tbl = fs->win+MBR_Table;    /* Create partiton table for single partition in the drive */
122             tbl[1] = 1;                        /* Partition start head */
123             tbl[2] = 1;                        /* Partition start sector */
124             tbl[3] = 0;                        /* Partition start cylinder */
125             tbl[4] = sys;                    /* System type */
126             tbl[5] = 254;                    /* Partition end head */
127             n = (b_vol + n_vol) / 63 / 255;
128             tbl[6] = (BYTE)((n >> 2) | 63);    /* Partiiton end sector */
129             tbl[7] = (BYTE)n;                /* End cylinder */
130             ST_DWORD(tbl+8, 63);            /* Partition start in LBA */
131             ST_DWORD(tbl+12, n_vol);        /* Partition size in LBA */
132             ST_WORD(fs->win+BS_55AA, 0xAA55);    /* MBR signature */
133             if (disk_write(pdrv, fs->win, 0, 1) != RES_OK)    /* Write it to the MBR sector */
134                 return FR_DISK_ERR;
135             md = 0xF8;
136         }
137     }
138 
139     /* Create BPB in the VBR */
140     tbl = fs->win;                            /* Clear sector */
141     mem_set(tbl, 0, SS(fs));
142     mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
143     i = SS(fs);                                /* Sector size */
144     ST_WORD(tbl+BPB_BytsPerSec, i);
145     tbl[BPB_SecPerClus] = (BYTE)au;            /* Sectors per cluster */
146     ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);        /* Reserved sectors */
147     tbl[BPB_NumFATs] = N_FATS;                /* Number of FATs */
148     i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR;    /* Number of rootdir entries */
149     ST_WORD(tbl+BPB_RootEntCnt, i);
150     if (n_vol < 0x10000) {                    /* Number of total sectors */
151         ST_WORD(tbl+BPB_TotSec16, n_vol);
152     } else {
153         ST_DWORD(tbl+BPB_TotSec32, n_vol);
154     }
155     tbl[BPB_Media] = md;                    /* Media descriptor */
156     ST_WORD(tbl+BPB_SecPerTrk, 63);            /* Number of sectors per track */
157     ST_WORD(tbl+BPB_NumHeads, 255);            /* Number of heads */
158     ST_DWORD(tbl+BPB_HiddSec, b_vol);        /* Hidden sectors */
159     n = get_fattime();                        /* Use current time as VSN */
160     if (fmt == FS_FAT32) {
161         ST_DWORD(tbl+BS_VolID32, n);        /* VSN */
162         ST_DWORD(tbl+BPB_FATSz32, n_fat);    /* Number of sectors per FAT */
163         ST_DWORD(tbl+BPB_RootClus, 2);        /* Root directory start cluster (2) */
164         ST_WORD(tbl+BPB_FSInfo, 1);            /* FSInfo record offset (VBR+1) */
165         ST_WORD(tbl+BPB_BkBootSec, 6);        /* Backup boot record offset (VBR+6) */
166         tbl[BS_DrvNum32] = 0x80;            /* Drive number */
167         tbl[BS_BootSig32] = 0x29;            /* Extended boot signature */
168         mem_cpy(tbl+BS_VolLab32, "NO NAME    " "FAT32   ", 19);    /* Volume label, FAT signature */
169     } else {
170         ST_DWORD(tbl+BS_VolID, n);            /* VSN */
171         ST_WORD(tbl+BPB_FATSz16, n_fat);    /* Number of sectors per FAT */
172         tbl[BS_DrvNum] = 0x80;                /* Drive number */
173         tbl[BS_BootSig] = 0x29;                /* Extended boot signature */
174         mem_cpy(tbl+BS_VolLab, "NO NAME    " "FAT     ", 19);    /* Volume label, FAT signature */
175     }
176     ST_WORD(tbl+BS_55AA, 0xAA55);            /* Signature (Offset is fixed here regardless of sector size) */
177     if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK)    /* Write it to the VBR sector */
178         return FR_DISK_ERR;
179     if (fmt == FS_FAT32)                            /* Write backup VBR if needed (VBR+6) */
180         disk_write(pdrv, tbl, b_vol + 6, 1);
181 
182     /* Initialize FAT area */
183     wsect = b_fat;
184     for (i = 0; i < N_FATS; i++) {        /* Initialize each FAT copy */
185         mem_set(tbl, 0, SS(fs));            /* 1st sector of the FAT  */
186         n = md;                                /* Media descriptor byte */
187         if (fmt != FS_FAT32) {
188             n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
189             ST_DWORD(tbl+0, n);                /* Reserve cluster #0-1 (FAT12/16) */
190         } else {
191             n |= 0xFFFFFF00;
192             ST_DWORD(tbl+0, n);                /* Reserve cluster #0-1 (FAT32) */
193             ST_DWORD(tbl+4, 0xFFFFFFFF);
194             ST_DWORD(tbl+8, 0x0FFFFFFF);    /* Reserve cluster #2 for root dir */
195         }
196         if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
197             return FR_DISK_ERR;
198         mem_set(tbl, 0, SS(fs));            /* Fill following FAT entries with zero */
199         for (n = 1; n < n_fat; n++) {        /* This loop may take a time on FAT32 volume due to many single sector writes */
200             if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
201                 return FR_DISK_ERR;
202         }
203     }
204 
205     /* Initialize root directory */
206     i = (fmt == FS_FAT32) ? au : n_dir;
207     do {
208         if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
209             return FR_DISK_ERR;
210     } while (--i);
211 
212 #if _USE_ERASE    /* Erase data area if needed */
213     {
214         DWORD eb[2];
215 
216         eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
217         disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
218     }
219 #endif
220 
221     /* Create FSInfo if needed */
222     if (fmt == FS_FAT32) {
223         ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
224         ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
225         ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);    /* Number of free clusters */
226         ST_DWORD(tbl+FSI_Nxt_Free, 2);                /* Last allocated cluster# */
227         ST_WORD(tbl+BS_55AA, 0xAA55);
228         disk_write(pdrv, tbl, b_vol + 1, 1);    /* Write original (VBR+1) */
229         disk_write(pdrv, tbl, b_vol + 7, 1);    /* Write backup (VBR+7) */
230     }
231 
232     return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
233 }
View Code

函数功能:在驱动器上创建一个文件系统(格式化 SD卡)

描述:

f_mkfs函数当_FS_READOLNY == 0并且_USE_MKFS == 1时可用。
f_mkfs函数在驱动器中创建一个FAT文件系统。对于可移动媒介,有两种分区规则:FDISK和SFD,通过参数PartitioningRule选择。FDISK格式在大多数情况下被推荐使用。该函数当前不支持多分区,因此,物理驱动器上已存在的分区将被删除,并且重新创建一个占据全部磁盘空间的新分区。
根据Microsoft发布的FAT规范,FAT分类:FAT12/FAT16/FAT32,由驱动器上的簇数决定。因此,选择哪种FAT分类,取决于卷大小和指定的簇大小。簇大小影响文件系统的性能,并且大簇会提高性能。

 

例:

 1   FATFS fs;
 2   FIL file;
 3   FRESULT res;
 4   char array[512]={0}, *parray = array;
 5   
 6   res = f_mount(0, &fs);
 7   res = f_mkfs(0 , 0, _MAX_SS);
 8   res = f_open(&file, "data.txt", FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
 9   f_printf(&file, "%s\n", "Success");        /* "Success" */
10   parray = f_gets(parray , 8, &file);
11   LCMTextOutExt(  0, 0, parray );
12   f_close(&file);
13   f_mount(0, NULL);
View Code