FATFS一个小BUG搞了我2天才解决.特此发帖,希望大家不要重蹈我的覆辙.

2019-07-21 01:06发布

问题:在做豪华版fatfs实验的时候,发现从综合实验移植过来的fatfs部分,f_mkdir不能正常工作,跟踪调试发现死在move_window函数里面,如下图红线处.

只要执行过红线,就进入hard_fault了...
经验告诉我,这肯定是内存访问有问题.
于是对比成功和失败两个版本的fs,wsect,fs->fatbase,fs->fsize 他们对应值都一样!!!
这样,哥迷茫了...
于是使出浑身解数,疯狂替换反替换,结果还是一样...
后来发现我的综合实验使用了-o1,等优化选项.于是设置为一模一样.此时终于可以f_mkdir了...
但是作为普通实验,没必要开优化啊...所以还得找原因.
没办法,最后用绝招了,从最简单的做起,把不相干的代码统统砍掉.最后在去掉malloc的时候,奇迹终于出现了...
把如下代码:
//为exfuns申请内存
//返回值:0,成功
//1,失败
u8 exfuns_init(void)
{
 fs[0]=(FATFS*)mymalloc(SRAMIN,sizeof(FATFS)); //为磁盘0工作区申请内存 
 fs[1]=(FATFS*)mymalloc(SRAMIN,sizeof(FATFS)); //为磁盘1工作区申请内存
 file=(FIL*)mymalloc(SRAMIN,sizeof(FIL));  //为file申请内存
 ftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL));  //为ftemp申请内存
 fatbuf=(u8*)mymalloc(SRAMIN,512);    //为fatbuf申请内存
 if(fs[0]&&fs[1]&&file&&ftemp&&fatbuf)return 0;  //申请有一个失败,即失败.
 else return 1; 
}
不用malloc,而直接用全局数组来实现,就可以正常工作.
然后发现FATFS本来只有562字节,但是sizeof之后,却是564字节,反复数了N遍,确认FATFS只有562字节,这多了的2个字节,肯定就是FATFS结构体数据对其的问题了,于是赶紧在FATFS结构体前面加上__paked关键字.如下:
__packed typedef struct {
 BYTE fs_type;  /* FAT sub-type (0:Not mounted) */
 BYTE drv;   /* Physical drive number */
 BYTE csize;   /* Sectors per cluster (1,2,4...128) */
 BYTE n_fats;   /* Number of FAT copies (1,2) */
 BYTE wflag;   /* win[] dirty flag (1:must be written back) */
 BYTE fsi_flag;  /* fsinfo dirty flag (1:must be written back) */
 WORD id;    /* File system mount ID */
 WORD n_rootdir;  /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != 512
 WORD ssize;   /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT
 _SYNC_t sobj;   /* Identifier of sync object */
#endif
#if !_FS_READONLY
 DWORD last_clust;  /* Last allocated cluster */
 DWORD free_clust;  /* Number of free clusters */
 DWORD fsi_sector;  /* fsinfo sector (FAT32) */
#endif
#if _FS_RPATH
 DWORD cdir;   /* Current directory start cluster (0:root) */
#endif
 DWORD n_fatent;  /* Number of FAT entries (= number of clusters + 2) */
 DWORD fsize;   /* Sectors per FAT */
 DWORD fatbase;  /* FAT start sector */
 DWORD dirbase;  /* Root directory start sector (FAT32:Cluster#) */
 DWORD database;  /* Data start sector */
 DWORD winsect;  /* Current sector appearing in the win[] */
 BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
} FATFS;

之后再用sizeof,得到FATFS大小是562字节了...
然后再次加入malloc,代码也可以正常工作了.
至此,该问题终于解决了.
究其原因,就是FATFS结构体的字节对齐问题.所以建议大家在自己建立结构体的时候,最好加上__packed关键字,免得再出现这种郁闷的情况.
浪费2天...
不过也有所收获.
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
47条回答
正点原子
1楼-- · 2019-07-21 03:27
回复【13楼】Pony279:
---------------------------------
是的,这里确实是我哪个malloc的问题.
在内存池前加上4字节对齐,问题解决!

//内存池(4字节对齐)
__align(4) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池
__align(4) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM内存池
zenghi
2楼-- · 2019-07-21 06:00
忽然让我想到了SSD的4K对齐,学习了。
Pony279
3楼-- · 2019-07-21 08:32
建议直接修改 malloc 使之分配出来的内存字节对齐,而不是修改 FATFS 源码,
如果强制用 pack 指令,最直接的影响就是程序的性能降低,虽然会节省 ram,但是省不了 flash
就算没有用 pack 指令,性能也可能会降低,而且如果运气不好,就会进入一些奇怪的错误中断了
修改 malloc 可以提高程序的兼容性。在 32 位机上通常是 4 字节对齐的。
正点原子
4楼-- · 2019-07-21 10:16
接着调试,发现FIL也需要字节对齐才行,否则也有问题!!!
Pony279
5楼-- · 2019-07-21 14:27
 精彩回答 2  元偷偷看……
正点原子
6楼-- · 2019-07-21 15:47
 精彩回答 2  元偷偷看……

一周热门 更多>