cubemx软件版本是V4.23.0,芯片型号是STM32F103ZET6、STM32F429IGT6;SD卡是闪迪的64G tf卡,然后用了转大卡的卡槽,exFAT。
该篇为调试过程,所以阅读时一定要看到尾,中间的判断是有误的!!!中间会涉及到F429是因为一直失败,我拿两个板子来回尝试。
注意,//在生成fatfs代码后,一定要在初始化SDIO时或者FATFS初始化时加上该句(在f_mount前就行),因为cubemx建立中间层,把SD也封装了中间层BSP_SD,所以之前的默认初始化中HAL_SD_Init移至了该函数中!!!
BSP_SD_Init();
死在这个函数中
uint8_t SDIO_GetCommandResponse(SDIO_TypeDef *SDIOx)
{
return (uint8_t)(SDIOx->RESPCMD);
}
这个函数从disk_initialize开始被层层调用,在f_mount中去初始化SD卡,看是否成功。disk_initialize在diskio.c中定义,cubemx会自动生成,正点原子是自己写的实现功能。
为什么cubemx出来的获取SD卡状态要用到SDMMC?而正点原子没有使用到?
在cubemx F429时一定要使能exfat,我的tf卡默认是exfat格式,正点原子支持,cubemx的教程都没有提到exfat,在f_mount中有判断SD卡的启动页,去检查是什么文件格式,如果不使能就会被认为是没有文件系统。f_mount就会失败。
但是在cubemx F103时则没有该项。
正点原子的HAL与我的cubemx生成的HAL,stm32f4xx_hal_sd.c都不一样。可能是版本问题,cubemx生成的HAL版本为2017年,原子的为2016年。
普通使用SD卡读写是可以的,但在FATFS中调用HAL_SD的读写就会死机,不知道为什么!
世上无难事,只要肯放弃。明天上网找找资料,如果还是没有结果的话,就先放到一边,以后有时间再突破把,反正移植原子的也可以用。
在F103精英版创建了读SD卡的程序,需要注意,因为HAL与正点原子的不同,读扇区不是计算出具体地址,而是直接输入要读的扇区号。
刚开始读不出来,后来在论坛上发现原子的分频因子设为了9.同样设为9就能读了,跟内存分配也没关系,读出的buff为局部指针也可以。
还发现一个不同,HAL版本不同,读出的SD卡的类型号也不同。
cubemx的HAL:
/** @defgroup SD_Exported_Constansts_Group3 SD Supported Memory Cards
* @{
#define CARD_SDSC 0x00000000U
#define CARD_SDHC_SDXC 0x00000001U //同样的SD卡读出这个
#define CARD_SECURED 0x00000003U
/** @defgroup SD_Exported_Constansts_Group4 SD Supported Version
* @{
*/
#define CARD_V1_X 0x00000000U
#define CARD_V2_X 0x00000001U
原子的HAL:
/**
* @brief Supported SD Memory Cards
*/
#define STD_CAPACITY_SD_CARD_V1_1 ((uint32_t)0x00000000)
#define STD_CAPACITY_SD_CARD_V2_0 ((uint32_t)0x00000001)
#define HIGH_CAPACITY_SD_CARD ((uint32_t)0x00000002) //同样的SD卡读出这个
#define MULTIMEDIA_CARD ((uint32_t)0x00000003)
#define SECURE_DIGITAL_IO_CARD ((uint32_t)0x00000004)
#define HIGH_SPEED_MULTIMEDIA_CARD ((uint32_t)0x00000005)
#define SECURE_DIGITAL_IO_COMBO_CARD ((uint32_t)0x00000006)
#define HIGH_CAPACITY_MMC_CARD ((uint32_t)0x00000007)
接下来再试写入,之后再读,成功后就重新配置fatfs.
在F429上重新实验SD卡,成功,发现一件事儿,就是SD卡的实验是往扇区0写入一串数字,这会破坏SD卡的fatfs的启动扇区。原来启动扇区中的数据都会被写入而先擦写。所以我之前可能也是因为这个而实验FATFS失败。
重新实验fatfs
我去,我竟然成功了!也太鬼扯了吧!
用F429的SD卡实验重新配置fatfs,竟然成功了!挂载、打开文件(打开、新建)、写文件、关文件、打开文件(读)、读文件、卸载都成功了。
转天我又尝试了F103的FATFS,F103与F429的cubemx配置FATFS不一样,F103没有使能exFAT的选项。
我以为是默认支持的,结果生成代码后总是mount失败。重新格式化也不行,而且去看0扇区,也没毛病呀。
追根溯源是代码在判断SD卡的FAT类型出错,识别不了FAT类型。
原来是cubemxF103生成的代码没有_FS_EXFAT,而原子的F103例程是有的,而且和F429的一致。
通过查看HAL版本,我发现cubemx生成的是 R0.11 (C)ChaN, 2015。原子的是R0.12 (C)ChaN, 2016
我想如果是因为2015版的HAL不支持exFAT,那我试试格式化SD卡为FAT32,结果成功了。。。。。。
也就是说可能是我的cubemx支持的F103板级包版本低。我试试升级软件版本试试看。
升级了最新的cubemx5.6.0,然后F103的板级包也是最新的,但是重新配置FATFS仍旧是version0.11。原子是从FATFS官方移植的R0.12,cubemx配置F429是R0.12c版本。所以应该就是cubemx没有及时更新F103的。
所以如果想用最新的,还是得自己去移植FATFS,有时间再搞吧。
F103实验结果:
1.先打印SD卡信息
2.打印0号扇区的数据
3.先挂载,显示成功
打开文件,读取,关闭,失败,因为没有STM32cube.txt文件
创建文件STM32cube.txt,写入数据,关闭,成功
打开文件,读取,关闭,成功,因为此时有了STM32cube.txt文件
卸载,成功
F429实验结果类似,就不贴结果了,有需要的朋友可以下载资源去试一下
1.看门狗延长了,恢复,没有问题。
2.SD卡的分频提高了,恢复最快速度,分频为0,也没问题。注意:F103的SD卡实验分频降到2以下就不行,需要在2以上。
3.把BSP_SD_Init放在挂载之后去,那么挂载的时候操作SD卡时就会死机。这个是坑,但我最近已经发现了这个问题。所以不是这个问题导致的。
4.那么有可能就是我往SD卡扇区0去写数据,损坏了启动盘,导致挂载失败。
5.此外还有一个坑是:f_open,如果你要写入一些文件,那么要先打开文件。retSD = f_open(&SDFile, filename, FA_CREATE_ALWAYS | FA_WRITE);
如果要读取一个文件前,也要先打开文件,但是注意区别!retSD = f_open(&SDFile, filename, FA_READ);
6.此外还有一个坑是:f_close,只要打开一个文件去操作了读写,那么之后一定要关闭文件。不然下次打开(即便你上次打开是要写,这次打开还是要写)就会失败。
也就是说,f_open和f_close要成为一个最小闭环。也就是()(),不能是(())。
也就是说,可以(f_write,f_write),但是不能(f_write(f_write)),(f_write,f_read)更是不可以了。
7.f_mount除了挂在外,retSD = f_mount(&SDFatFS, (const TCHAR*)SDPath, 1);
还有卸载的功能,即把路径下的文件系统卸载,retSD = f_mount(0, (const TCHAR*)SDPath, 1);
挂载和卸载都可以重复,没有问题。即便没有挂载也可以卸载。
但需要注意的是:卸载后就不能操作f_open等功能了,一定要先挂载。
挂载是个什么意思呢,就是通过读取SD卡的启动扇区,来让单片机的fatfs知道SD卡的具体参数,如检查是FAT32还是EXFAT啊,有没有文件系统啊。fat表的个数啊、簇大小啊、扇区数量、扇区大小啊。
然后还要通过SDMMC(SD卡的底层)去询问SD卡的状态,去查SD卡的FATFS是否能用啊。非常多。
一通检查,信息也获取了,验证能使了,就挂载成功了。
通过查看FATFS的句柄也可知其一二。
8.把栈空间分配的大一些,0x1000就够了。堆不用多分配0x200够了。我们看到原子的栈是0x400,堆是0x200,那怎么够呢。
他用的是内存分配,把要用到的FATFS的句柄、读写buff都分配在静态内存空间中,也就是除去堆和栈的SRAM空间中。
9.SD卡是FAT32的还是exFAT的都无所谓,但是一定要知道自己的SD卡是什么文件系统的,如果是exFAT类型的,则一定要使能_FS_EXFAT
F103不一定会区分exFAT,要看HAL库版本是否支持_FS_EXFAT。如果HAL版本低,那就先把SD卡格式化为FAT32再用吧。
exFAT和FAT32的区别在哪呢?FAT32不支持单文件超过4G,exFAT支持。FAT32有两个FAT表,exFAT只有一个。
FATFS其实还真的蛮复杂的,尤其是出问题的时候,真的是要一点一点倒,很多错误码的返回,去分析。
ff.c的代码也很复杂,但是我想起一句话,就是说一个东西底层做的很复杂的,往往使用起来就很简单。
比如USB,驱动也是很复杂的。比如苹果,用起来很简单的一个功能,底层代码不知道有多少逻辑。
这次做这个实验,我真的是头要炸了,好在有开发板,开发板能成功,我们就能对比着来看,找不同。
通过修改不同,一点点把自己的代码尝试成功。
所以开发板的作用一定不是给你提供底层让你去移植的,他只能作为学习用,真正使用好cubemx,会让你事半功倍。
不用看SD卡的手册,命令怎么发之类的。配置好cubemx,HAL库的封装做的非常好,直接读写指定扇区。
不用从源码移植FATFS,辛辛苦苦的,还得做好FATFS与SD卡的连接,选好FATFS的SD选项,cubemx帮你建立好连接。f_mount就完事儿了。
但是cubemx也不能认为是万能的,比如初始化的坑。他自己也有写的不好的地方,所以这也是为什么要自己动手去实战去找坑。
只有提前踩好了坑,以后用时才会不慌。
这次调试FATFS包括学习资料,断断续续大约耗时十六个小时,中间好几次想放弃了,但是心有不甘。
好在成功了,非常非常开心。
希望能够帮到别人,祝所有努力的人都有回报。
最近项目中的nandflash128M,不够存了。和同事咨询用SD卡存历史数据。一种是用文件系统、一种是不用文件系统按照类似操作nandflash的方式操作。
1.如果用文件系统的话每日生成一个.csv,导出数据比较方便,想导出数据的话直接取下SD卡就能在电脑上读取。存起来也比较方便,不用计算存到哪个扇区,哪一页,偏移量多少。但是缺点是,在应用程序中读取历史数据很麻烦,由于文件系统是针对文件的,并不支持文件中内容的操作,比如查找、指定位置增加删除数据等。
2.如果不用文件系统的话,难点就在于设计一个用时间计算地址的方式,因为最小擦除单位和nandflash一样都是扇区,所以这部分工作也不少做。此外,由于没有用文件系统,电脑不能直接读取。所以还需要做一个U盘导出功能。但是优点就是应用程序获取指定时间的历史数据比较方便。
对nandflash感兴趣的可以看下我的文章
调试数据存储到nandflash的那些事儿(一):关于sizeof()的一些坑
调试数据存储到nandflash的那些事儿(二): 存入nandflash的方式比较
调试数据存储到nandflash的那些事儿(三): 关于移位存入,强制类型转换读出的讨论
调试数据存储到nandflash的那些事儿(四):nandflash底层的简介
调试数据存储到nandflash的那些事儿(五):对nandflash的寻址说明