STM32完全学习——FLASH上FATFS文件管理系统

一、需要移植的接口

我们通过看官网的手册,可以看到我们只要完成下面函数的实现,就可以完成移植。我们这里只移植前5个函数,获取时间的函数我们不在这里移植。

二、移植接口函数

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
	switch (pdrv) {
		case DEV_FALSH :
			stat = EN25QXX_ReadSR();

			return stat;

		return stat;
	}
	return STA_NOINIT;
}
//获取存储器状态的函数
uint8_t EN25QXX_ReadSR(void)   
{  
	uint8_t byte = 0;   
	FLASH_CS = 0;                            //使能器件   
	SPI1_ReadWriteByte(EN25X_ReadStatusReg);    //发送读取状态寄存器命令    
	byte = SPI1_ReadWriteByte(0Xff);             //读取一个字节  
	FLASH_CS = 1;                            //取消片选     
	return byte;   
} 
DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat = 0;;
	if (pdrv == DEV_FALSH)  //由于我只里关于FLASH的初始化,在main函数里面已经完成了,这里直接返回就行
	{
		return stat;
	}

	return STA_NOINIT;
}

 需要注意的是读和写的函数里面的LBA_t sector这个程序内部代表的是扇区号,而不是扇区地址,但是我们的FLASH写和读函数里面传的参数是地址,因此一定要先将扇区号转化成对应的地址然后才可以进行传参。count代表的是扇区的个数而不是我们要写的字节数。而我们的读函数一次是读一个扇区,因此count是多少就代表我们要读多少个扇区。读完一个扇区后一定要将地址和数据进行更新,虽然在FALSH层面上读是不会限制大小的,但是由于我们是给FATFS文件系统使用,因此我们就要写成按一个扇区来读。

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;
	uint32_t addr = sector*SECTOR_SIZE;
	if (pdrv == DEV_FALSH)
	{
		for (i=0; i<count; i++)
		{
			EN25QXX_Read((BYTE *)buff, addr, SECTOR_SIZE);  //每运行一次就读一个扇区
			addr += SECTOR_SIZE;
			buff += SECTOR_SIZE;

		}
		return RES_OK;
	}


	return RES_PARERR;
}


//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void EN25QXX_Read(uint8_t *pBuffer,uint32_t ReadAddr, uint16_t NumByteToRead)   
{ 
 	uint16_t i;   										    
	FLASH_CS = 0;                            //使能器件   
    SPI1_ReadWriteByte(EN25X_ReadData);         //发送读取命令   
    SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>16));  //发送24bit地址    
    SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
    SPI1_ReadWriteByte((uint8_t)ReadAddr);   
    for(i=0; i<NumByteToRead; i++)
	{ 
        pBuffer[i] = SPI1_ReadWriteByte(0XFF);   //循环读数 
    }
	FLASH_CS = 1;  				    	      
} 


//SPI1 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
	HAL_SPI_TransmitReceive_DMA(&hspi1, &TxData, &Rxdata, 1);
	delay_us(1);   //必须的需要这个延时,不然速度太快了

 	return Rxdata;          		    //返回收到的数据		
}



 这里需要注意的是FLASH在每次写之前一定要先进行擦除,才可以写,因此我们这里还需要一个按扇区擦除的函数。

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;
	uint32_t addr = sector*SECTOR_SIZE;
	if (pdrv == DEV_FALSH)
	{
		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;
	}
	


	return RES_PARERR;
}

//擦除一个扇区
//Dst_Addr:扇区地址 根据实际容量设置
//擦除一个山区的最少时间:150ms
void EN25QXX_Erase_Sector(uint32_t Dst_Addr)   
{  
	//监视falsh擦除情况,测试用   
// 	printf("fe:%x\r\n",Dst_Addr);	  
    EN25QXX_Write_Enable();                  //SET WEL 	 
    EN25QXX_Wait_Busy();   
  	FLASH_CS = 0;                            //使能器件   
    SPI1_ReadWriteByte(EN25X_SectorErase);      //发送扇区擦除指令 
    SPI1_ReadWriteByte((uint8_t)((Dst_Addr)>>16));  //发送24bit地址    
    SPI1_ReadWriteByte((uint8_t)((Dst_Addr)>>8));   
    SPI1_ReadWriteByte((uint8_t)Dst_Addr);  
	FLASH_CS = 1;                            //取消片选     	      
    EN25QXX_Wait_Busy();   				   //等待擦除完成
}
DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	if (pdrv == DEV_FALSH)
	{
		switch (cmd){
			case CTRL_SYNC:               //确保设备已完成挂起的写入过程。如果磁盘I/O层或存储设备具有回写式缓存,则脏缓存数据必须立即提交到介质。如果对介质的每个写操作都在以下时间内完成,则此命令不执行任何操作 disk_write 功能。
				return RES_OK;
			case GET_SECTOR_COUNT:{
				*(DWORD *)buff = 4096;     //表示扇区的个数
				return RES_OK;
			}		
			case GET_SECTOR_SIZE:{
				*(WORD *)buff = SECTOR_SIZE;  //表示每个扇区的大小
				return RES_OK;
			}	
		}
		return RES_PARERR;
	}
	return RES_PARERR;
}

