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

news2024/12/29 0:44:12

一、下载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,就算有问题,他写会显示挂载成功的,这时候肯定是不行的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ollama+OpenWebUI+llama3本地部署

引言 llama3在4月19日刚刚发布&#xff0c;官方的对比结果中在开源模型中堪称世界第一&#xff0c;整好周六日有时间&#xff0c;在魔搭社区上测试一下 2 安装Ollama 2.1 下载Ollama 登录Ollama官网下载Ollama安装包 GitHub&#xff1a;https://github.com/ollama/ollama?t…

新品:SA628F39大功率全双工音频传输模块

SA628F39是一款高集成度的8W大功率全双工无线数据语音一体通话模块&#xff0c;专为高效、稳定的远程通信设计。该模块内置高速微控制器、高性能射频芯片、功率放大器、ESD静电保护和硬件看门狗芯片&#xff0c;具备反接保护、过流过压保护和防死机保护等多重安全功能&#xff…

Unity EasyAR入门教程

文章目录 Easy不用下载盗版安装SDK注册应用ID最简单的识别注意点 Easy不用下载盗版 EasyAR可以免费试用&#xff0c;如果不在乎水印&#xff0c;直接去官网下载即可 EasyAR官网 安装SDK 先下载&#xff0c;官网找到下载页&#xff0c;如下选择 下载后不是普通的unityPackag…

ID卡网络读卡器Python小程序开发

UDP网络读卡器Python示例代码。 主页UI设计界面&#xff1a; UI代码&#xff1a; from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Frame(object):def setupUi(self, Frame):Frame.setObjectName("Frame")Frame.resize(1082, 685)font QtGui.QFont()font.set…

yarn list --pattern vuex-module-decorators

dgqdgqdeMac-mini spid-admin % yarn list --pattern vuex-module-decorators yarn list v1.22.22 └─ vuex-module-decorators0.16.1 ✨ Done in 0.24s.好的&#xff0c;这段代码是一个典型的 Vuex 模块定义&#xff0c;使用了 vuex-module-decorators 库。这个库为 Vuex 提…

微机接口课设——基于Proteus和8086的打地鼠设计(8255、8253、8259)Proteus中Unknown 1-byte opcode / Unknown 2-byte opcode错误

原理图设计 汇编代码 ; I/O 端口地址定义 IOY0 EQU 0600H IOY1 EQU 0640H IOY2 EQU 0680HMY8255_A EQU IOY000H*2 ; 8255 A 口端口地址 MY8255_B EQU IOY001H*2 ; 8255 B 口端口地址 MY8255_C EQU IOY002H*2 ; 8255 C 口端口地址 MY8255_MODE EQU IOY003H*2 ; …

【HENU】河南大学计院2024 计算机网络 期末复习知识点

和光同尘_我的个人主页 一直游到海水变蓝。 计网复习 第一章互联网组成类别交换方式分组交换的要点&#xff1a;分组交换的优点&#xff1a; 网络性能指标体系结构网络协议五层协议 第二章&#xff1a;物理层物理层的主要任务&#xff08;四大特性&#xff09;通信的三种方式…

chatwoot 开源客服系统搭建

1. 准备开源客服系统&#xff08;我是用的Chatwoot &#xff09; 可以选择以下开源客服系统作为基础&#xff1a; Chatwoot: 功能强大&#xff0c;支持多渠道客户对接&#xff0c;&#xff08;支持app&#xff0c;web&#xff09;。Zammad: 现代的开源工单系统。FreeScout: 免…

python爬虫----爬取视频实战

python爬虫-爬取视频 本次爬取&#xff0c;还是运用的是requests方法 首先进入此网站中&#xff0c;选取你想要爬取的视频&#xff0c;进入视频页面&#xff0c;按F12&#xff0c;将网络中的名称栏向上拉找到第一个并点击&#xff0c;可以在标头中&#xff0c;找到后续我们想要…

【PPTist】表格功能

