STM32FATFS文件系统移植

1。 FATFS简介

FATFS文件系统是一个用于在微控制器上运行的开源文件系统,支持FAT/FATFS、NTFS、exFAT等主流文件系统,且一直保持更新。在此以FatFs官网最新版本v0.15进行移植。

2. 移植具体操作

2.1 下载FatFs源码

FATFS源码在其官网就有下载链接,下载后解压即可,官网页面如图1所示:

图1.FATFS官网页面

将其翻至最下面,就可以找到下载链接,如图2所示:

图2.FATFS下载链接

2.2 FATFS代码结构

FATFS源码解压后,其一级目录结构如图3所示:

图3.FATFS源码一级目录结构

其source文件夹下各文件作用如下所示:

source
├── 00history.txt //历史版本信息
├── 00readme.txt //FATFS简介
├── diskio.c //磁盘IO适配文件
├── diskio.h //磁盘IO适配头文件
├── ff.c //FATFS主要实现文件
├── ff.h //FATFS主要实现头文件
├── ffconf.h //FATFS配置头文件
├── ffsystem.c //系统调用适配文件
└── ffunicode.c //Unicode适配文件

在移植过程中,主要对diskio.c、ffconf.h进行修改。

2.3 修改前后文件对比

后文所有代码比对均默认左侧为原代码,右侧为修改后的代码。

2.3.1 diskio.c文件修改比对

diskio.c文件主要实现对存储介质的硬件适配,需要将FLASH读写、初始化等代码移植至此文件内的固定接口。

2.3.1.1头文件添加及宏定义变量修改对比

如图4所示:

图4.diskio.c文件头文件添加及宏定义变量修改对比

#include "Spi.h"        //引用SPI初始化
#include "W25q64.h" //引用FLASH文件操作函数,文件内代码均在上篇文章中。
#define SPI_FLASH 3 //定义驱动卷名

FATFS中文件目录格式为为驱动卷名+“:”+文件名,假如说SPI_FLASH文件系统一级目录内有“aaa.txt”这个文件,那么其目录格式为"3:aaa.txt"。3就是宏定义的驱动卷名,文件系统挂载什么的如果要挂载SPIFLASH就是挂载"3:"目录,其余驱动卷或设备同理。

在C语言中上述的写法更简单,C语言支持宏定义的字符串拼接,具体示范如下列代码所示:

#define SPI_FLASH_DIR "3:"

res_flash = f_mount(&fs,SPI_FLASH_DIR,1);

res_flash = f_open(&fnew,SPI_FLASH_DIR"ABC.txt",FA_CREATE_ALWAYS | FA_WRITE);
#define SPI_FLASH_DIR 3

res_flash = f_mount(&fs,"3:",1);

res_flash = f_open(&fnew,"3:ABC.txt",FA_CREATE_ALWAYS | FA_WRITE);

这两段代码在实现效果上并无差别。

2.3.1.2 磁盘存储介质状态查询接口修改对比

如图5所示:

图5.diskio.c文件磁盘存储介质状态查询修改对比

需要将对磁盘存储介质的硬件状态查询移植至此文件内的固定接口。具体操作为在switch (pdrv) 内添加一条分支,返回值分为STATUS_NOINIT、STATUS_NODISK、STATUS_PROTECT与RES_OK四种情况,分别代表磁盘存储介质未初始化、没有对应驱动卷名、磁盘写保护与磁盘正常。

2.3.1.3 磁盘存储介质初始化接口修改对比

如图6所示:

图6.diskio.c文件磁盘存储介质初始化修改对比

需要对磁盘存储介质的硬件初始化移植至此文件内的固定接口。具体操作为在switch (pdrv) 内添加一条分支,调用SPI_FLASH_Init()函数进行初始化。可用返回值与状态查询的返回值一致,在这里我图省事,直接调用了状态查询函数。

2.3.1.4 磁盘存储介质数据读取接口修改对比

如图7所示:

图7.diskio.c文件磁盘存储介质数据读取接口修改对比

需要对磁盘存储介质的硬件数据读取移植至此文件内的固定接口。具体操作为在switch (pdrv) 内添加一条分支,调用SPI_FLASH_Read()函数进行读取。其中读取数据的存储地址为*buff,读取数据的扇区逻辑位号为sector,读取数据的扇区数量为count。

