FatFs文件系统(只针对SPI-Flash)总结

news2024/12/29 13:12:29

作用

当我们利用SPI操作Flash时往往读写的都是一段连续的扇区,而FatFs文件系统可以将我们要写入的数据拆分成不连续的扇区见缝插针写入,类似与链表一块扇区指向下一块扇区,不需要物理逻辑地址连续也可以读取整个文件。

这是为啥嘞,举个例子。

各各颜色代表各自的文件,A文件占了flash的1个扇区,B占了2个,C文件占了4个扇区

当我对B文件进行删除擦除扇区时,就是以下图那样

 这时我们要写入一个占4扇区大小的新文件时,像SPI我们写的库那样写的都是连续的地址会把C文件的数据覆盖,造成数据损坏,而FatFs文件系统就解决了这个问题。

 它会把新文件拆开来插入见缝插针,每块扇区都有尾指针指向下一块扇区,解决了不连续的问题,把空间利用最大化。

系统生成

常见的windows下的文件系统格式包括FAT32、NTFS、exFAT。
在使用文件系统前,要先对存储介质进行格式化。格式化时会在存储介质上新建一个文件分配表和目录。这样,文件系统就可以记录数据存放的物理地址,剩余空间。

文件系统的结构与特性

使用文件系统时,数据都以文件的形式存储。写入新文件时,先在目录中创建一个文件索引,它指示了文件存放的物理地址,再把数据存储到该地址中。当需要读取数据时,可以从目录中找到该文件的索引,进而在相应的地址中读取出数据。具体还涉及到逻辑地址、簇大小、不连续存储等一系列辅助结构或处理过程。
文件系统的存在使存取数据时,不再是简单地向某物理地址直接读写,而是要遵循它的读写格式。如经过逻辑转换,一个完整的文件可能被分开成多段存储到不连续的物理地址,使用目录或链表的方式来获知下一段的位置。

文件系统的空间示意图

 目录示意图

 文件分配表

 下面一行相当于下个扇区的地址作为索引,如果索引到0xFF代表整个文件索引结束。

索引到0x00代表空间空闲没有占用。

科普

为啥这个文档只有761字节却要占4096字节空间呢,因为一个文件最小占用单位都是一个簇(扇区),一个扇区为4096字节。

 

代码讲解

程序源码可以自行百度去FatFs官网移植,作者已经开源

我们所需修改的都在diskio.c文件中修改

建立设备

将你需要读写的设备定义一个物理编号,在diskio.c文件中立个宏,这里我使用到的是SPI对Flash进行读写


/* 为每个设备定义一个物理编号 */
#define ATA			    0     // 预留SD卡使用
#define SPI_FLASH		1     // 外部SPI Flash

获取设备状态

当我们对Flash发送读取ID指令,收到的ID数据与Flash数据手册ID对应一致的话则证明设备OK没问题

/*-----------------------------------------------------------------------*/
/* 获取设备状态                                                          */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
	BYTE pdrv		/* 物理编号 */
)
{

	DSTATUS status = STA_NOINIT;
	
	switch (pdrv) {
		case ATA:	/* SD CARD */
			break;
    
		case SPI_FLASH:      
      /* SPI Flash状态检测:读取SPI Flash 设备ID */
      if(sFLASH_ID == SPI_FLASH_ReadID())
      {
        /* 设备ID读取结果正确 */
        status &= ~STA_NOINIT;
      }
      else
      {
        /* 设备ID读取结果错误 */
        status = STA_NOINIT;;
      }
			break;

		default:
			status = STA_NOINIT;
	}
	return status;
}

设备初始化

就是将SPI和对应的IO进行初始化再加上面函数的获取状态则证明初始化完成

/*-----------------------------------------------------------------------*/
/* 设备初始化                                                            */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
	BYTE pdrv				/* 物理编号 */
)
{
  uint16_t i;
	DSTATUS status = STA_NOINIT;	
	switch (pdrv) {
		case ATA:	         /* SD CARD */
			break;
    
		case SPI_FLASH:    /* SPI Flash */ 
      /* 初始化SPI Flash */
			SPI_FLASH_Init();
      /* 延时一小段时间 */
      i=500;
	    while(--i);	
      /* 唤醒SPI Flash */
	    SPI_Flash_WAKEUP();
      /* 获取SPI Flash芯片状态 */
      status=disk_status(SPI_FLASH);
			break;
      
		default:
			status = STA_NOINIT;
	}
	return status;
}