前言&#xff1a;这篇文章来探讨一下表格功能是怎么实现的吧&#xff01; 一、插入表格 我们可以看到&#xff0c;鼠标移动到菜单项上出现的提示语是“插入表格” 那么就全局搜索一下&#xff0c;就发现这个菜单在 src/views/Editor/CanvasTool/index.vue 文件中 <Popov…

Web安全攻防入门教程——hvv行动详解

Web安全攻防入门教程 Web安全攻防是指在Web应用程序的开发、部署和运行过程中&#xff0c;保护Web应用免受攻击和恶意行为的技术与策略。这个领域不仅涉及防御措施的实现&#xff0c;还包括通过渗透测试、漏洞挖掘和模拟攻击来识别潜在的安全问题。 本教程将带你入门Web安全攻防…

游戏开发线性空间下PS工作流程

前言 使用基于物理的渲染&#xff0c;为了保证光照计算的准确&#xff0c;需要使用线性空间&#xff1b; 使用线性空间会带来一个问题&#xff0c;ui 在游戏引擎中的渲染结果与 PS 中的不一致&#xff1a; PS&#xff08;颜色空间默认是sRGB伽马空间&#xff09;&#xff1a…

Segment Routing Overview

大家觉得有意义和帮助记得及时关注和点赞!!! Segment Routing (SR) 是近年来网络领域的一项新技术&#xff0c;“segment” 在这里 指代网络隔离技术&#xff0c;例如 MPLS。如果快速回顾网络设计在过去几十年的 发展&#xff0c;我们会发现 SR 也许是正在形成的第三代网络设计…

【连续学习之随机初始化算法 】2024Nature期刊论文Loss of plasticity in deep continual learning

1 介绍 年份&#xff1a;2024 期刊&#xff1a;Nature Dohare S, Hernandez-Garcia J F, Lan Q, et al. Loss of plasticity in deep continual learning[J]. Nature, 2024, 632(8026): 768-774. 本文提出的算法是“持续反向传播”&#xff08;continual backpropagation&a…

【NODE】01-fs和path常用知识点

前言 最近在使用express-generator知识进行搭建前后端通信&#xff0c;其中有些知识点涉及到nodejs的fs和path核心模块&#xff0c;因此另写一篇文章进行介绍和代码案例练习。 fs&#xff08;文件系统&#xff09;和 path 是 Node.js 的核心模块&#xff0c;用于文件操作和路径…

两分钟解决:vscode卡在设置SSH主机,VS Code-正在本地初始化VSCode服务器

问题原因 remote-ssh还是有一些bug的&#xff0c;在跟新之后可能会一直加载初始化SSH主机解决方案 1.打开终端2.登录链接vscode的账号&#xff0c;到家目录下3.找到 .vscode-server文件,删掉这个文件4.重启 vscode 就没问题了

干货ScottPlot4向ScottPlot5迁移

干货ScottPlot4向ScottPlot5迁移 干货满满1.背景2.需求的引出3.先说结论1.好消息2.坏消息 4.迁移的部分笔记ColorScottPlot.PlottableScottPlot.Plottables中的对象如何定义添加 ScottPlot.Plottable.ScatterPlot 对象ScatterPolygonMarker也类似 Scatter的marker formsPlot1Re…

Github优质项目推荐(第九期)

文章目录 Github优质项目推荐&#xff08;第九期&#xff09;一、【tldraw】&#xff0c;37.1k stars - 在 React 中创建无限画布体验的库二、【zapret】&#xff0c;9.1k stars - 独立&#xff08;无需第三方服务器&#xff09;DPI 规避工具三、【uBlock】&#xff0c;48.3k s…

学习threejs,THREE.PlaneGeometry 二维平面几何体

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️HREE.PlaneGeometry 二维平…

力扣矩阵-算法模版总结

lc-73.矩阵置零-(时隔14天)-12.27 思路&#xff1a;(23min22s) 1.直接遍历遇0将行列设0肯定不行&#xff0c;会影响后续判断&#xff0c;题目又要求原地算法&#xff0c;那么进一步考虑是否可以将元素为0&#xff0c;其行列需要设为0的位置给存储下来&#xff0c;最后再遍历根据…