STM32完全学习——FATFS0.15移植SD卡

一、下载FATFS源码

大家都知道使用CubMAX可以很快的将,FATFS文件管理系统移植到单片机上,但是别的芯片没有这么好用的工具,就需要自己从官网下载源码进行移植。我们首先解决SD卡的驱动问题,然后再移植FATFS文件管理系统。

二、SD卡的DMA读写实现

 这个我们直接使用工具生成就可以了,需要注意上面的那几点,不然会工作不正常。为了让大家看得更加清楚,下面的几个函数下的都比较简单,没有过多的判断。尽可能地缩短代码。下面这几个函数的实现是必须的不能在减少了。

//获取卡的状态
uint8_t SD_GetCardState(void)
{
	HAL_SD_CardStatusTypeDef pStatus;
	if (HAL_SD_GetCardStatus(&hsd, &pStatus) != 0)
	{
		return HAL_BUSY;
	}
	else
	{
		return HAL_OK;
	}
	
}
void SD_ReadBlocks_DMA(uint8_t *buf, uint32_t sector, uint32_t cnt)
{
	HAL_SD_ReadBlocks_DMA(&hsd, buf, sector, cnt);//通过DMA读取SD卡n个扇区
	while(SD_GetCardState() != SD_TRANSFER_OK);
	//等待SD卡读完
}
 
uint8_t SD_WriteBlocks_DMA(uint8_t *buf, uint32_t sector, uint32_t cnt)
{
	HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*)buf, sector, cnt);//通过DMA写SD卡n个扇区
	//等待SD卡写完
	while(SD_GetCardState()!=SD_TRANSFER_OK)
}

 三、FATFS中diskio.c里面相关函数的实现

#define DEV_FALSH   0
#define DEV_SD      1

#define SECTOR_SIZE 4096               //定义扇区大小

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
	switch (pdrv) {
		case DEV_FALSH :
			stat = EN25QXX_ReadSR();  //读取FLASH状态的函数
			return stat;
		case DEV_SD :
			stat = SD_GetCardState(); //读取SD卡状态的函数
			return stat;		
	}
	return STA_NOINIT;
}
DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat = 0;;

	switch (pdrv) {
		case DEV_FALSH :   
			return stat;   //如果你在外面已经做过了相关模块的初始化啥的这里直接返回接可以了
		case DEV_SD :
			return stat;
	}
	return STA_NOINIT;
}
DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA 
	UINT count		/* Number of sectors to read */
)
{
	uint32_t i = 0;
	uint8_t result = 0;
	
	switch (pdrv) {
		case DEV_FALSH :{
			uint32_t addr = sector*SECTOR_SIZE;
			for (i=0; i<count; i++)
			{
				EN25QXX_Read((BYTE *)buff, addr, SECTOR_SIZE);
				addr += SECTOR_SIZE;
				buff += SECTOR_SIZE;
			}
			return RES_OK;
		}
		case DEV_SD :{
			SD_ReadBlocks_DMA(buff, sector, count);
			return RES_OK;
		}
		
	}

	return RES_PARERR;
}

 这里需要注意的是FLASH和SD卡里面的两个函数是不太一样的,FLASH里面的函数只能写一个扇区,要想写多个扇区那你就得循环写,在FATFS文件系统里面,他的sector地址是从0-0xffffffff他是一个连续的地址,一个sector就是一个地址,但是在FLASH里面他的最小单位不是扇区,他有比扇区更小的操作也就是页,但是他最小的单位是可以按字节来读取的,也就是说他是一个字节一个地址,如果我们直接将FATFS里面的地址传过来,在FLASH里面他就会认为是字节地址,因此我们需要一个地址的偏移,也就是FLASH里面一个扇区的大小,也就是4096.理解这里你需要知道他们呢两个的基本操作的单元是不一样的。但是在SD卡里面就不需要这样的偏移,因为SD卡里面他就是以扇区为大小来进行读取的。也就是SD卡里面每个地址是512个字节。他的最小读写单元就是512个字节,也就是一个扇区。因此我们在传入参数的时候不需要将地址进行偏移。而且SD卡的读写函数是一次可以读多个扇区的,因此可以直接将count传入,他也是可以直接读的。其实说白了就是如果你的最小读写单元就是512个字节那么你就不需要地址的偏倚,否则你就要根据自己设置的扇区大小进行偏移。

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
	uint32_t i = 0;
	uint8_t result = 0;

	switch (pdrv) {
		case DEV_FALSH :{
			uint32_t addr = sector*SECTOR_SIZE;
			for (i=0; i<count; i++)
			{
				EN25QXX_Erase_Sector(addr);
				EN25QXX_Write_Sector((BYTE *)buff, addr, SECTOR_SIZE);
				addr += SECTOR_SIZE;
				buff += SECTOR_SIZE;
			}
			return RES_OK;
		}
		case DEV_SD :{
			SD_WriteBlocks_DMA((BYTE *)buff, sector, count);
			return RES_OK;
		}
	}

	return RES_PARERR;
}
DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
//	DRESULT res = 0;
//	int result;

	switch (pdrv) {
		case DEV_FALSH :{
			switch (cmd){
				case CTRL_SYNC:
					return RES_OK;
				case GET_SECTOR_COUNT:{
					*(DWORD *)buff = 4096;     //表示扇区的个数
					return RES_OK;
				}		
				case GET_SECTOR_SIZE:{
					*(WORD *)buff = SECTOR_SIZE;  //表示每个扇区的大小
					return RES_OK;
				}	
			}
		}
		case DEV_SD :{
			switch (cmd){
				case CTRL_SYNC:
					return RES_OK;
				case GET_SECTOR_COUNT:{
					*(DWORD *)buff = 31116288;     //表示扇区的个数
					return RES_OK;
				}		
				case GET_SECTOR_SIZE:{
					*(WORD *)buff = 512;  //表示每个扇区的大小
					return RES_OK;
				}	
				case GET_BLOCK_SIZE:{
					*(DWORD *)buff = 512;  //表示每个扇区的大小
					return RES_OK;
				}
				default :
					return RES_PARERR;
			}
		}
	}

	return RES_PARERR;
}