读扇区

为啥要做地址偏移嘞,参照你的flash分部说明,在下图说明了我的flash前6M放了一些数据最好不要动。

偏移为啥是1536嘞,一个扇区4096字节。

1536*4096/1024/1024=6M

下面读函数的<<12是扇区*4096求出扇区地址

/*-----------------------------------------------------------------------*/
/* 读扇区:读取扇区内容到指定存储区                                              */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
	BYTE pdrv,		/* 设备物理编号(0..) */
	BYTE *buff,		/* 数据缓存区 */
	DWORD sector,	/* 扇区首地址 */
	UINT count		/* 扇区个数(1..128) */
)
{
	DRESULT status = RES_PARERR;
	switch (pdrv) {
		case ATA:	/* SD CARD */
			break;
    
		case SPI_FLASH:
      /* 扇区偏移6MB,外部Flash文件系统空间放在SPI Flash后面10MB空间 */
      sector+=1536;      
      SPI_FLASH_BufferRead(buff, sector <<12, count<<12);
      status = RES_OK;
		break;
    
		default:
			status = RES_PARERR;
	}
	return status;
}

写扇区

 与读扇区的理论差不多,就函数变了

写入前要对相应的扇区进行擦除

<<12是扇区*4096求出扇区地址

/*-----------------------------------------------------------------------*/
/* 写扇区:见数据写入指定扇区空间上                                      */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
	BYTE pdrv,			  /* 设备物理编号(0..) */
	const BYTE *buff,	/* 欲写入数据的缓存区 */
	DWORD sector,		  /* 扇区首地址 */
	UINT count			  /* 扇区个数(1..128) */
)
{
  uint32_t write_addr; 
	DRESULT status = RES_PARERR;
	if (!count) {
		return RES_PARERR;		/* Check parameter */
	}

	switch (pdrv) {
		case ATA:	/* SD CARD */      
		break;

		case SPI_FLASH:
      /* 扇区偏移6MB,外部Flash文件系统空间放在SPI Flash后面10MB空间 */
			sector+=1536;
      write_addr = sector<<12;    
      SPI_FLASH_SectorErase(write_addr);
      SPI_FLASH_BufferWrite((u8 *)buff,write_addr,count<<12);
      status = RES_OK;
		break;
    
		default:
			status = RES_PARERR;
	}
	return status;
}
#endif

报错

如果你在操作的过程中遇到了报错,基本都有log可以查看

main函数中的操作返回值是

FRESULT res_flash;                /* 文件操作结果 */

根据返回值对应FRESULT对应的枚举可以找到报错的原因,文件是ff.h

typedef enum {
	FR_OK = 0,				/* (0) Succeeded */
	FR_DISK_ERR,			/* (1) A hard error occurred in the low level disk I/O layer */
	FR_INT_ERR,				/* (2) Assertion failed */
	FR_NOT_READY,			/* (3) The physical drive cannot work */
	FR_NO_FILE,				/* (4) Could not find the file */
	FR_NO_PATH,				/* (5) Could not find the path */
	FR_INVALID_NAME,		/* (6) The path name format is invalid */
	FR_DENIED,				/* (7) Access denied due to prohibited access or directory full */
	FR_EXIST,				/* (8) Access denied due to prohibited access */
	FR_INVALID_OBJECT,		/* (9) The file/directory object is invalid */
	FR_WRITE_PROTECTED,		/* (10) The physical drive is write protected */
	FR_INVALID_DRIVE,		/* (11) The logical drive number is invalid */
	FR_NOT_ENABLED,			/* (12) The volume has no work area */
	FR_NO_FILESYSTEM,		/* (13) There is no valid FAT volume */
	FR_MKFS_ABORTED,		/* (14) The f_mkfs() aborted due to any parameter error */
	FR_TIMEOUT,				/* (15) Could not get a grant to access the volume within defined period */
	FR_LOCKED,				/* (16) The operation is rejected according to the file sharing policy */
	FR_NOT_ENOUGH_CORE,		/* (17) LFN working buffer could not be allocated */
	FR_TOO_MANY_OPEN_FILES,	/* (18) Number of open files > _FS_LOCK */
	FR_INVALID_PARAMETER	/* (19) Given parameter is invalid */
} FRESULT;

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

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

