野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 31027|回复: 6

FatFS文件系统崩溃问题

[复制链接]
发表于 2018-5-23 17:52:10 | 显示全部楼层 |阅读模式
F429-挑战者板子。

用SD卡文件系统的例程改的程序,读写、建立文件、遍历都很顺利。卡是32G SDHC。没有操作系统。

这两天想测试一下文件写满和SD卡写满的极限情况,就改了这么一个流程:

建立一个新文件,在主程序中持续不断地f_write(),每次32768字节,文件长度达到2G之后,关闭文件。再建立一个新文件。如此循环。

但一直出问题,写了几G就会停止,此时用PC读卡就会发现文件系统被损坏,或者文件被损坏。

调试后发现是f_write()返回FR_OK,但是返回的实际写入字节是0。

进一步跟踪发现,分为两种情况:

一种是文件系统的free_clust还有很多剩余,但是last_clust已经是最后一个簇的地址了;

另一种是last_clust指向正常的几个G的地址,但是free_clust为0了。

进一步对第一种情况进行跟踪后发现,用get_fat()申请新簇的时候,列表中根本没用过的簇返回值也不是0,而是一个乱数,感觉文件系统的参数区被写乱了。

进一步测试,开机重新建立文件系统,之后对所有空闲簇调用get_fat(),返回值均为0,证明此时文件系统的参数区还是好的。推测是连续写操作时意外地把数据写进了参数区。

后来我降低了测试的写入速度,主循环4096次才调用一次f_write(),上述现象有所缓解。

那么问题来了:

1,大家有没有碰到过类似的情况?

2,我这种操作流程有没有什么问题?

3,对SD卡的读写操作不是阻塞式的吗?为什么连续读写会造成异常呢?

期待大家的解答,也希望遇到类似问题的朋友来一起讨论!
回复

使用道具 举报

发表于 2018-5-24 08:54:10 | 显示全部楼层
应该是sdio的底层驱动有问题,st官方写得不够完善
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-24 09:19:01 | 显示全部楼层
左丘冰 发表于 2018-5-24 08:54
应该是sdio的底层驱动有问题,st官方写得不够完善

感谢回答!

请问你也碰到过类似的情况吗?

那么是不是我主要关注diskio.c里的函数就好了呢?

我之前试着跑不带文件系统的那个SD例程,可是没有跑通,擦除的时候失败了。这两个历程的sdio底层是一样的吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-25 17:55:14 | 显示全部楼层
更新一下调试的情况。问题仍然没有解决。

1,降低写入速度并没有改善这个问题。仍然会出现。

2,问题出现的规律大概是这样的。如果单个文件尺寸较小(如100M),那么在写入总量达到2G多的时候就会出问题;如果文件尺寸是4G,那么第二个文件就会出问题,第一个文件还没有见过出问题的。

3,确认问题的根源是文件系统被写乱了。首先把写入文件的数据固定为0x55,出问题后调用get_fat()查询簇状态,本应是未使用的簇返回值就是0x55555555。

4,我直接调用diskio.c里的disk_write()和disk_read()进行读写测试,写32768字节再读出,比较读出和写入内容是否一致。未发现异常。

基于以上现象,基本可以确定问题的原因是把数据写入错误的地址了。可是这究竟是哪里的问题呢?

1,如果说是硬件问题,SD卡寻址是通过指令完成的,而且指令还有CRC校验,感觉误码的概率比较小。

2,由于disk_write()和disk_read()测试没有出问题,是不是可以考虑问题出在文件系统本身?

3,由于第一个文件总是不出错,难道是f_close()会造成问题?但是小文件也不是第二个文件出问题,所以问题还是跟地址有关系?

期待大家的想法,或者是测试建议!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-5-28 21:56:39 | 显示全部楼层
问题解决了。

结果还是diskio.c的问题。

disk_write()函数里调用了SD_WriteMultiBlocks()函数,其中有一个参数是WriteAddr,这个地址是字节寻址的,是64位整数。如下:
               
                        SD_state=SD_WriteMultiBlocks((uint8_t *)buff,sector*SD_BLOCKSIZE,SD_BLOCKSIZE,count);

可以看到调用时的实参表达式是sector*SD_BLOCKSIZE,这个sector是扇区寻址的,是一个32位整数,所以这个表达式的计算结果仍然是32位的,导致地址的高位被抹掉,所以错误地寻址到前面的扇区,破坏了文件系统。

解决方法也很简单,定义一个64位的临时变量,把sector的值赋进去再做乘法就好了。
回复 支持 反对

使用道具 举报

发表于 2018-6-16 23:21:13 来自手机 | 显示全部楼层
厉害了,膜拜一下大神
回复 支持 反对

使用道具 举报

发表于 2021-6-25 08:56:38 | 显示全部楼层
厉害啦.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-9-22 22:21 , Processed in 0.094904 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表