SD卡的FatFs文件系统已经满大街了,可以参考的资源也有很多。
移植FatFs文件系统主要内容在于“diskio.c”,“ffconf.h”,一个是用于定义底层接口,一个用于定义FatFs配置,百度或者google都能找得到说明,就不详细说明了。
碰到的主要问题就是f_mkfs()函数过后,Fat系统没有刷新成功,于是f_open()返回(FR_NO_FLESYSTEM),文件系统没有刷新成功。
开始查ff.c文件 ,进入f_mkfs:
FRESULT f_mkfs (
BYTE drv, /* Logical drive number */
BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
UINT au /* Allocation unit size [bytes] */
)
{
static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
BYTE fmt, md, sys, *tbl, pdrv, part;
DWORD n_clst, vs, n, wsect;
UINT i;
DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
FATFS *fs;
DSTATUS stat;
/* Check mounted drive and clear work area */
if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
if (sfd > 1) return FR_INVALID_PARAMETER;
if (au & (au - 1)) return FR_INVALID_PARAMETER;
fs = FatFs[drv];
if (!fs) return FR_NOT_ENABLED;
fs->fs_type = 0;
pdrv = LD2PD(drv); /* Physical drive */
part = LD2PT(drv); /* Partition (0:auto detect, 1-4:get from partition table)*/
/* Get disk statics */
stat = disk_initialize(pdrv);
if (stat & STA_NOINIT) return FR_NOT_READY;
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
#if _MAX_SS != 512 /* Get disk sector size */
if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
return FR_DISK_ERR;
#endif
if (_MULTI_PARTITION && part) {
/* Get partition information from partition table in the MBR */
if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */
b_vol = LD_DWORD(tbl+8); /* Volume start sector */
n_vol = LD_DWORD(tbl+12); /* Volume size */
} else {
/* Create a partition in this function */
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
return FR_DISK_ERR;
b_vol = (sfd) ? 0 : 63; /* Volume start sector */
n_vol -= b_vol; /* Volume size */
}
if (!au) { /* AU auto selection */
vs = n_vol / (2000 / (SS(fs) / 512));
for (i = 0; vs < vst[i]; i++) ;
au = cst[i];
}
au /= SS(fs); /* Number of sectors per cluster */
if (au == 0) au = 1;
if (au > 128) au = 128;
/* Pre-compute number of clusters and FAT sub-type */
n_clst = n_vol / au;
fmt = FS_FAT12;
if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
/* Determine offset and size of FAT structure */
if (fmt == FS_FAT32) {
n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
n_rsv = 32;
n_dir = 0;
} else {
n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
n_fat = (n_fat + SS(fs) - 1) / SS(fs);
n_rsv = 1;
n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
}
b_fat = b_vol + n_rsv; /* FAT area start sector */
b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
b_data = b_dir + n_dir; /* Data area start sector */
if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
/* Align data start sector to erase block boundary (for flash memory media) */
if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
n = (n - b_data) / N_FATS;
if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
n_rsv += n;
b_fat += n;
} else { /* FAT12/16: Expand FAT size */
n_fat += n;
}
/* Determine number of clusters and final check of validity of the FAT sub-type */
n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
|| (fmt == FS_FAT32 && n_clst < MIN_FAT32))
return FR_MKFS_ABORTED;
switch (fmt) { /* Determine system ID for partition table */
case FS_FAT12: sys = 0x01; break;
case FS_FAT16: sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
default: sys = 0x0C;
}
if (_MULTI_PARTITION && part) {
/* Update system ID in the partition table */
tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
tbl[4] = sys;
if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
md = 0xF8;
} else {
if (sfd) { /* No partition table (SFD) */
md = 0xF0;
} else { /* Create partition table (FDISK) */
mem_set(fs->win, 0, SS(fs));
tbl = fs->win+MBR_Table; /* Create partition table for single partition in the drive */
tbl[1] = 1; /* Partition start head */
tbl[2] = 1; /* Partition start sector */
tbl[3] = 0; /* Partition start cylinder */
tbl[4] = sys; /* System type */
tbl[5] = 254; /* Partition end head */
n = (b_vol + n_vol) / 63 / 255;
tbl[6] = (BYTE)((n >> 2) | 63); /* Partition end sector */
tbl[7] = (BYTE)n; /* End cylinder */
ST_DWORD(tbl+8, 63); /* Partition start in LBA */
ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */
if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR sector */
return FR_DISK_ERR;
md = 0xF8;
}
}
/* Create BPB in the VBR */
tbl = fs->win; /* Clear sector */
mem_set(tbl, 0, SS(fs));
mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
i = SS(fs); /* Sector size */
ST_WORD(tbl+BPB_BytsPerSec, i);
tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
ST_WORD(tbl+BPB_RootEntCnt, i);
if (n_vol < 0x10000) { /* Number of total sectors */
ST_WORD(tbl+BPB_TotSec16, n_vol);
} else {
ST_DWORD(tbl+BPB_TotSec32, n_vol);
}
tbl[BPB_Media] = md; /* Media descriptor */
ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
n = get_fattime(); /* Use current time as VSN */
if (fmt == FS_FAT32) {
ST_DWORD(tbl+BS_VolID32, n); /* VSN */
ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
tbl[BS_DrvNum32] = 0x80; /* Drive number */
tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
} else {
ST_DWORD(tbl+BS_VolID, n); /* VSN */
ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
tbl[BS_DrvNum] = 0x80; /* Drive number */
tbl[BS_BootSig] = 0x29; /* Extended boot signature */
mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
}
ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
return FR_DISK_ERR;
if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */
disk_write(pdrv, tbl, b_vol + 6, 1);
/* Initialize FAT area */
wsect = b_fat;
for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
n = md; /* Media descriptor byte */
if (fmt != FS_FAT32) {
n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
} else {
n |= 0xFFFFFF00;
ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
ST_DWORD(tbl+4, 0xFFFFFFFF);
ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
}
if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
return FR_DISK_ERR;
mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
return FR_DISK_ERR;
}
}
/* Initialize root directory */
i = (fmt == FS_FAT32) ? au : n_dir;
do {
if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
return FR_DISK_ERR;
} while (--i);
#if _USE_ERASE /* Erase data area if needed */
{
DWORD eb[2];
eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
}
#endif
/* Create FSInfo if needed */
if (fmt == FS_FAT32) {
ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */
ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */
ST_WORD(tbl+BS_55AA, 0xAA55);
disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */
disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */
}
return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
}
在线仿真,发现函数在disk_write处存在问题,于是开始改写该底层函数
/**************************************************************************************
* 名 称: disk_write
* 功 能: Write Sector(s)
* 参 数: drv:表示需要读扇区的磁盘对象
*<span style="white-space:pre"> </span> BYTE drv: Physical drive nmuber (0..)
*<span style="white-space:pre"> </span> BYTE *buff: Data buffer to store read data
*<span style="white-space:pre"> </span> DWORD sector: Sector address (LBA)
*<span style="white-space:pre"> </span> BYTE count: Number of sectors to read (1..128)
* 调用方式:disk_initialize(0,buff,0,1);
* 返 回 值:<span style="white-space:pre"> </span>状态标识0:表示成功
***************************************************************************************/
void flash_page_write_si(uint32_t sector,uint8_t *data)
{
<span style="white-space:pre"> </span>uint16_t i;<span style="white-space:pre"> </span>
SPI_FLASH_WriteEnable();
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW();
/* Send "Write to Memory " instruction */
SPI_FLASH_SendByte(0x02);
/* Send WriteAddr high nibble address byte to write to */
SPI_FLASH_SendByte((sector & 0xFF0000) >> 16);
/* Send WriteAddr medium nibble address byte to write to */
SPI_FLASH_SendByte((sector & 0xFF00) >> 8);
/* Send WriteAddr low nibble address byte to write to */
SPI_FLASH_SendByte(sector & 0xFF);
<span style="white-space:pre"> </span>for (i = 0; i < FLASH_SECTOR_SIZE; i++)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>SPI_FLASH_SendByte(*data++);
<span style="white-space:pre"> </span>}
SPI_FLASH_CS_HIGH();
/* Wait the end of Flash writing */
SPI_FLASH_WaitForWriteEnd();
}
DSTATUS disk_write (BYTE drv,const BYTE *buff,<span style="white-space:pre"> </span>DWORD sector,<span style="white-space:pre"> </span>BYTE count)
{
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>flash_page_write_si(sector,(uint8_t *)buff);
<span style="white-space:pre"> </span>return RES_OK;
}
disk_write改写完成,是对内存块进行写操作。这样子flash的初始化应该算是完成了。再次烧录程序,报错相同。
进入f_open函数,发现错误返回在chk_mounted(),进入该函数,发现check_fs()才是罪魁祸首,
fmt = check_fs(fs, bsect = 0); /* Load sector 0 and check if it is an FAT-VBR (in SFD) */
if (LD2PT(vol) && !fmt) fmt = 1; /* Force non-SFD if the volume is forced partition */
if (fmt == 1) { /* Not an FAT-VBR, the physical drive can be partitioned */
/* Check the partition listed in the partition table */
pi = LD2PT(vol);
if (pi) pi--;
tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* Partition table */
if (tbl[4]) { /* Is the partition existing? */
bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
fmt = check_fs(fs, bsect); /* Check the partition */
}
}
if (fmt == 3) return FR_DISK_ERR;
if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
研究了很久,还是找不到问题所在,于是请教了一个大神,说可能是flash大小问题,我使用的是2M大小,大神说fat系统的管理所占用的内存就非常大,要不就自己做小个小型的文件系统来实现这个功能。好吧,受教了。