在图7中可以看到,扇区逻辑区块地址(LBA)与扇区数量均左移12位,即乘4096。然而这两个数据乘4096的原因不一样。扇区逻辑区块地址乘4096是为了将扇区逻辑区块地址转化位扇区物理地址,而扇区数量乘4096是为了将扇区数量转化为扇区数据读取数量。

PS:LBA是非常单纯的一种定址模式﹔从0开始编号来定位区块,第一区块LBA=0,第二区块LBA=1,依此类推。这种定址模式取代了原先操作系统必须面对存储设备硬件构造的方式。

2.3.1.5 磁盘存储介质数据写入接口修改对比

如图8所示:

图8.diskio.c文件磁盘存储介质数据写入接口修改对比

需要对磁盘存储介质的硬件数据写入移植至此文件内的固定接口。具体操作为在switch (pdrv) 内添加一条分支,调用SPI_FLASH_Write()函数进行写入。其中写入数据的存储地址为*buff,写入数据的扇区逻辑位号为sector,写入数据的扇区数量为count。至于为什么向左移12位,与读取数据相同,都是将扇区逻辑区块地址转化为扇区物理地址,将扇区数量转化为扇区数据写入数量。

2.3.1.6 磁盘存储介质信息接口修改对比

如图9所示:

图9.diskio.c文件磁盘存储介质信息接口修改对比

需要对磁盘存储介质的硬件信息查询移植至此文件内的固定接口。具体操作为在switch (pdrv) 内添加一条分支,在其中添加一个switch,检索传入的cmd,需要对cmd建立3条分支,分别为GET_SECTOR_COUNT、GET_SECTOR_SIZE与GET_BLOCK_SIZE,分别将物理扇区总数量、物理扇区大小与擦除块数量返回给*buff并返回RES_OK即可。

2.3.1.7 磁盘存储介质写入时间函数

在FATFS文件系统中并不附带获取时间的函数接口,但是创建文件、修改文件等操作都需要获取当前时间,因此需要添加一个获取当前时间的函数接口。具体操作为使用弱定义,定义FATFS文件系统中的获取时间函数内容

__weak DWORD get_fattime(void)              // 获取时间
{
return ((DWORD)(2024-1980)<<25) // 设置年份为2024
| ((DWORD)1<<21) // 设置月份为1
| ((DWORD)1<<16) // 设置日期为1
| ((DWORD)1<<11) // 设置小时为1
| ((DWORD)1<<5) // 设置分钟为1
| ((DWORD)1<<1); // 设置秒数为1
}

FATFS采用时间戳的方式来记录时间,具体格式如图10所示:

图10.FATFS文件系统时间戳格式

2.3.2 ffconf.h文件修改对比

ffconf.h文件为FATFS文件系统配置文件,其中定义了FATFS文件系统的配置参数。

2.3.2.1 文件系统格式化宏定义修改对比

如图11所示:

图11.文件系统格式化宏定义修改对比

这个选项会打开f_mkfs()函数,允许对文件系统格式化,或在没有文件系统的情况下建立文件系统

2.3.2.2 文件系统命名格式与命名空间宏定义修改对比

如图12所示:

图12.文件系统命名格式与命名空间宏定义修改对比

由于FATFS文件系统默认命名为日文,需要将FF_CODE_PAGE的值修改,以支持中文命名。FF_USE_LEN决定了实现长文件支持所使用的内存方式,0为不使用LFN,1为使用LFN,但没有线程安全,2为使用LFN并使用堆内存,3为使用LFN并使用栈内存。

2.3.2.3 文件系统驱动卷数量与最大扇区内存修改对比

如图13所示:

图13.文件系统驱动卷数量与最大扇区内存修改对比

修改FF_VOLUMES的值,以便支持多个卷。修改FF_MAX_SS的值,以便支持更大的扇区。

2.3.2.5 文件系统时间戳宏定义修改对比

如图14所示:

图14.文件系统时间戳宏定义修改对比

FF_FS_NORTC=1表示使用时间函数,FF_FS_NORTC=-1表示不使用时间函数。

3. 移植后main文件使用演示

首先需要引用“ff.h”头文件,然后定义如下全局变量:

FATFS fs;
FIL fnew;
FRESULT res_flash;
UINT fnum;

由于FATFS文件系统的结构体都比较大,在main函数中定义会导致堆栈溢出。

