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. JAVA多线程并发编程-避坑指南

    作者:京东零售 肖朋伟 一.前言 开发过程中,多线程的应用场景可谓十分广泛,可以充分利用服务器资源,提高程序处理速度.我们通常也会使用池化技术,去避免频繁创建和销毁线程. 本篇旨在基于编码规范.工作中 ...

  2. JS中every的简单使用

    every 方法 every()方法用于检测数组中的所有元素是否都满足指定条件. every()方法会遍历数组的每一项,如果有一项不满足条件,则返回false,剩余的项将不会再执行检测. 如果遍历完数 ...

  3. 【K哥爬虫普法】不要沾边!涉案 7k 合判 6 年!

    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识, ...

  4. Gin 应用多实例部署session问题、session参数与刷新

    目录 一.Gin Session 存储的实现方案 二.memstore:基于内存的实现 2.1 基本使用 2.2 关键参数 三.使用redis:多实例部署 3.1 使用redis优势 3.2 基本使用 ...

  5. Python RE 正则表达式模块

    正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex.regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为&qu ...

  6. C/C++ 实现通过FTP上传下载

    实现FTP文件下载: #include <stdio.h> #include <Windows.h> #include <WinInet.h> #pragma co ...

  7. 基于AvaloniaUI开发跨平台.NET三维应用:环境搭建

    本文介绍在Vistual Studio 2022中使用Avalonia和集成AnyCAD AvaloniaUI三维控件的的过程. 目录 0 初始化环境 1 创建项目 2 集成AnyCAD Avalon ...

  8. conditional_t和enable_if_t的实现

      conditional_t和enable_if_t是元编程里面很相似却有有着一定区别的模板.形如conditional_t<_Cond, _If, _Else>是指如果_Cond表达式 ...

  9. ajax中的同步异步和跨域请求

    ajax中的同步异步和跨域请求 同步异步 demo.html <script> $.ajax({ type: "get", async: false, data: &q ...

  10. windows10 安装运行docker

    windows10 安装使用docker part01.windows设置 启用windows 虚拟化 任务管理器-性能-CPU-虚拟化启用 启用Hyper-v 控制面板(Win+R -> 输入 ...