项目背景
最近项目需要对一个64GB的SDNAND用stm32 通过FatFs文件系统进行初始化和读写,但是用的是贴片的SDnand,没办法像tf卡那样可以先插到电脑上初始化一下FAT32文件系统再插到stm32板子上用。SDNAND在制板时就需要贴在板子上了。所以只能用stm32对其进行初始化并建立文件系统。下面是我用的SD驱动,在网上找的,好像还是一个流传度比较高的驱动。
问题
但是用stm32对64GB的SDNAND芯片进行初始化时,不知为何初始化之后的结果是只有26.3GB的空间被成功初始化成了FAT32文件系统,还有32GB的空间是未分配的状态。 如下图:
一开始我以为是fatfs文件系统的版本太低了,但是我问了一下chatgpt他说是f_mkfs()函数的问题,需要将f_mkfs("", 1, 0);中的第二个参数改成1,也就是将SD格式化成一整个简单卷。我改了但是没用。
然后我把64GB的芯片换成了32GB的,用同样的程序和流程对其进行了初始化,结果32GB的空间全部初始化成功。
那么这个时候就有一个疑点了,如果说是文件系统的限制最大只能格式化32GB的卡的话,那之前64GB的时候为什么只格式了26.3GB?而且还刚好未分配的空间是32GB。这种状况让我联想到给一个变量赋值但超过其表示范围时发生的情况:例如一个变量它能表示的数据范围是0到10,你给它赋值10,那么它的值就是10,但是如果你给它赋值15的话,它里面存储的数不会是它能表示的最大数 10,而是多余的数会回到0重新开始累计,也就是最终这个变量里存储的数是5,你丢失掉的数据才是10。
所以我把目光转向了检查代码中是否有发生变量数据溢出的情况,结合另一篇文章:SD/TF卡使用FATFS的f_mkfs()函数格式化后容量减小_fatfs 格式化-CSDN博客
我把目光放向了一个函数:SD_GetSectorCount(void)
uint32_t SD_GetSectorCount(void)
{
uint8_t csd[16];
uint32_t Capacity;
uint8_t n;
uint16_t csize;
//取CSD信息,如果期间出错,返回0
if(SD_GETCSD(csd)!=0) return 0;
//如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
Capacity = (uint32_t)csize << 10;//得到扇区数
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
Capacity= (uint32_t)csize << (n - 9);//得到扇区数
}
return Capacity;
}
我问了一下chatgpt,他说是csize的计算方法出了问题,应该是:
csize = ((uint32_t)(csd[7] & 0x3F) << 16) | ((uint16_t)csd[8] << 8) | csd[9];
那么这个时候csize就应该是32位的,然后Capacity这个变量应该是64位的才对,然后我把这个函数修改了之后再运行,结果终于可以初始化64GB的卡了。
修改后的函数如下:
uint64_t SD_GetSectorCount(void)
{
uint8_t csd[16];
uint64_t Capacity;
uint8_t n;
uint32_t csize;
//取CSD信息,如果期间出错,返回0
if(SD_GETCSD(csd)!=0) return 0;
//如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = ((uint32_t)(csd[7] & 0x3F) << 16) | ((uint16_t)csd[8] << 8) | csd[9];
Capacity = ((uint64_t)csize + 1) << 10; // 得到扇区数,单位为512字节
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
Capacity= (uint32_t)csize << (n - 9);//得到扇区数
}
return Capacity;
}