019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识

最近工作比较忙,没时间摸鱼学习,抽空学点就整理一点笔记。

1、文件系统

在之前学习Flash的时候,可以调用SPI_FLASH_BufferWrite函数,将数据内容写入到Flash芯片中,需要使用的时候,可以再从Flash中读取出来,但是我们每次写入数据的时候,有以下三点比较麻烦:

  1. 有效数据的位置不方便记录;
  2. 存储数据量大小可能随时变动,对于Flash的容量剩余大小难以确定;
  3. 存储数据类型多变,读取时不确定该以何种格式解读数据。

目前我们接触到的Windows/Linux系统就是比较常见的文件系统,我们在Windows/Linux中查找文件只需要根据文件的存储路径就可以方便的找到需要的文件,文件内容读取可以通过文件类型(例如txt、exe等)方式去通过特定的打开方式去使用。

数据文件在硬盘(以机械硬盘为例)中的存储,是将硬盘分为盘片-扇区-磁道的方式分布存储在磁道中,文件存储时,磁盘会记录文件存储的地址,当使用文件的时候,会根据地址寻址进行读取写入磁盘。

为了存储和管理数据方便,在存储介质中会建立组织结构,包含操作系统的引导区、目录和文件。常见的Windows系统下文件系统格式包括FAT32、NTFS、exFAT,我们拿到新的磁盘时,需要将磁盘格式化为上述的一种文件格式,格式化时,会在磁盘中建立一个文件分配表和目录,后续文件系统可以在文件分配表和目录中记录数据存放的地址以及剩余空间了。
019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第1张图片

如上图,Windows中将磁盘通过逻辑划分,将整块硬盘划分为几块,包含主引导记录分区(MBR),基本分区1-3,逻辑分区等,其中主引导分区中记录着后续几个分区的物理地址,可以通过这些物理地址找到后续分区,这里会装系统的基本都懂,就不过多阐述了,感兴趣的可以百度一下学习学习。

当使用文件系统时,数据都是以文件的方式进行存储。写入新文件时,首先要在目录中创建一个文件索引,用来指示文件存放的物理位置,然后再将文件存储到该地址中;当需要读取数据时,首先到目录中查找读取数据的文件索引,再到相应的地址中区读取数据。这期间还牵扯到逻辑地址、簇大小、不连续存储等一系列过程。

文件存储时,不仅仅是简单的向某个物理地址直接读写,需要以一定的既定格式进行读写。

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第2张图片

例如在火哥的教程中举的例子,假设现在有0-99共100簇的存储空间(簇可以理解为扇区),其中第0簇是文件分配表,第1簇为目录,后续几个文件分别占用不同数量的扇区存储文件,这些文件的存储信息都在记录在第1簇的目录中。

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第3张图片

目录表

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第4张图片

文件分配表 - 连续存储

当需要读取文件时,根据目录相中,读取到开始簇为2,找到文件分配表中,第2簇上读取到数据为3,表示下一部分数据指向存储在第3簇上,再到第3簇记录上读到下一簇得数据指向为4,一次向后,直到最后一簇11时,发现下一个指向为FF,表示到文件末尾了,到此文件就读取完了。到这里的时候,起始发现这种指向方式很像链表,链表头指向的时数据存放的位置,链表尾,指向的是下一个数据起始位置。

上面这个表中,数据是连续存储的,假如我们对文件进行修改了,可能原来的存储单元存不下更多的数据,那么后续增加的内容可能会放到其他簇中,这样在原来的第11簇位置指向的FF就变更为后续文件存储的起始位置了。如下图

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第5张图片

文件分配表 - 不连续存储

2、FatFs系统

FatFs是面向小型嵌入式系统的一种通用的FAT文件系统,由AISI C语言编写,并且完全独立于底层的I/O介质。因此它可以很容易的不加修改一直到其他处理器中。

上节中我们已经写好用SPI读写Flash,这节开始就可以将FatFs文件系统代码移植进去,就可以使用文件系统的各种函数,对Flash采用文件的方式进行读写了。

学习中使用到的FatFs文件系统官网地址:

FatFs文件系统官网

目前官网最新的FatFs版本为ff15,野火教程中使用的为ff11a,这里也就根据野火教程先进行学习,等到后面抽空再学习最新的版本。

