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

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

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

相关文章

5、栈应用-表达式求值

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

【递归与回溯深度解析:经典题解精讲(下篇)】—— Leetcode

文章目录 有效的数独解数独单词搜索黄金矿工不同的路径||| 有效的数独 递归解法思路 将每个数独的格子视为一个任务&#xff0c;依次检查每个格子是否合法。 如果当前格子中的数字违反了数独规则&#xff08;在行、列或 33 小方块中重复&#xff09;&#xff0c;直接返回 Fals…

Llama 3 预训练(二)

目录 3. 预训练 3.1 预训练数据 3.1.1 网络数据筛选 PII 和安全过滤 文本提取与清理 去重&#xff08;De-duplication&#xff09; 启发式过滤&#xff08;Heuristic Filtering&#xff09; 基于模型的质量过滤 代码和数学推理数据处理 多语言数据处理 3.1.2 确定数…

双指针——查找总价格为目标值的两个商品

一.题目描述 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 二.题目解析 这个题目非常简单&#xff0c;其实就是判断有没有两个数加起来等于target。 三.算法解析 1.暴力解法 暴力解法的话我们可以枚举出所有的情况&#xff0c;然后判…

sqlserver镜像设置

本案例是双机热备&#xff0c;只设置主体服务器&#xff08;主&#xff09;和镜像服务器&#xff08;从&#xff09;&#xff0c;不设置见证服务器 设置镜像前先检查是否启用了 主从服务器数据库的 TCP/IP协议 和 RemoteDAC &#xff08;1&#xff09;打开SQL Server配置管理器…

Elasticsearch:analyzer(分析器)

一、概述 可用于将字符串字段转换为单独的术语&#xff1a; 添加到倒排索引中&#xff0c;以便文档可搜索。级查询&#xff08;如 生成搜索词的 match查询&#xff09;使用。 分析器分为内置分析器和自定义的分析器&#xff0c;它们都是由若干个字符过滤器&#xff08;chara…

ElementPlus 自定义封装 el-date-picker 的快捷功能

文章目录 需求分析 需求 分析 我们看到官网上给出的案例如下&#xff0c;但是不太满足我们用户想要的快捷功能&#xff0c;因为不太多&#xff0c;因此需要我们自己封装一些&#xff0c;方法如下 外部自定义该组件的快捷内容 export const getPickerOptions () > {cons…

低代码开发平台排名2024

低代码开发平台在过去几年中迅速崛起&#xff0c;成为企业数字化转型的重要工具。这些平台通过可视化界面和拖放组件&#xff0c;使业务人员和技术人员都能快速构建应用程序&#xff0c;大大缩短了开发周期。以下是一些在2024年值得关注和使用的低代码开发平台。 一、Zoho Cre…

计算机网络——期末复习(4)协议或技术汇总、思维导图

思维导图 协议与技术 物理层通信协议&#xff1a;曼彻斯特编码链路层通信协议&#xff1a;CSMA/CD &#xff08;1&#xff09;停止-等待协议&#xff08;属于自动请求重传ARQ协议&#xff09;&#xff1a;确认、否认、重传、超时重传、 &#xff08;2&#xff09;回退N帧协…

【MySQL学习笔记】关于索引

文章目录 【MySQL学习笔记】关于索引1.索引数据结构2.索引存储3.联合索引3.1 联合索引的b树结构3.2 索引覆盖&#xff1f;回表&#xff1f;3.3 联合索引最左匹配原则3.5 索引下推 4.索引失效 【MySQL学习笔记】关于索引 1.索引数据结构 索引是一种能提高查询速度的数据结构。…

D104【python 接口自动化学习】- pytest进阶参数化用法

day104 pytest参数化parametrize单参数 学习日期&#xff1a;20241223 学习目标&#xff1a;pytest基础用法 -- pytest参数化parametrize单参数 学习笔记&#xff1a; 参数化 parametrize 参数化可以组装测试数据&#xff0c;在测试前定义好测试数据&#xff0c;并在测试用…

第T4周:TensorFlow实现猴痘识别(Tensorboard的使用)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标&#xff1a; 1、学习tensorboard的使用 具体实现&#xff1a; &#xff08;一&#xff09;环境&#xff1a; 语言环境&#xff1a;Python 3.10 编 译 器…

Docker-构建自己的Web-Linux系统-镜像webtop:ubuntu-kde

介绍 安装自己的linux-server,可以作为学习使用&#xff0c;web方式访问&#xff0c;基于ubuntu构建开源项目 https://github.com/linuxserver/docker-webtop安装 docker run -d -p 1336:3000 -e PASSWORD123456 --name webtop lscr.io/linuxserver/webtop:ubuntu-kde登录 …

小米路由器开启SSH,配置阿里云ddns,开启外网访问SSH和WEB管理界面

文章目录 前言一、开启SSH二、配置阿里云ddns1.准备工作2.创建ddns脚本3.添加定时任务 三、开启外网访问SSH和WEB管理界面1、解除WEB管理页面访问限制2.手动添加防火墙端口转发规则&#xff0c;开启外网访问WEB管理和SSH 前言 例如&#xff1a;随着人工智能的不断发展&#xf…

什么是ESC ---- 防止车辆打滑并提高驾驶时稳定性的技术

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…

LinkedList类 (链表)

目录 一. LinkedList 基本介绍 二. LinkedList 中的法及其应用 1. 添加元素 (1) add() (2) addAll() (3) addFirst() (4) addLast() 2. 删除元素 (1) remove() (2) removeAll() (3) removeFirst() (4) removeLast() 3. 遍历元素 (1) for 循环遍历 (2) for - each …

复习打卡大数据篇——Hadoop MapReduce

目录 1. MapReduce基本介绍 2. MapReduce原理 1. MapReduce基本介绍 什么是MapReduce MapReduce是一个分布式运算程序的编程框架&#xff0c;核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c;并发运行在Hadoop集群上。 MapRed…

Java基础知识(四) -- 面向对象(下)

1.类变量和类方法 1.1 类变量背景 有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩? 思路分析: 核心在于如何让变量count被所有对象共享 public class Child {private String name;// 定义静态变量(所有Child对象共享)public static int count 0;p…

SpringBoot中使用TraceId进行日志追踪

**查询日志的痛点&#xff1a;**项目中每当我们查询日志的时候都是看前端请求什么接口&#xff0c;根据一些关键字进入服务器查询日志中是否有这个关键字&#xff0c;然而这个关键字在日志里面并不是唯一的&#xff0c;所以要生成一个唯一的标识&#xff0c;每一次请求都是唯一…

C++类与对象上

1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题 例如洗衣服&#xff1a; C是基于面向对象的&#xff0c;关注的是对象&#xff0c;讲一件事拆分成不同的对象&#xff0c;靠对…