[大问题的解决!]!!!用FatFS的朋友们注意了啊,福利来了!

2019-07-20 04:43发布

以前用FatFS的时候有没有发现在使用大容量卡(4G以上)的时候,卡里存了4G以上的东西,新存的文件就不能被正确读取了呢?!
这是因为大家移植的FatFS都是32位寻址的,只能读到4G以下地址的东西,4G以上的东西虽然文件分配表还有分配,但是却没有这么大的地址去读取。
怎么办呢?让我们来解决这个问题吧!

首先,打开SDIO/SPI总线驱动SD卡的底层文件:

sd.h-------------------
sd.c-------------------

在文件里找到下面的几个函数(类似的也行):
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);

看到Addr的参数了吗?这是地址,现在我们把它改成64位的,像这样:

SD_Error SD_ReadBlock(uint8_t *readbuff, uint64_t ReadAddr, uint16_t BlockSize);
SD_Error SD_ReadMultiBlocks(uint8_t *readbuff, uint64_t ReadAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);
SD_Error SD_WriteBlock(uint8_t *writebuff, uint64_t WriteAddr, uint16_t BlockSize);
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint64_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);

现在,SD卡的底层就改造好了,我们接着改造FatFS:
打开FatFS目录下的integer.h

找到下面几行代码:
/* These types must be 32-bit integer */
typedef long  LONG;
typedef unsigned long  ULONG;
typedef unsigned long  DWORD;

现在稍稍修改一下,变成这样:
/* These types must be 64-bit integer */
typedef long long LONG;
typedef unsigned long long ULONG;
typedef unsigned long long DWORD;

就是把unsigned long 无符号长整型变成unsigned long long 无符号64位长整型。
现在整体改造完毕,可以试试往SD卡里先写5~6G数据,然后再写个文本,现在读就不会读出乱码啦!
原先32位寻址时,最大支持4GBytes的寻址,现在的寻址空间扩大了4294967295倍,你的SD卡再怎么大都不会出错啦!



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
46条回答
yu7622
2019-07-25 08:20
我试了一下
这个方法可以,但是有个地方不好:“就是把unsigned long 无符号长整型变成unsigned long long 无符号64位长整型。”这种操作其实已经改变了FATFS的库函数的变量类型,我觉得最好别改库文件。
我用另一个方法做了测试,不需要修改这个变量类型的定义:

DRESULT disk_write (
        BYTE pdrv,                        /* Physical drive nmuber to identify the drive */
        const BYTE *buff,        /* Data to be written */
        DWORD sector,                /* Start sector in LBA */
        UINT count                        /* Number of sectors to write */
){}
这个函数传递的是一个sector值,在调用SD_WriteMultiBlocks(uint8_t *writebuff, uint64_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks);这个函数的时候,我这里找到的例程是直接用这样的方式:
SD_WriteMultiBlocks(buff, BLOCK_SIZE*sector, BLOCK_SIZE, count);
因为sector本身是一个DWORD类型,是不是因为BLOCK_SIZE*sector的值在计算之后仍然默认是DWORD类型(这时候已经地址溢出了),然后在参数传递的时候才强制转换为uint64_t,其实等于是先发生了溢出,然后再传递?
所以我改成了这种方式:
SD_WriteMultiBlocks(buff, BLOCK_SIZE*(uint64_t)sector, BLOCK_SIZE, count);

这样处理并不需要更改integer文件里面DWORD的类型定义,测试后反正8G的SD卡读写到6G多的时候是没什么问题的。按这样处理的话,在BLOCK_SIZE为512的情况下,理论上应该能支持512*4G 大小的SD卡,不知道我理解的对不对?

一周热门 更多>