然后定义一些临时变量,用于存储文件名和文件内容以及FATFS文件系统运行状态:

BYTE buffer[4096] = {0};
BYTE textFileBuffer[] = "ABCDEFG";
uint8_t c[256] = {0};

我所使用的开发板为野火STM32F103指南者开发板,驱动卷命名为"3",具体执行代码如下所示

int main()
{
HSE_SetSysClock(RCC_PLLMul_9); // 设置系统时钟为9倍,72MHz
Usart_init(); // 初始化串口
USART_SendString(USART1,"Systeam is OK.");
res_flash = f_mount(&fs,"3:",1); // 挂载文件系统
USART_SendByte(USART1,res_flash);
if(res_flash == FR_NO_FILESYSTEM) // 检测是否存在文件系统
{
res_flash = f_mkfs("3:",NULL,buffer,4096); // 创建文件系统
if(res_flash == FR_OK) // 判断是否创建成功
{
USART_SendString(USART1,"FATFS has been mkf.");
res_flash = f_mount(NULL,"3:",0); // 卸载文件系统
res_flash = f_mount(&fs,"3:",1); // 重新挂载文件系统
}
else // 创建失败
{
USART_SendString(USART1,"FATFS mkf filed.");
USART_SendByte(USART1,res_flash);
while(1) // 死循环
{
}
}
}
else if(res_flash !=FR_OK) // 挂载失败
{
USART_SendString(USART1,"mount ERROR.");
while(1) // 死循环
{
}
}
else // 挂载成功
{
USART_SendString(USART1,"mount OK.");
}
res_flash = f_open(&fnew,"3:ABC.txt",FA_CREATE_ALWAYS | FA_WRITE); // 创建文件
USART_SendByte(USART1,res_flash);
if(res_flash == FR_OK) // 判断是否创建成功
{
USART_SendString(USART1,"File open is OK.");
}
res_flash = f_write(&fnew,"ABCDEFG",7,&fnum); // 写入数据
if(res_flash == FR_OK) // 判断是否写入成功
{
USART_SendString(USART1,"File write is OK.");
}
else // 写入失败
{
USART_SendByte(USART1,res_flash);
}
f_close(&fnew); // 关闭文件
if(res_flash == FR_OK) // 判断是否关闭成功
{
USART_SendString(USART1,"File close is OK.");
}
else // 关闭失败
{
USART_SendByte(USART1,res_flash);
}
res_flash = f_unmount("3:"); // 卸载文件系统
USART_SendByte(USART1,res_flash);
res_flash = f_mount(&fs,"3:",1); // 重新挂载文件系统
USART_SendByte(USART1,res_flash); // 判断是否重新挂载成功
res_flash = f_open(&fnew,"3:ABC.txt",FA_OPEN_EXISTING | FA_READ); // 打开文件
if(res_flash == FR_OK) // 判断是否打开成功
{
USART_SendString(USART1,"File open is OK.");
USART_SendString(USART1,c);
}
else // 打开失败
{
USART_SendByte(USART1,res_flash);
}
res_flash = f_read(&fnew,c,7,&fnum); // 读取文件内容
if(res_flash == FR_OK) // 判断是否读取成功
{
USART_SendString(USART1,"File read is OK.");
USART_SendString(USART1,c);
}
else // 读取失败
{
USART_SendByte(USART1,res_flash);
}
f_close(&fnew); // 关闭文件
res_flash = f_unmount("3:"); // 卸载文件系统
USART_SendByte(USART1,res_flash);
if(res_flash == FR_OK) // 判断是否卸载成功
{
USART_SendString(USART1,"unmount OK.");
}
while(1){ }
}

烧录结果

如图15所示:

图15.烧录结果