在下载好的FatFs源码文件中,在documents目录下,有关于此源码的说明,关于接口函数的说明可以看一下说明文档,这里不做过多赘述。

在src文件夹中,有个read.txt,里面对源码中的各个文件都做了说明,感兴趣的可以看一下。

文件名 功能
integer.h 文件中包含了一些数值类型的定义。
diskio.c 包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。
ff.c FatFs核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。
cc936.c 本文件在option目录下,是简体中文支持所需要添加的文件,包含了简体中文的GBK和Unicode互相转换功能函数
ffconf.h 这个头文件包含了对FatFs功能配置的宏定义,通过修改这些宏定义就可以裁剪FatFs的功能,如果需要支持简体中文,需要把ffconf.h中的_CODE_PAGE的宏改成936,并把上面的ccp36.c文件加入到工程中。

在以上几个文件中,我们需要修改的主要是diskio.c、ff.c以及ffconf.h,这里针对性的讲一下关于FatFs文件系统移植需要注意的地方。

先看一下FatFs在程序中的关系网络图:

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第6张图片

这里先分析一下ff.c、diskio.c这几个文件:

diskio.c中,我们主要了解一下DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count)函数

#define ATA		0	/* 硬盘设备标号为0 */
#define MMC		1	/* MMC/SD设备标号为1 */
#define USB		2	/* USB设备标号为2 */
DRESULT disk_read (BYTE pdrv,BYTE *buff,DWORD sector,UINT count)
{
	DRESULT res;
	int result;
	switch (pdrv) {
	case ATA :
		// translate the arguments here
		result = ATA_disk_read(buff, sector, count);
		// translate the reslut code here
		return res;
	case MMC :
		// translate the arguments here
		result = MMC_disk_read(buff, sector, count);
		// translate the reslut code here
		return res;
	case USB :
		// translate the arguments here
		result = USB_disk_read(buff, sector, count);
		// translate the reslut code here
		return res;
	}
	return RES_PARERR;
}

disk_read函数是Fatfs与底层程序对接的接口,在这里可以实现对硬盘、SD卡、USB等设备的读写,在程序中,实际上预留了给用户改写自己实现的底层程序,例如这里,我们可以将我们在之前学习I2C读写EEPROM或者SPI读写Flash的函数放在这里实现,例如改写后:

#define FLASH		3	/* FLASH设备标号为3 */
//以上省略
	case FLASH :
		//这里采用我们之前实现的额SPI读取Flash的函数,使用前需要在文件前#include "bsp_spi_flash.h"
		result = SPI_Flash_ReadDate(buff, sector, count);
		return res;
//以下省略

在diskio.c中还有disk_write,同样我们也可以采用跟读方式相同的办法用我们自己实现的写函数进行改写。

这里改写完成后,再到ff.c中看一下,这里我们就可以使用学习C语言是学到的文件操作函数了,例如f_open()、f_read()、f_write()等。

FRESULT f_read (
	FIL* fp, 		/* Pointer to the file object */
	void* buff,		/* Pointer to data buffer */
	UINT btr,		/* Number of bytes to read */
	UINT* br		/* Pointer to number of bytes read */
)
{
//---------------------------篇幅原因省略----------------------------------------//
				if (csect + cc > fp->fs->csize)	/* Clip at cluster boundary */
					cc = fp->fs->csize - csect;
				if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK)
					ABORT(fp->fs, FR_DISK_ERR);
//---------------------------篇幅原因省略----------------------------------------//
}

在以上程序中,f_read函数又调用了disk_read函数,从而实现文件的读取。

因此在使用FatFs文件系统时,我们只需要去修改diskio.c文件基本就可以完成对设备的读写等操作了。ff.c、ff.h、integer.h以及diskio.h这四个文件基本不需要改动。

另外在说一下ffconf.h文件,关于FatFs文件系统所具备的功能,基本上跟我们在PC系统上操作硬盘、文件夹、文件等操作一致,因此我们使用FatFs文件系统时,可以根据实际需要对其功能进行裁剪,野火的教程中对内容进行了总结,这里就直接附到下面各位可以根据实际需求进行裁剪。

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识_第7张图片

关于FatFs文件系统的相关内容,可以在官网或者帮助文档中看看相关的介绍。

你可能感兴趣的:(stm32,stm32,学习,笔记)