相关文章

从零开始部署“生产级别”的主从模式Mysql

从零开始部署“生产级别”的主从模式Mysql 1. 撰写的缘由 Mysql 在日常应用中使用范围非常广泛&#xff0c;它的部署&#xff0c;其实一个docker run 就可以搞定了&#xff0c;但是这种单个standalone模式下&#xff0c;非常不具备高可用性。 测试环境和开发可以随便用&…

集团审计BI项目的特点

审计到底做哪些事情呢&#xff1f;如果之前大家没有接触的话&#xff0c;试着想一下&#xff0c;可能都会想到审计工作做的应该是跟监督有关的事情。实际上&#xff0c;现代审计职责不仅仅只是监督&#xff0c;还要兼顾到服务&#xff0c;具有监督和服务的双重属性。 什么是审…

stm32学习笔记-2 软件安装及创建工程

2 软件安装及创建工程 [toc] 注&#xff1a;笔记主要参考B站 江科大自化协 教学视频“STM32入门教程-2023持续更新中”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 2.1 软件安装 软件安装的步骤有&#xff1a; 安装Keil5 MDK。Keil5 MDK专门用于给ARM系列单片…

网络安全规划实践

在企业IT战略规划方面&#xff0c;很多时候我们会自动忽略网络安全规划&#xff0c;一是不够重视&#xff0c;从公司到技术部门&#xff0c;对网络安全的认识有限&#xff0c;重视不够&#xff0c;不愿意花钱。 二是技术部门自身原因&#xff0c;不愿意多花成本和精力去规划&am…

推荐14款最受欢迎的3d建模软件

最好的 3D 建模软件可以毫不费力地设计出最奇特的创意&#xff0c;并将它们变成令人惊叹的 3D 可视化效果。如果您确切知道要设计的模型类型&#xff0c;请查看此 3D 建模软件列表&#xff0c;比较 15 种一流的 3D 建模平台&#xff0c;然后选择最适合您的一款。最佳 3D 建模软…

金兔迎福报、新春第一炮【2022 中国开源年度报告】!

【中国开源年度报告】由开源社从 2015 年发起&#xff0c;是国内首个结合多个开源社区、高校、媒体、风投、企业与个人&#xff0c;以纯志愿、非营利的理念和开源社区协作的模式&#xff0c;携手共创完成的开源研究报告。后来由于一些因素暂停&#xff0c;在 2018 年重启了这个…

【王道数据结构】第一章 | 绪论 | 数据结构与算法的概念

目录 1.1数据结构的基本概念 1.2数据结构的三要素 1&#xff09;.数据的逻辑结构&#xff1a; 2&#xff09;.数据的存储结构&#xff08;物理结构&#xff09;&#xff1a; 3&#xff09;.数据的运算 4&#xff09;.数据类型和抽线数据类型 1.3算法的基本概念 1.4 空间…

人大金仓数据库分区表

分区表 声明式创建分区 按列创建分区&#xff08;PARTITION BY LIST&#xff09; 将学员表student按所在城市使用partition by list创建分区 创建分区表&#xff08;基表&#xff09; 创建格式 create table 表名&#xff08;字段名 数据类型&#xff09;PARTITION BY LI…

Redis哨兵工作原理 | 黑马Redis高级篇

哨兵的作用 Redis提供了哨兵机制来实现主从集群的自动故障恢复 监控&#xff1a;sentinel会不断检查master和slave是否按照预期工作 自动故障恢复&#xff1a;如果master故障&#xff0c;sentinel会将一个slave变为master&#xff0c;当故障实例恢复后也以新的master为主 通…

低代码平台助力交通行业数字化科学管理

编者按&#xff1a;本文分析了交通行业的数字化转型需求&#xff0c;并指出了适合交通行业的低代码平台的特性&#xff0c;最后通过相关案例进行了功能展示。关键词&#xff1a;对接能力&#xff0c;国产化&#xff0c;数据引擎&#xff0c;智能化交通运输是国民经济先导性、战…

3、基本的SELECT语句