上面这个函数的实现我是直接将数据写到里面的,这样操作如果换了别的SD卡,就完蛋了,严谨一点的操作是使用相关函数,读出来。我这里就比较粗糙的实现了,主打一个能用就行。

四、进行挂载

如果你的挂载直接就返回0,那么恭喜你直接就成功了,但是在大多数的情况下我们的挂载是不能成功的。下面就针对几个返回值进行故障的排除。

f_mount返回11  也就是你要使用几个外设,如果你就一个SD卡,那么问题,如果有2个你这里就得改成2,不然就会返回错误代码11

 f_mount返回1,当这些函数没有正确的返回值就会报这个错误,我将哪里注释掉之后,就会产生这个错误。

还有一种就是返回值是13的错误,他的意思是卡上面没有文件系统导致的。但是我将卡格式化后发现,还是识别不上。还是返回13。经过一夜的查找发现是DMA设置那里没有设置地址的递增,就导致他一次只能读几个字节,后面的读写完全就是不正常的,内存里面是有一个缓冲区的,如果地址传完不发生偏移,那这个缓冲区就是没有意义的,因此只要你传入的DMA里面的buf[]数组里面的元素不止一个那么这里就得设置地址偏移。

	res = f_mount(&fs, "1:/", 1);

 一般来讲只要能挂载成功,其他的函数都是可以正常工作的,前提是你挂载的时候,后面选项里面一定要是 1,如果是0,就算有问题,他写会显示挂载成功的,这时候肯定是不行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/944058.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【知识】cuda检测GPU是否支持P2P通信及一些注意事项

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 代码流程 先检查所有GPU之间是否支持P2P通信&#xff1b;然后尝试启用GPU之间的P2P通信&#xff1b;再次检查所有GPU之间是否支持P2P通信。 test.cu&…

Mysql大数据量表分页查询性能优化

一、模拟场景 1、产品表t_product,数据量500万+ 2、未做任何优化前,cout查询时间大约4秒;LIMIT offset, count 时,offset 值较大时查询时间越久。 count查询 SELECT COUNT(*) AS total FROM t_product WHERE deleted = 0 AND tenant_id = 1 分页查询 SELECT * FROM t_…

go语言的成神之路-筑基篇-对文件的操作

目录 一、对文件的读写 Reader?接口 ?Writer接口 copy接口 bufio的使用 ioutil库? 二、cat命令 三、包 1. 包的声明 2. 导入包 3. 包的可见性 4. 包的初始化 5. 标准库包 6. 第三方包 ?7. 包的组织 8. 包的别名 9. 包的路径 10. 包的版本管理 四、go mo…

Qt 应用程序转换为服务

一、在 Windows 上将 Qt 应用程序转换为服务 方法1&#xff1a; 创建一个 Windows 服务应用程序&#xff1a; Windows 服务应用程序是一个没有用户界面的后台进程&#xff0c;通常由 Win32 Service 模板创建&#xff0c;或者直接编写 main() 函数以实现服务逻辑。 修改 Qt 应…

【HarmonyOS之旅】HarmonyOS概述(一)

目录 1 -> HarmonyOS简介 2 -> HarmonyOS发展历程 3 -> HarmonyOS技术特性 3.1 -> 硬件互助&#xff0c;资源共享 3.1.1 -> 分布式软总线 3.1.2 -> 分布式设备虚拟化 3.1.3 -> 分布式数据管理 3.1.4 -> 分布式任务调度 3.1.5 -> 分布式连接…

5、栈应用-表达式求值

本章内容使用上述栈结构函数&#xff0c;来完成表达式求值操作。 表达式例如&#xff1a;3*(7-2) 或者 (0-12)*((5-3)*32)/(22) 。 1、实现思路 a、建立OPTR&#xff08;运算符&#xff09;和OPND&#xff08;数字&#xff09;两个栈&#xff0c;后输入字符串以结束 b、自左向…

【软件】教务系统成绩提交工具使用步骤

