这段时间在做SD卡的驱动以及在此基础上增加FAT32文件系统.
SD卡目前使用SDHC 16G的TF卡,读写擦功能都支持.
那么FAT32文件系统,我们可以在网上找到开源的FAT文件系统这个文件系统,目前很多人都在使用.
移植方面很简单,只要实现diskio.c里面的几个函数就可以了.
另外,还有一个配置文件ffconf.h这个文件,主要配置一些功能.如是否支持长文件名,中文编码等等。
所以我们要实现支持长的英文名字,是需要配置以下宏
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
*/
#define _USE_LFN 3
#define _MAX_LFN 255
/* The _USE_LFN option switches the LFN feature.
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
/ to 1. This option also affects behavior of string I/O functions. */
然后将option目录下的syscall.c、unicode.c包含到工程里面.
由于需要支持到内存动态分配等原因,所以修改syscall.c文件的相关函数.如下图:
然后进行编译=======>通过!
然后,你写一个长文件名,如test0123456789.TXT,并往里面写内容.完全没有问题.读文件也是没有问题.
但是如果你要读文件的内容时,你要注意一下,因为你需要知道要读取的文件大小.也许你会使用
FRESULT f_stat (
const TCHAR* path, /* Pointer to the file path */
FILINFO* fno /* Pointer to file information to return */
)
通常代码,你会如下写
FILINFO fno;
if(f_stat( "0:Test1234567890.txt",&fno))
{
DEBUG_MSG(MAIN_DEBUG,("f_stat Fail !!!!\r\n"));
}
else
{
DEBUG_MSG(MAIN_DEBUG,("%s Size %d .\r\n",fno.fname,fno.fsize));
if(f_open(&file, "0:Test1234567890.txt", FA_OPEN_EXISTING | FA_READ))
{
DEBUG_MSG(MAIN_DEBUG,("f_open File Fail .\r\n"));
}
else
{
char *pBuffer = malloc(fno.fsize);
memset(pBuffer,0,fno.fsize);
if(pBuffer)
{
u32 kk = 0;
if(f_read(&file, pBuffer,fno.fsize, &bw))
{
DEBUG_MSG(MAIN_DEBUG,("f_read Fail !!!!\r\n"));
}
while(kk < fno.fsize)
{
DEBUG_MSG(MAIN_DEBUG,("%c",pBuffer[kk++]));
}
DEBUG_MSG(MAIN_DEBUG,("\r\nRead Size %d .\r\n",bw));
free(pBuffer);
pBuffer = NULL;
}
f_close(&file);
}
}
这个代码逻辑是没有什么大问题的.但是如果你用IAR debug方式,运行你会发现当程序异常了.
你深入调试会发现一个问题,文件大小竟然非常非常大.这个数值貌似没有赋值.
当你跟踪到如下代码
/*-----------------------------------------------------------------------*/
/* Get file information from directory entry */
/*-----------------------------------------------------------------------*/
#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
static
void get_fileinfo ( /* No return code */
DIR* dp, /* Pointer to the directory object */
FILINFO* fno /* Pointer to the file information to be filled */
)
{
UINT i;
TCHAR *p, c;
BYTE *dir;
#if _USE_LFN
WCHAR w, *lfn;
#endif
p = fno->fname;
if (dp->sect) { /* Get SFN */
dir = dp->dir;
i = 0;
while (i < 11) { /* Copy name body and extension */
c = (TCHAR)dir[i++];
if (c == ' ') continue; /* Skip padding spaces */
if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */
if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */
#if _USE_LFN
if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY)))
c += 0x20; /* To lower */
#if _LFN_UNICODE
if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i]))
c = c << 8 | dir[i++];
c = ff_convert(c, 1); /* OEM -> Unicode */
if (!c) c = '?';
#endif
#endif
*p++ = c;
}
fno->fattrib = dir[DIR_Attr]; /* Attribute */
fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */
fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */
fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */
}
*p = 0; /* Terminate SFN string by a \0 */
#if _USE_LFN
if (fno->lfname) {
i = 0; p = fno->lfname;
if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */
lfn = dp->lfn;
while ((w = *lfn++) != 0) { /* Get an LFN character */
#if !_LFN_UNICODE
w = ff_convert(w, 0); /* Unicode -> OEM */
if (!w) { i = 0; break; } /* No LFN if it could not be converted */
if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
p[i++] = (TCHAR)(w >> 8);
#endif
if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */
p[i++] = (TCHAR)w;
}
}
p[i] = 0; /* Terminate LFN string by a \0 */
}
#endif
}
#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
你会发现“fno->lfsize”这个值很大。如果你一路从f_stat函数跟踪进来,你会知道这整个过程“fno->lfsize”都没有被赋值过.因此,解决这个问题的方法是,开始的时候对"FILINFO fno"进行赋值.可以写成"FILINFO fno = {0};"
至此,读文件内容也正常了.补充一点,当不支持长命名文件时,都是很正常(但或许存在风险,因此无论如何对该结构体变量都需要进行赋初值).