STM32FATFS文件系统移植
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文件系统移植的更多相关文章
- 基于s5pv210嵌入式系统busybox文件系统移植
基于s5pv210嵌入式系统busybox文件系统移植 1.下载源码 busybox.net/downloads下载最新版的busybox源码,最新源码为1.21.1 2.解压源码文件 tar xvf ...
- SD卡fat文件系统移植
经过充分的研究,发现fatfs文件系统移植的比较简单!因为代码都已经被别人做好了!我们只需把io层稍稍做个处理就ok了: 至于sd卡的驱动请看我这篇博客:http://blog.csdn.net/ie ...
- 小白自制Linux开发板 三. Linux内核与文件系统移植
上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...
- linux2.6.30.4内核移植(3)——yaffs文件系统移植
内核源码:linux2.6.30.4 交叉编译工具:3.4.5 移植linux内核至:TQ2440 工作基础:http://www.cnblogs.com/nufangrensheng/p/36696 ...
- 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及 ...
- UBI 文件系统移植 sys 设备信息【转】
转自:http://blog.chinaunix.net/uid-25304914-id-3058647.html cat /sys/class/misc/ubi_ctrl/dev --------- ...
- Linux内核,文件系统移植过程中出现的一些问题与解决办法
1.bootm地址和load address一样 此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行. ...
- uboot 、内核、文件系统移植
1. 参考下面博客: http://blog.csdn.net/andylauren/article/details/51448353 2.查看u盘: $ sudo fdisk -l 3. 格式化u盘 ...
- STM32 FATFS文件系统移植
http://www.360doc.com/content/11/1221/10/7736891_173820469.shtml
- 关于linux下的嵌入式文件系统以及flash文件系统选择
嵌入式linux下常见的文件系统 • RomFS:只读文件系统,可以放在ROM空间,也 可以在系统的RAM中,嵌入式linux中常用来作 根文件系统 • RamFS:利用VFS自身结构而形成的内存文件 ...
随机推荐
- k8s笔记——NodePort暴露nginx-controller实现https自动跳转自定义nodePort端口
安装nginx-controller并暴露nodePort helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx ...
- Vue基础系列文章05----babel安装与使用
1.安装babel-node包,运行: 1) npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node 2 ...
- golang uuid库介绍
简介: 在现代软件开发中,全球唯一标识符(UUID)在许多场景中发挥着重要的作用.UUID是一种128位的唯一标识符,它能够保证在全球范围内不重复.在Go语言中,我们可以使用第三方库github.co ...
- 设计模式学习-使用go实现组合模式
组合模式 定义 适用范围 优点 缺点 代码实现 参考 组合模式 定义 组合模式(Composite),将对象组合成树形结构以表示'部分-整体'的层次关系.组合模式使得用户对单个对象和组合对象的使用具有 ...
- python读取json格式文件大量数据,以及python字典和列表嵌套用法详解
1.Python读取JSON报错:JSONDecodeError:Extra data:line 2 column 1 错误原因: JSON数据中数据存在多行,在读取数据时,不能够单单用open(), ...
- 3.1 C/C++ 使用字符与指针
C/C++语言是一种通用的编程语言,具有高效.灵活和可移植等特点.C语言主要用于系统编程,如操作系统.编译器.数据库等:C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统.图形用户界面 ...
- 分享四个实用的vue自定义指令
v-drag 需求:鼠标拖动元素 思路: 元素偏移量 = 鼠标滑动后的坐标 - 鼠标初始点击元素时的坐标 + 初始点击时元素距离可视区域的top.left 将可视区域作为边界,限制在可视区域里面拖拽 ...
- 使用CAShapeLayer,UIBezierPath,CAGradientLayer构建边框颜色会旋转的六边形
主要思路是: 1.使用UIBezierPath绘制一个六边形路径 2.创建一个CAShapeLayer图层,将这个六边形path设置到CAShapeLayer属性上.然后设置fillColor为透明, ...
- pandas教程01: pandas的安装和基本操作
pandas是Python中常用的数据处理库,主要用来处理表格数据,类似于下面这种: 好好干文化有限公司员工薪资表 姓名 年龄 性别 年薪 奖金 久九刘 35 男 182600 42000 傅儿待 ...
- 数学问题,2的n次方 - 1 是怎么来的? 通常用作计算数值