【软件】教务系统成绩提交工具使用步骤 零、快速开始 安装 与大多数软件一样&#xff0c;安装步骤很简单&#xff0c;一直点击“下一步”即可快速完成安装&#xff0c;安装完成后&#xff0c;在桌面会有一个软件图标&#xff0c;双击即可打开软件主界面。 导入成绩到Excel中…

书签管理工具的使用技巧

分类与筛选技巧 多层级分类&#xff1a;创建多层级的文件夹结构&#xff0c;如先按大的主题分类&#xff0c;再在每个主题下细分小类。例如&#xff0c;先创建 “工作”“学习”“生活” 等大文件夹&#xff0c;在 “工作” 文件夹下再细分 “项目文档”“办公软件”“行业资讯…

如何安全获取股票实时数据API并在服务器运行?

以下是安全获取股票实时数据 API 并在服务器运行的方法&#xff1a; 选择合适的券商或交易平台 评估自身需求&#xff1a;明确自己的交易策略、交易品种、交易频率等需求&#xff0c;以及对 股票api 的功能、性能、稳定性等方面的要求。调研券商或平台&#xff1a;了解不同券商…

图像处理-Ch2-空间域的图像增强

Ch2 空间域的图像增强 文章目录 Ch2 空间域的图像增强Background灰度变换函数(Gray-level Transformation)对数变换(Logarithmic)幂律变换(Power-Law)分段线性变换函数(Piecewise-Linear)对比度拉伸(Contrast-Stretching)灰度级分层(Gray-level Slicing) 直方图处理(Histogram …

告别 Shuffle!深入探索 Spark 的 SPJ 技术

随着 Spark > 3.3&#xff08;在 3.4 中更加成熟&#xff09;中引入的存储分区连接&#xff08;Storage Partition Join&#xff0c;SPJ&#xff09;优化技术&#xff0c;您可以在不触发 Shuffle 的情况下对分区的数据源 V2 表执行连接操作&#xff08;当然&#xff0c;需要…

解决Springboot整合Shiro自定义SessionDAO+Redis管理会话,登录后不跳转首页

解决Springboot整合Shiro自定义SessionDAORedis管理会话&#xff0c;登录后不跳转首页 问题发现问题解决 问题发现 在Shiro框架中&#xff0c;SessionDAO的默认实现是MemorySessionDAO。它内部维护了一个ConcurrentMap来保存session数据&#xff0c;即将session数据缓存在内存…

【蓝桥杯——物联网设计与开发】基础模块8 - RTC

目录 一、RTC &#xff08;1&#xff09;资源介绍 &#x1f505;简介 &#x1f505;时钟与分频&#xff08;十分重要‼️&#xff09; &#xff08;2&#xff09;STM32CubeMX 软件配置 &#xff08;3&#xff09;代码编写 &#xff08;4&#xff09;实验现象 二、RTC接口…

API安全学习笔记

必要性 前后端分离已经成为web的一大趋势&#xff0c;通过TomcatNgnix(也可以中间有个Node.js)&#xff0c;有效地进行解耦。并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务&#xff08;多种客户端&#xff0c;例如&#xff1a;浏览器&#x…

2011-2020年各省城镇职工基本医疗保险年末参保人数数据

2011-2020年各省城镇职工基本医疗保险年末参保人数数据 1、时间&#xff1a;2011-2020年 2、来源&#xff1a;国家统计局 3、指标&#xff1a;省份、时间、城镇职工基本医疗保险年末参保人数 4、范围&#xff1a;31省 5、指标解释&#xff1a;参保人数指报告期末按国家有关…

【蓝桥杯——物联网设计与开发】拓展模块4 - 脉冲模块

目录 一、脉冲模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 &#x1f505;采集原理 &#xff08;2&#xff09;STM32CubeMX 软件配置 &#xff08;3&#xff09;代码编写 &#xff08;4&#xff09;实验现象 二、脉冲模块接口函数封装 三、踩坑日记 &a…

Kubernetes Gateway API-2-跨命名空间路由

1 跨命名空间路由 Gateway API 具有跨命名空间路由的核心支持。当多个用户或团队共享底层网络基础设施时,这很有用,但必须对控制和配置进行分段,以尽量减少访问和容错域。 Gateway 和 Route(HTTPRoute,TCPRoute,GRPCRoute) 可以部署到不同的命名空间中,路由可以跨命名空间…

Windows Powershell实战指南(未完成)

目前只作简单了解&#xff0c;开始吧。 一、初识Powershell 目标 初步认识 Powershell和其集成环境 Ise&#xff0c;学会基本设置 实验 我们从简单的例子开始&#xff1a;希望你能从控制台和ISE的配置中实现相同的结果。然后按照下面五步进行。 &#xff08;1&#xff09;选…

Android着色器SweepGradient渐变圆环,Kotlin

Android着色器SweepGradient渐变圆环&#xff0c;Kotlin import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Path import android.graphics.SweepGradient import android…

项目上传到gitcode

首先需要在个人设置里面找到令牌 记住自己的账号和访问令牌&#xff08;一长串&#xff09;&#xff0c;后面git要输入这个&#xff0c; 账号是下面这个 来到自己的仓库 #查看远程仓库&#xff0c;是不是自己的云仓库 git remote -v # 创建新分支 git checkout -b llf # 三步…