三、注意事项

移植完上面的接口函数后,因为我们无法手动给FLASH里面格式化成FAT32文件系统,因此我们需要使用f_mkfs()函数,来完成格式化。当你使用这个函数的时候,你会发现会报错,那是因为在ffconf.h里面的相关配置没有打开。

 如果你在编译的过程中发现下面的错误,那也是因为配置里面没有关闭使用时间这个选项

 

如果发现运行过程中,程序老是死在某个地方,他不是死循环,而是直接程序就不动了。那有可能是因为扇区的大小设置的不对,因为FATFS默认情况将512个字节作为一个簇,但是我们的FLASH里面的最小擦出的单元是一个扇区,而我们的一个扇区大小是4KB也就是4096个字节。因此我们要将扇区范围的上限提高一下。

res = f_mkfs("0:/", 0, work, 4096);
这里传的参数也是一个扇区的大小,如果不对格式化会有问题。

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

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

相关文章

pyqt5冻结+分页表

逻辑代码 # -*- coding: utf-8 -*- import sys,time,copy from PyQt5.QtWidgets import QWidget,QApplication, QDesktopWidget,QTableWidgetItem from QhTableWidgetQGN import Ui_QhTableWidgetQGN from PyQt5.QtCore import Qt from PyQt5 import QtCore, QtGui, QtWidgets…

Windows 使用 非安装版MySQL 8

1.下载MySQL 8 https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.40-winx64.zip 2.创建my.ini 下载解压后&#xff0c;发现根目录没有my.ini文件&#xff0c;需手动创建 my.ini # For advice on how to change settings please see # http://dev.mysql.com/doc/refma…

海外招聘丨 苏黎世联邦理工学院—机器学习在社会和政治科学中的应用博士后

雇主简介 苏黎世联邦理工学院是世界领先的科技大学之一。我们以优质的教育、尖端的基础研究和将新知识直接转化为社会而闻名。来自 120 多个国家的 30,000 多名学生认为我们的大学是一个鼓励独立思考和激励卓越的环境的地方。 我们位于欧洲中心&#xff0c;但与世界各地建立联…

微信小程序中遇到过的问题

记录微信小程序中遇到的问题&#xff08;持续更新ing&#xff09; 问题描述&#xff1a;1. WXML中无法直接调用JavaScript方法。2. css中无法直接引用背景图片。3. 关于右上角胶囊按钮。4. 数据绑定问题。5. 事件处理问题。 问题描述&#xff1a; 1. WXML中无法直接调用JavaSc…

idea 8年使用整理

文章目录 前言idea 8年使用整理1. 覆盖application配置2. 启动的时候设置编辑空间大小&#xff0c;并忽略最大空间3. 查询类的关系4. 查看这个方法的引用关系5. 查看方法的调用关系5.1. 查看被调用关系5.2. 查看调用关系 6. 方法分隔线7. 选择快捷键类型8. 代码预览插件9. JReb…

RAGFLOW使用笔记【更新ing】

0.引言 本文记录使用RAGFLOW的一些问题以及解决办法&#xff0c;它以笔记的形式存在&#xff0c;方便我以后回顾自己的学习工作。 1.RAGFLOW上传文件大小默认是128M,如何修改上传文件大小&#xff1f; 更新ragflow/docker/.env中的MAX_CONTENT_LENGTH 环境变量 然后同步更新…

ubuntu22.04安装PaddleX3

PaddleOCR 安装过程可以参考PaddleX本地安装教程 我的电脑环境配置&#xff1a; ubuntu22.04 cuda11.8&#xff08;之前安装的是12.4没有匹配的paddle-gpu;这里改成11.8&#xff09; 一、安装基础环境 1、 conda create -n ppx1 python3.10 2、 conda activate ppx1 3、…

Android 之 Activity 的启动模式(launchMode)

一、Activity 启动模式 在实际项目中&#xff0c;应该根据项目的实际需要来为每个 Activity 指定恰当的启动模式 launchMode。启动模式一共有四种&#xff0c;分别是 standard、singleTop、singleTask 和 singleInstance。可以在 AndroidManifest.xml 中通过给 <activity&g…

软件老化分析

