1、虚拟文件系统
本节内容建议参考:文件系统RT-Thread官方介绍,我也是copy过来的。
文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型 (Abstract data type),是一种用于向用户提供底层数据访问的机制。文件系统通常存储的基本单位是文件,即数据是按照一个个文件的方式进行组织。当文件比较多时,将导致文件繁多,不易分类、重名的问题。而文件夹作为一个容纳多个文件的容器而存在。
DFS简介
DFS 是 RT-Thread 提供的虚拟文件系统组件,全称为 Device File System,即设备虚拟文件系统。
DFS架构
- 提供统一的POSIX接口给应用程序。
- 支持多种类型的文件系统。
- 支持多种存储设备。
POSIX接口层
- POSIX 表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写 POSIX),POSIX 标准定义了操作系统应该为应用程序提供的接口标准,是 IEEE 为要在各种 UNIX 操作系统上运行的软件而定义的一系列 API 标准的总称。
- POSIX 标准意在期望获得源代码级别的软件可移植性。换句话说,为一个 POSIX 兼容的操作系统编写的程序,应该可以在任何其它 POSIX 操作系统(即使是来自另一个厂商)上编译执行。RT-Thread 支持 POSIX 标准接口,因此可以很方便的将 Linux/Unix 的程序移植到 RT-Thread 操作系统上。
- 在类 Unix 系统中,普通文件、设备文件、网络文件描述符是同一种文件描述符。而在 RT-Thread 操作系统中,使用 DFS 来实现这种统一性。有了这种文件描述符的统一性,我们就可以使用 poll/select 接口来对这几种描述符进行统一轮询,为实现程序功能带来方便。
- 使用 poll/select 接口可以阻塞地同时探测一组支持非阻塞的 I/O 设备是否有事件发生(如可读,可写,有高优先级的错误输出,出现错误等等),直至某一个设备触发了事件或者超过了指定的等待时间。这种机制可以帮助调用者寻找当前就绪的设备,降低编程的复杂度。
虚拟文件系统层
用户可以将具体的文件系统注册到DFS中。
设备抽象层
设备抽象层将物理设备如 SD Card、SPI Flash、Nand Flash,抽象成符合文件系统能够访问的设备。例如 FAT 文件系统要求存储设备必须是块设备类型。
不同文件系统类型是独立于存储设备驱动而实现的,因此把底层存储设备的驱动接口和文件系统对接起来之后,才可以正确地使用文件系统功能。
注册设备
文件系统的初始化过程一般分为以下几个步骤:
- 初始化 DFS 组件。
- 初始化具体类型的文件系统。
- 在存储器上创建块设备。
- 格式化块设备。
- 挂载块设备到 DFS 目录中。
- 当文件系统不再使用,可以将它卸载。
文件系统注册:
注册块设备
格式化过程
………………………………………………!!!
2、SFUD组件
SFUD 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。
详情查看gitee开源资料:SFUD官方介绍
3、正点原子F407移植
- 正点原子F407开发板
- ENV工具
- Keil编译器
- RT-Thread4.0.5源码
生成dist
进入目录打开env工具,进入配置界面
打开SPI FLASH
如果不是已经做好的BSP,这里需要单独打开以下select的东西。
打开文件系统
扇区大小改为4096。
退出保存!!!!!
这些代码是SFUD框架注册的代码。这样我们就可以通过SFUD去驱动我们的flash存储芯片了。
#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_spi.h"
#if defined(BSP_USING_SPI_FLASH)
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
rt_hw_spi_device_attach("spi1", "spi10", GPIOB, GPIO_PIN_14);
if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
{
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
此时还没有将flash挂载到文件系统上。我们需要自己写。通过上面的步骤,我们需要格式化flash和挂载。
格式化:
int dfs_mkfs(const char * fs_name, const char * device_name);
挂载:
int dfs_mount(const char *device_name,
const char *path,
const char *filesystemtype,
unsigned long rwflag,
const void *data);
#include "dfs_fs.h"
static int rt_hw_spi_file_system_init(void)
{
dfs_mkfs("elm","W25Q128");
if(dfs_mount("W25Q128", "/","elm",0,0) == 0) //注册块设备,这一步可以将外部flash抽象为系统的块设备
{
return -RT_ERROR;
}
return RT_EOK;
}
INIT_ENV_EXPORT(rt_hw_spi_file_system_init);
编译下载
一些问题
扇区大小需要修改,不然就是设备的扇区大小大于 FAT 的扇区大小
文件系统挂载的时候,文件系统一定要初始化好!!!
INIT_ENV_EXPORT(rt_hw_spi_file_system_init);
最开始我是直接把挂载操作写在rt_hw_spi_flash_init
函数里面的,然后用的是自动初始化机制中的组件初始化INIT_COMPONENT_EXPORT
,elm文件系统系统初始化也是INIT_COMPONENT_EXPORT
,所以就会造成文件系统还没准备好,就挂载。