本帖最后由 huo_hu 于 2018-3-3 00:21 编辑
此内容由EEWORLD论坛网友huo_hu原创,如需转载或用于商业用途需征得作者同意并注明出处
最近整了一下cubeMX FAT sdio 一点经验和大家分享,有不对的地方欢迎指正。
我用的是一个stm32f407的系统板,网上买的,自带micro sd卡座,原理图如下
其中第九脚NC可以接一个IO口做插卡检测。SD卡部分硬件很简单。
软件配置比较复杂,我说得详细一点照顾一下初上手的同学们哈。
首先要从st的官网上下载cubeMX安装包,大概300多M,下载前需要用邮箱登记一个账号,通过收到的邮件链接登陆后就可以下载了。
安装好cubeMX以后,先在cube里下载最新的固件库
多说一句这里面的Updata Setting 可以选择固件库的安装路径,默认是在C盘,cube会把安装包和解压的文件全放在指定的那个目录里,而且新旧版本同时存在,st的其他芯片型号的库文件全在这里比较大而且文件众多,你可以考虑换到其它目录里。
有一个最新版就行了,没必要都装,之前用1.18在fat部分里面有个bug,1.19是前几天刚发布的已经修正了。
下一步新建project选择芯片型号如图
我这个是f407 qfp100,405和407基本通用
然后给工程添加需要使用的硬件
这里面sys部分是为了支持仿真器我用的是stlink sw模式,图上是最小化的管脚配置没用到的都留出来。
sdio部分用的是4线模式和原理图对应。
下一步配置一下时钟,这个实验里对时钟要求不严格,所以用内部时钟源
下一步添加文件系统,因为你系统里可能有多种设备比如u盘或闪存,要让fatfs和sd卡挂钩
下一步SDIO的dma设置和中断
这里说明一下sdio的操作不是必须用dma,这里只是加入dma的配置代码。
另外使能sdio中断,dma的收发完成中断会自动添加,paramatersetting里也是比较重要的是sdio基本设置,默认的就行不贴图了。
下一步调整中断优先级,如果你开的中断比较多可能需要调整一下响应顺序,这步不是必须的。
下一步是文件系统选项,这里参数众多,而且不太好理解做什么用的,其实在生成代码以后这些设置对应在ffconf.h里面的宏设置,在每个设置里面都有一段说明,这里有一个中文的
aa.txt
(59 Bytes, 下载次数: 13)
我在这里关闭了长文件名的支持,打开长文件名和中文支持后编出来的目标又好几十K,感觉太浪费了,(其实文件系统所要确定的就是一个绝对扇区号,长文件名的支持太耗资源了)
关闭以后你只要记得用最古老的dos文件名方式就行,1:文件名和目录都不要有中文 2:不区分大小写一律按大写算 3:8.3的格式8个文件名加三个字符的文件类型。
生成代码以后这些配置全都在ff.c应用,具体怎么个情况看ff.c程序代码就可以了。
另外还有2个设置,不太重要。前面那个dma只是配置dma,这里选择才是真正的在程序中使用。
sd卡和fatfs就这些,下一步设置一下工程然后生成代码
好了,现在打开工程文件,main.c里应该已经调用了两个初始化 MX_SDIO_SD_Init(); 和MX_FATFS_Init();
你可以看到sdio的初始化只是配置硬件,并没有真正的去读卡,MX_FATFS_Init();才真正的去读卡信息,如果你需要插卡检测功能的话,你可以屏蔽掉这个函数可以,等到检测到卡插入再执行。建议你不要去直接改main.c,因为下次更新代码的时候所做的修改会被覆盖,你最好从cube里选择不要执行这个初始化,在cube的project setting ->advanced setting里勾选not generate function call就好
fatfsinit里添加挂载函数
(下面的红色部分是要添加的)
void MX_FATFS_Init(void)
{
/*## FatFS: Link the SD driver ###########################*/
retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
/*## FatFS: Link the USER driver ###########################*/
retUSER = FATFS_LinkDriver(&USER_Driver, USERPath);
/* USER CODE END Init */
retSD = f_mount(&SDFatFS, SDPath, 1);
/* USER CODE BEGIN Init */
}
如果你使能了dma访问,就是那个“use dma template"为 enable ,f_mount函数会死循环,是因为DMA中断里要加一个回掉函数更多细节我们后面再探讨。先打开stm32f4xx_it.c在最前面部分引入这两个函数
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "stm32f4xx.h"
#include "stm32f4xx_it.h"
/* USER CODE BEGIN 0 */
extern void BSP_SD_WriteCpltCallback(void);
extern void BSP_SD_ReadCpltCallback(void);
/* USER CODE END 0 */
在dma中断处理完以后调用对应的回调
void DMA2_Stream3_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream3_IRQn 0 */
/* USER CODE END DMA2_Stream3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_sdio_rx);
/* USER CODE BEGIN DMA2_Stream3_IRQn 1 */
BSP_SD_ReadCpltCallback();
/* USER CODE END DMA2_Stream3_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream6 global interrupt.
*/
void DMA2_Stream6_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream6_IRQn 0 */
/* USER CODE END DMA2_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_sdio_tx);
/* USER CODE BEGIN DMA2_Stream6_IRQn 1 */
BSP_SD_WriteCpltCallback();
/* USER CODE END DMA2_Stream6_IRQn 1 */
}
这样dma读写就可以正常了。
f_mount是真正的初始化卡,大致的顺序是这样,1先读卡信息判断卡类型,2读0扇区确定分区偏移,3读引导区确定fat类型表位置等,成功的话会返回0,另外你可以看到fatfs.c里有全局量定义
全局量有两套,sdXX userXX,一套是给文件系统用的,一套是用户打开的文件,因为范围fat或目录表的时候和访问文件是一样的,实际上fat表就是一个文件。FIL文件结构里带有缓冲区,文件操作会触发fat表的访问,访问时fat表内容填充到SDFile的缓冲区。
这个f_mout函数的最后一个参数是
1表示挂载,0表示卸载,这里和网上的文章不一样。
挂载以后就可以用open打开文件了,打开文件的时候先检索路径符号/找到目录表,然后在目录表里查找匹配的文件名,如果找到则取出文件信息。
我这个文件是放在LCD_BMP目录下的,可以用绝对路径打开文件
retUSER = f_open(&USERFile,"LCD_BMP/FJ800_01.BIN", FA_READ);
函数返回0成功,否则返回ff.h里定义的FRESULT类型,如果出错了对着找下原因。
打开成功以后就可以访问文件数据了,
retUSER =f_read(&USERFile,readbuf,512,&rsize);
这里只是用顺序文件的访问方式,能不能任意位置读取还要看你对fatfs的seek设置。
readbuf是读取的数据填充缓冲区地址,512是读取的字节数,rsize是一个32位变量,把变量指针传给函数
uint32_t rsize;//读出字节
函数返回后这个变量是实际读取的字节数,比较特殊的情况是文件末尾不够512个字节的时候需要特殊处理。
编译后下载试试吧,sd+fat读取数据就这么多了,接下来是fsmc 方式的tftlcd