文章目录1. SQL概述1.1 SQL背景知识1.2 SQL语言排行榜1.3 SQL 分类2 SQL语言的规则与规范2.1 基本规则2.2 SQL大小写规范 &#xff08;建议遵守&#xff09;2.3 注 释2.4 命名规则&#xff08;暂时了解&#xff09;2.5 数据导入指令3 基本的SELECT语句3.0 SELECT...3.1 SELECT …

大数据技术架构(组件)15——Hive:内置UDAF函数

1.4.10、内置UDAF函数1.4.10.1、count--可以发现count(id)会把idnull的值剔除掉select count(1),count(*),count(distinct id),count(id) from test1.4.10.2、sumselect sum(1) from test;1.4.10.3、avg该函数太简单了&#xff0c;就不给大家演示了1.4.10.4、min该函数太简单了…

Hive(5):数据定义语言(DDL)

1 数据定义语言&#xff08;DDL&#xff09;概述 1.1 DDL语法的作用 数据定义语言 (Data Definition Language, DDL)&#xff0c;是SQL语言集中对数据库内部的对象结构进行创建&#xff0c;删除&#xff0c;修改等的操作语言&#xff0c;这些数据库对象包括database&#xff…

面试官问 ,Mybatis SELECT 查询, 集合或者单个对象,如果数据库不存在数据,需要判空吗?

前言 于昨日下班时段&#xff0c;本人正在与生活作斗争&#xff0c;收到了金三银四一线作战小队成员紧急反应的战况问题。 不熟悉的或者是不知道怎么去看源码的看官&#xff0c;上车了。 正文 这面试题问的&#xff0c; 考察的是什么&#xff1f; ① mybatis框架的应用掌握情…

如何实现报表集成?(三)——资源集成

在上一篇&#xff0c;我们介绍了用户同步和单点登录&#xff0c;帮助用户了解什么是用户同步、如何做用户验证&#xff0c;以及如何实现单点登录。 这一篇&#xff0c;我们看下如何做资源集成。行文过程中得到了来自报表软件厂商 Smartbi 的报表产品&#xff1a;电子表格软件的…

leetcode-每日一题-1663-具有给定数值的最小字符串(简单,贪心)

很久没有做过贪心类型的题目了&#xff0c;因为用的很少&#xff0c;大多都用的dp&#xff0c;这道题第一眼看过去以为是dp&#xff0c;因为力扣里面的中等题很多都是dp&#xff0c;但仔细一看发现是贪心&#xff0c;思路其实很简单&#xff0c;先全部最小&#xff0c;中间插一…

机械设备ERP系统可以给企业带来哪些好处?

随着信息化技术的进步与智能制造的发展趋势&#xff0c;很多制造企业也在一直探寻适合自己的信息化管理转型之路。机械设备EPR系统对于机械设备制造企业来说就是关键一环。要充分发挥出机械设备ERP系统的赋能作用&#xff0c;必不可少的是从生产制造的各个环节出发&#xff0c;…

ONLYOFFICE 文档 v7.3 现已发布:表单角色、SmartArt、安全性设置、查看窗口等功能

在 ONLYOFFICE 最新版本的在线编辑器中现已提供高级表单、SmartArt 图形插入、增强密码保护和公式计算、幻灯片特殊粘贴项等多项功能。继续阅读以了解所有更新。 字段填写接收人角色 现在&#xff0c;数字表单将更加高效。您可为需要填写表单的用户分配各种角色&#xff0c;简…

中医名词看不懂?用PaddleNLP做一个中医“百科全书”

我是一个深度学习爱好者&#xff0c;目前对自然语言处理感兴趣&#xff0c;热衷于了解一些人工智能中的数学推导和经典论文复现&#xff0c;正在成长的“小趴菜”一枚&#xff0c;在PPDE指导计划中&#xff0c;创作了中医文献阅读理解项目&#xff0c;下面将由我介绍在项目创作…

Java开发面试(技术面)经历 (二)

2022-11-08&#xff0c;应聘Java开发 &#xff1a;云智慧&#xff08;实训机构&#xff0c;个人观点&#xff0c;与培训没区别&#xff09; 今天二面技术面&#xff0c;问了一些问题 1.集合有哪些&#xff1f; 两大容器如图&#xff1a;Collection集合 list下面还有Vector&…