STM32FATFS文件系统移植的更多相关文章

  1. 基于s5pv210嵌入式系统busybox文件系统移植

    基于s5pv210嵌入式系统busybox文件系统移植 1.下载源码 busybox.net/downloads下载最新版的busybox源码,最新源码为1.21.1 2.解压源码文件 tar xvf ...

  2. SD卡fat文件系统移植

    经过充分的研究,发现fatfs文件系统移植的比较简单!因为代码都已经被别人做好了!我们只需把io层稍稍做个处理就ok了: 至于sd卡的驱动请看我这篇博客:http://blog.csdn.net/ie ...

  3. 小白自制Linux开发板 三. Linux内核与文件系统移植

    上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...

  4. linux2.6.30.4内核移植(3)——yaffs文件系统移植

    内核源码:linux2.6.30.4 交叉编译工具:3.4.5 移植linux内核至:TQ2440 工作基础:http://www.cnblogs.com/nufangrensheng/p/36696 ...

  5. RTT下spi flash+elm fat文件系统移植小记

    背景: MCU:STM32F207 SPI flash: Winbond W25Q16BV OS: RTT V1.1.1 bsp: STM32F20x 1 将spi_core.c,spi_dev.c及 ...

  6. UBI 文件系统移植 sys 设备信息【转】

    转自:http://blog.chinaunix.net/uid-25304914-id-3058647.html cat /sys/class/misc/ubi_ctrl/dev --------- ...

  7. Linux内核,文件系统移植过程中出现的一些问题与解决办法

    1.bootm地址和load address一样 此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行. ...

  8. uboot 、内核、文件系统移植

    1. 参考下面博客: http://blog.csdn.net/andylauren/article/details/51448353 2.查看u盘: $ sudo fdisk -l 3. 格式化u盘 ...

  9. STM32 FATFS文件系统移植

    http://www.360doc.com/content/11/1221/10/7736891_173820469.shtml

  10. 关于linux下的嵌入式文件系统以及flash文件系统选择

    嵌入式linux下常见的文件系统 • RomFS:只读文件系统,可以放在ROM空间,也 可以在系统的RAM中,嵌入式linux中常用来作 根文件系统 • RamFS:利用VFS自身结构而形成的内存文件 ...

随机推荐

  1. TypeScript中的元组 Tuple

    元组类型 // 元组类型:表示一个已知元素数量和类型的数组,各元素的类型不必相同 let undata: [string, '男'| '女']; //已知数量是两个.类型分别是字符串和男或者女 und ...

  2. Redis做Mybatis的二级缓存

    Redis做mybatis的二级缓存 作用提升速度,保证多台服务器访问同一数据库时不会崩 注意:保证本地有下载redis且已经打开,否则无法使用. [本文只讲述了实现步骤,并没有原理讲解] 保证有导入 ...

  3. # 重要-即时通讯IM开源项目OpenIM关于版本管理及v2.3.0发布计划

    越来越多的客户把OpenIM用到了生产环境,由于新特性持续迭代和bug修复,会涉及到后续的升级方案,为了让大家后续从容应对,本文重点总结OpenIM对未来版本管理的思路和方案.同时,官网对于文档进行了 ...

  4. Unity的SpriteAtlas实践

    我的环境 Unity引擎版本:Unity2019.3.7f1 AssetBundles-Browser 于2021-1-14拉取,github上最后提交日期是2019-12-14,在本文简称:ABBr ...

  5. github clone或访问慢

    做技术的我们经常会访问github.com,有时出现github访问非常慢或者git clone速度很慢,git push也很慢 原因很简单:github被高高的墙屏蔽了. 所以解决方案就是手动把 c ...

  6. 在cmd(命令行)或bat文件切换盘符

    bat文件 写一个自动更新git的bat文件,如果bat文件放在E盘,想要去到D盘的某个目录下执行命令,代码如下: SET ksf=D:\code\KSFramework @echo on d: cd ...

  7. pandas读取txt---按行输入按行输出

    1.pandas读取txt---按行输入按行输出 import pandas as pd # 我们的需求是 取出所有的姓名 # test1的内容 ''' id name score 1 张三 100 ...

  8. 1.1 Windows驱动开发:配置驱动开发环境

    在进行驱动开发之前,您需要先安装适当的开发环境和工具.首先,您需要安装Windows驱动开发工具包(WDK),这是一组驱动开发所需的工具.库.示例和文档.然后,您需要安装Visual Studio开发 ...

  9. Spring一套全通6—注解编程

    百知教育 --- Spring系列课程 --- 注解编程 第一章.注解基础概念 1. 什么是注解编程 指的是在类或者方法上加入特定的注解(@XXX),完成特定功能的开发. @Component pub ...

  10. Spring一套全通5—SSM整合

    百知教育 - Spring系列课程 - MVC框架整合 第一章.MVC框架整合思想 1. 搭建Web运行环境 <dependency> <groupId>javax.servl ...