软件老化 课程&#xff1a;软件质量分析 作业 解答 Python代码如下&#xff1a; n int(input("类别数&#xff1a;")) theta list(map(float, input("各个类别的权重&#xff1a;").split())) m list(map(int, input("各个类别的度量元数量&…

Jenkins 构建流水线

在 Linux 系统上安装 Jenkins 服务&#xff0c;以及配置自动化构建项目 前置准备环境&#xff1a;docker、docker-compose、jdk、maven 一、环境搭建 1. Jenkins 安装 &#xff08;1&#xff09;拉取镜像 # 安装镜像包&#xff0c;默认安装最新版本 docker pull jenkins/jen…

5G学习笔记之Non-Public Network

目录 0. NPN系列 1. 概述 2. SNPN 2.1 SNPN概述 2.2 SNPN架构 2.3 SNPN部署 2.3.1 完全独立 2.3.2 共享PLMN基站 2.3.3 共享PLMN基站和PLMN频谱 3. PNI-NPN 3.1 PNI-NPN概述 3.2 PNI-NPN部署 3.2.1 UPF独立 3.2.2 完全共享 0. NPN系列 1. NPN概述 2. NPN R18 3. 【SNPN系列】S…

若依plus apifox导入接口显示为空

项目已经正常启动 访问接口有些没问题&#xff0c;有些有问题 其他模块都可以正常导入 解决&#xff1a;

elementPlus消息组件多按钮案例

let customClass zsl-el-message-box efb.messageBox({title: 操作提示,showConfirmButton: false,customClass,message: efb.VNode(div, null, [efb.VNode(style, null, .${customClass} .el-message-box__message {width: 100%;}),efb.VNode(div, null, hello world),efb.VN…

计算机网络:应用层 —— 网络应用模式

文章目录 客户—服务器方式和对等方式客户/服务器方式 (C/S方式)工作流程特点 对等方式 (P2P方式)工作流程P2P 应用特点 客户—服务器方式和对等方式 网络应用程序运行在处于网络边缘的不同的端系统上&#xff0c;通过彼此间的通信来共同完成某项任务。 开发一种新的网络应用…

科技创新 数智未来|清科·沙丘投研院走进竹云

12月20日&#xff0c;清科沙丘投研院带领企投家团队走进竹云交流分享&#xff0c;聚焦技术创新、企业数字化管理、行业前沿应用案例等热点议题&#xff0c;深入探讨数字技术如何点燃企业高质量发展的澎湃动力&#xff0c;共话企业数字化、智能化发展之道。 达晨财智股权管理部…

外连接转AntiJoin的应用场景与限制条件 | OceanBase SQL 查询改写系列

在《SQL 改写系列&#xff1a;外连接转内连接的常见场景与错误》一文中&#xff0c;我们了解到谓词条件可以过滤掉连接结果中的 null 情形的&#xff0c;将外连接转化为内连接的做法是可行的&#xff0c;正如图1中路径(a)所示。此时&#xff0c;敏锐的你或许会进一步思考&#…

Java - 日志体系_Apache Commons Logging(JCL)日志接口库

文章目录 官网1. 什么是JCL&#xff1f;2. JCL的主要特点3. JCL的核心组件4. JCL的实现机制5. SimpleLog 简介6. CodeExample 1 &#xff1a; 默认日志实现 (JCL 1.3.2版本)Example 2 &#xff1a; JCL (1.2版本&#xff09; Log4J 【安全风险高&#xff0c;请勿使用】 7. 使用…

mavlink移植到单片机stm32f103c8t6,实现接收和发送数据

前言&#xff1a; 好久没更新博客了&#xff0c;这两个月真的是异常的忙&#xff0c;白天要忙着公司里的事&#xff0c;晚上还要忙着修改小论文&#xff0c;一点自己的时间都没有了&#xff0c;不过确确实实是学到了很多东西&#xff0c;对无人机的技术研究也更深了一些。不过好…

GitLab的安装与卸载

目录 GitLab安装 GitLab使用 使用前可选操作 修改web端口 修改Prometheus端口 使用方法 GitLab的卸载 环境说明 系统版本 CentOS 7.2 x86_64 软件版本 gitlab-ce-10.8.4 GitLab安装 Gitlab的rpm包集成了它需要的软件&#xff0c;简化了安装步骤&#xff0c;所以直接…

子网掩码计算route命令

子网掩码 - 站长工具 1.子网掩码 子网掩码就是用来遮掩IP地址并划分网段的工具&#xff0c;根据遮掩的位数不同来划分不同的网段。 2.网关 网关(Gateway)又称网间连接器、协议转换器。默认网关在网络层上以实现网络互连&#xff0c;是最复杂的网络互连设备&#xff0c;仅用…