RT-Thread 学习笔记(七)---开启基于SPI Flash的elmfat文件系统(中)

在RT-Thread Studio配置SPI Flash littlefs文件系统 记录踩过的坑与您分享 阅读详情

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2

硬件环境:Armfly STM32F103ZE-EK v3.0开发板

参考文章:RT-Thread编程指南

[RTthread]新版本RTT中的SPI驱动框架

Github托管的Realtouch分支中examples目录中spi flash的例程

【1】RT-Thread 1.2.x中组件初始化代码分析

上篇文章中介绍了spi flash的相关驱动文件添加和相关代码修改,编译虽然能通过但并不代表能够调试通过。因为针对rt-thread-1.2.x版本采用了组件初始化功能,具体是components.c中实现的,请看下面代码:

/**
 * RT-Thread Components Initialization
 */
void rt_components_init(void)
{
#ifndef _MSC_VER
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;

rt_kprintf("do components intialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
    const init_fn_t *fn_ptr;
    for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
    {
        (*fn_ptr)();
    }

#endif

上面代码蓝色粗体是组件初始化的入口,是一个函数指针。init_fn_t 的定义在rtdef.h中,如下所示:

/* initialization export */
#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
... ...
... ...
    #define INIT_EXPORT(fn, level)  \
        const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn

... ...
... ...
... ...
#endif

其中typdef int (*init_fn_t)(void)的意思是定义init_fn_t为指向函数的指针类型,该函数返回int类型值。这样一来,我们对(*init_fn_t)()的意思就清楚了。

INIT_EXPOT(fn,level) 的表达式是const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn,其中##连词符,SECTION的定义为:

#define SECTION(x)   __attribute__((section(x)))

RealView 编译工具 编译器参考指南中给出了下面的解释:

__attribute__((section("name")))

通常,ARM 编译器将它生成的对象放在节中,如 data 和 bss。但是,您可能需要使用其他数据节,或者希望变量出现在特殊节中,例如,便于映射到特殊硬件。section 属性指定变量必须放在特定数据节中。如果使用 section 属性,则将只读变量放在 RO 数据节中,而将读写变量放在 RW 数据节中,除非您使用 zero_init 属性。在这种情况下,变量被放在 ZI 节中。

到此,意思已经很明了了,编译器可以根据对section("name")中的name指定,可以将它生成的数据放到特定的数据节中,下面引用一个网友electrlife的看法:

类似的这样的方式,Linux也提供了一些借鉴,把一个函数的地址(注意是函数地址,而不是函数本身)输出到一个独立的section中,同时按照一定顺序进行排列,例如:
.rti_fn.0
.rti_fn.1
.rti_fn.2
...
.rti_fn.7
这样几个section(这样几个不同的section也给出了排列的顺序)。同时把.rti_fn.0和.rti_fn.7保留给系统使用,分别定义出两个桩放置在这两个点上。也可以按照RT-Thread的形式定义简化的宏:
typedef int (*init_fn_t)(void);
#define INIT_EXPORT(fn, level)        \
        const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn
#define INIT_BOARD_EXPORT(fn)                INIT_EXPORT(fn, "1")
#define INIT_CPU_EXPORT(fn)                    INIT_EXPORT(fn, "2")
#define INIT_DEVICE_EXPORT(fn)                INIT_EXPORT(fn, "3")
#define INIT_COMPONENT_EXPORT(fn)         INIT_EXPORT(fn, "4")
#define INIT_FS_EXPORT(fn)                      INIT_EXPORT(fn, "5")
#define INIT_APP_EXPORT(fn)                    INIT_EXPORT(fn, "6")
INIT_EXPORT宏用于输出一个函数到初始化序列中,相应的可以定义一些更简化的宏。
这样两个桩可以定义成:
static int rti_start(void)
{
        return 0;
}
INIT_EXPORT(rti_start, "0");
static int rti_end(void)
{
        return 0;
}
INIT_EXPORT(rti_end,"7");
根据这两个桩的位置,简化的rt_components_init()函数就可以变成:
void rt_components_init(void)
{
        const init_fn_t* fn_ptr;
        for (fn_ptr = &__rt_init_rti_start; fn_ptr < &__rt_init_rti_end; )
        {
                (*fn_ptr)();
                fn_ptr ++;
        }
}

事实上,aozima做了工程测试得到了验证:

 工程编译后,从map文件找到相关部分内容:
InitFuncSym$$Base                        0x00000e18   Number         0init_1.o(InitFuncSym)
    __rt_init_init_1                         0x00000e18   Data         4init_1.o(InitFuncSym)
    __rt_init_init_2                         0x00000e1c   Data         4init_2.o(InitFuncSym)
    __rt_init_init_3                         0x00000e20   Data         4init_3.o(InitFuncSym)
    __rt_init_init_4                         0x00000e24   Data         4init_4.o(InitFuncSym)
    __rt_init_init_5                         0x00000e28   Data         4init_5.o(InitFuncSym)
    __rt_init_init_6                         0x00000e2c   Data         4init_6.o(InitFuncSym)
    InitFuncSym$$Limit                     0x00000e30   Number         0init_6.o(InitFuncSym)
尽管数据存放在不同的文件,但从这里这可以看到是空间连续分配的
楼主设定的桩
static int rti_start(void)
{
        return 0;
}
INIT_EXPORT(rti_start, "0");

static int rti_end(void)
{
        return 0;
}
INIT_EXPORT(rti_end,"7");
可由InitFuncSym$$Base和InitFuncSym$$Limit 代替
最后,初始化过程可以写成
      extern int InitFuncSym$$Base;
        extern int InitFuncSym$$Limit;
        init_fn_t* fn;
        for (fn = (init_fn_t *)&InitFuncSym$$Base; fn < (init_fn_t *)&InitFuncSym$$Limit; fn ++ ) {
                (*fn)();
        }

同样的,ffxz也有下面的测试:

参考RTT下的IAR工程,在ICF文件增加一行
keep { section InitFuncSym };
这行关系到以下信息是否生成.
在Debug/List下的map中有这样的描述
.text            ro code0x00000658   0x16xprout.o 
InitFuncSym               0x00000670   0x14<Block>
    InitFuncSym      const    0x00000670    0x4init_1.o 
    InitFuncSym      const    0x00000674    0x4init_2.o 
    InitFuncSym      const    0x00000678    0x4init_4.o 
    InitFuncSym      const    0x0000067c    0x4init_5.o 
    InitFuncSym      const    0x00000680    0x4init_6.o 
.rodata            const    0x00000684   0x10init_1.o 
......
InitFuncSym$$Base   0x00000670         DataGb- Linker created -
InitFuncSym$$Limit    0x00000684         DataGb- Linker created -

总之,通过定义

#define INIT_EXPORT(fn, level)        \
        const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn

可以系统各部分的组件通过INIT_EXPORT(fn,level)放到一个特定代码段当中,简言之,当我们要初始化某个组件时,定义完这个初始化函数后,根据上面宏定义的注释,在其下面接着放一条INIT_XXX_EXPORT(fn)就可以了。相当于一个指定到特定代码段的隐形调用,而且要清楚这个段中是不同组件初始化函数的入口地址,例如:

int my_init_fun(void)

{

... ...

}

INIT_XXX_EXPORT(my_init_fun)

根据以上分析,我们需要工程文件做相应的修改:

【2】工程文件修改

(1)打开sdcard.c文件,定位到3241行附近,修改如下:

int rt_hw_sdcard_init(void)
{
    /* SDIO POWER */

... ...

__return:
    rt_kprintf("sdcard init failed\n");
    GPIO_SetBits(GPIOC,GPIO_Pin_6); /* SD card power down */
    return 0;
}
//INIT_DEVICE_EXPORT(rt_hw_sdcard_init);
... ...
修改完成后保存,因为还没有sd卡的功能,先注释掉,不让系统调用这个初始化函数。
(2)打开rt_spi_flash_device.c文件,定位到94行附近,修改如下:

... ...
}
INIT_DEVICE_EXPORT(rt_hw_spi_init);
#endif /* RT_USING_SPI */
void rt_spi_flash_device_init(void)
{
#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)

w25qxx_init("flash0", "spi11");

#endif /* RT_USING_DFS && RT_USING_DFS_ELMFAT */

... ...

通过在rt_hw_spi_init()下面加上宏语句“INIT_DEVICE_EXPORT(rt_hw_spi_init);”让系统隐含调用它。当然也就不需要在rt_spi_device_init()函数调用它了。

(3)打开application.c,定位到99行附近,确认已经修改成如下代码:

void rt_init_thread_entry(void* parameter)
{
#ifdef RT_USING_COMPONENTS_INIT
    /* initialization RT-Thread Components */
    rt_components_init();
#endif

    rt_spi_flash_device_init();


#ifdef  RT_USING_FINSH
    finsh_set_device(RT_CONSOLE_DEVICE_NAME);
#endif  /* RT_USING_FINSH */

然后定位到文件开头45行附近,加入外部声明,如下:

#include "led.h"

extern void rt_spi_flash_device_init(void);

ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t led_stack[ 512 ];
static struct rt_thread led_thread;
static void led_thread_entry(void* parameter)
{
    unsigned int count=0;


    rt_hw_led_init();

... ...

修改完成后保存。

【3】确认Flash底层驱动的芯片型号识别部分代码是否和开发板上硬件对应上

开发板上的SPI Flash芯片型号SST25VF016B,打开数据手册,定位到第19页,可以看到下图所示定义:


制造商ID号0xBF,器件ID是0x4125,打开spi_flash_w25qxx.c,定位到37行附近,修改如下:

/* JEDEC Manufacturer¡¯s ID */
#define MF_ID           (0xBF) /*(0xEF)*/
/* JEDEC Device ID: Memory type and Capacity */
#define MTC_W25Q16_BV_CL_CV   (0x4015) /* W25Q16BV W25Q16CL W25Q16CV  */
#define MTC_W25Q16_DW         (0x6015) /* W25Q16DW  */
#define MTC_W25Q32_BV         (0x4016) /* W25Q32BV */
#define MTC_W25Q32_DW         (0x6016) /* W25Q32DW */
#define MTC_W25Q64_BV_CV      (0x4017) /* W25Q64BV W25Q64CV */
#define MTC_W25Q64_DW         (0x4017) /* W25Q64DW */
#define MTC_W25Q128_BV        (0x4018) /* W25Q128BV */
#define MTC_W25Q256_FV        (TBD)    /* W25Q256FV */
#define MTC_SST25VF016B       (0x4125) /* SST25V016B */

然后定位到378行附近,修改如下:

... ...

        else if(memory_type_capacity == MTC_W25Q16_DW)
        {
            FLASH_TRACE("W25Q16DW detection\r\n");
            spi_flash_device.geometry.sector_count = 512;
        }
else if(memory_type_capacity == MTC_SST25VF016B)
        {
            FLASH_TRACE("W25Q16DW detection\r\n");
            spi_flash_device.geometry.sector_count = 512;
        }
        else
        {
            FLASH_TRACE("Memory Capacity error!\r\n");
            return -RT_ENOSYS;
        }

... ...

修改完成后保存。

(4) 使用Notepad++打开driver目录下的Sconscript,定位到23行附近,把前面添加到driver目录的rt_spi_device.c,rt_stm32f10x_spi.c,spi_flash_w25qxx.c添加到Depend()中,修改如下:

# add DFS drvers.
if GetDepend('RT_USING_DFS'):
    src += ['rt_spi_flash_device.c','rt_stm32f10x_spi.c','spi_flash_w25qxx.c']


# add RTC drvers.
if GetDepend('RT_USING_RTC'):
    src += ['rtc.c']

这样执行该脚本时,加入驱动文件才能被编译,修改完成后保存。

【4】编译测试

编译后发现如下信息:

drivers\rt_spi_device.c(86): warning:  #144-D: a value of type "void (*)(void)" cannot be used to initialize an entity of type "const init_fn_t"

出现告警:原因是rt_hw_spi_init(void)函数出来问题,这个函数应该定义成int 类型而不是void类型,现在改过来,打开rt_spi_device.c定位到21行附近,修改如下:


#ifdef RT_USING_SPI
static int rt_hw_spi_init(void)
{


    /* register spi bus */
    {

... ...

return 0;


}
INIT_DEVICE_EXPORT(rt_hw_spi_init);
#endif /* RT_USING_SPI */


修改完成后保存,重新编译,OK,编译通过,没有告警。

下载到开发板上运行,结果如下:


Memory 容量错误,挂载失败。

进入跟踪调试模式,打开spi_flash_w25qxx.c,定位到378行,在出现“Memory Capacity error!”地方这个断点,然后点击运行,停到断点处,得到memory_type_capacity的跟踪值如下图所示:


显然是下图中的MTC_SST25VF016B的值定义错了,定位到


往上定位到48行附近,原来是芯片型号定义问题

... ...
#define MTC_W25Q128_BV        (0x4018) /* W25Q128BV */
#define MTC_W25Q256_FV        (TBD)    /* W25Q256FV */
#define MTC_SST25VF016B       (0x4125) /* SST25V016B */
... ...

现在修改成和跟踪到memory_type_capacity值相同:

... ...
#define MTC_SST25VF016B       (0x25
41) /* SST25V016B */

... ...

然后退出调试模式,保存修改,重新编译,下载,运行后,终端信息如下:


可以看到,Flash芯片已经被成功识别,但文件系统还是没有下载成功,因为我们还没有格式化芯片,没有文件系统当然也就识别不到了。下一篇将要研究文件系统相关操作操作。

elm FatFs文件系统移植总结 本文将根据我的一些理解,针对elm FatFs文件系统做一个初步总结。 阅读详情

相关推荐

RT-Thread:W25Q128虚拟U盘并搭载文件系统

文章目录前言一、配置工程二、W25Q128搭载文件系统总结 前言 使用片外Flash W25Q128虚拟成U盘。 一、配置工程 1、打开W25Q128 2、打开USB Drever 3、开启大容量设备,并设置容量设备名称为W25Q128 4、编译、下载和运行,第一次插入电脑后提示需要格式化,我们选择快速格式化即可。 二、W25Q128搭载文件系统 1、参考我之前的博文,注意工程使用刚刚配置好虚拟U盘的工程。 2、编译、下载和运行,发现当前程序只能是要么虚拟成U盘,要么让W25Q128搭载文件系统,

小破孩的博客 2689

rt-thread组件之elmfat文件系统浅析

上一文主要是讲到RTT的文件系统顶层dfs框架及其实现,接下来这篇博文主要是讲述其中间层的一个具体文件系统--elmfat文件系统。rt-thread的elmfat文件系统是一个开源的小型嵌入式文件系统,它的官网是http://elm-chan.org/fsw/ff/00index_e.html,RTT当前版本V1.1.0版本下的elmfat文件系统是从它的R0.08b版本移植而来。本文不打算详情

放飞梦想,成就未来 1万+

IOT-OS之RT-Thread(十)--- DFS文件系统管理与devfs/elmfat示例

文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型 (Abstract data type),是一种用于向用户提供底层数据访问的机制。文件系统通常存储的基本单位是文件,即数据是按照一个个文件的方式进行组织。当文件比较多时,将导致文件繁多,不易分类、重名的问题。而文件夹作为一个容纳多个文件的容器而存在。

流云 9041

RT-Thread:SPI万能驱动 SFUD 驱动Flash W25Q64,通过 STM32CubeMX 配置 STM32 SPI 驱动

说明:RT-Thread 系统 使用SPI万能驱动 SFUD 驱动 Flash W25Q64,通过 STM32CubeMX 配置 STM32 SPI 驱动。

yutian0606的博客 4357

RT-Thread实战:基于SPI Flash的FATFS文件系统移植与优化

本文详细介绍了在RT-Thread实时操作系统中,如何基于SPI Flash移植和优化FATFS文件系统。从环境搭建、驱动移植到性能优化,提供了完整的实战指南,帮助开发者高效实现嵌入式设备的数据存储与管理。重点解析了SPI总线配置、SFUD驱动移植以及FATFS空间优化等关键技术,并分享掉电安全写入等高级应用技巧。

weixin_29291863的博客 387

RT-Thread Radio开发套件深度解析:从硬件选型到内核调试

实时操作系统(RTOS)是嵌入式系统的核心软件平台,它通过任务调度、内存管理和进程间通信等机制,为资源受限的微控制器提供多任务并发执行能力。其技术价值在于能够高效管理硬件资源,确保关键任务的实时响应,从而广泛应用于物联网设备、工业控制和消费电子等领域。本文以RT-Thread Radio网络播放器开发套件为具体案例,深入剖析了其基于STM32F103的硬件架构设计,包括网络、音频、存储等关键外设的协同原理。同时,重点探讨了如何利用RT-Thread内置的Finsh Shell工具进行动态系统状态诊断和实时调

weixin_30947043的博客 403

正点原子探索者stm32f407 rt-thread 文件系统使用

硬件说明:正点原子探索者stm32f407,板载SPI-FLASH W25Q128 系统说明:RT-Thread 3.1.2(以上的其他版本也可以) 在rt-thread-v3.1.2-stm32f407-elmfat\rt-thread\bsp\stm32\stm32f407-atk-explorer下,打开env配置工具, 第一步:进入Hardware Driver Config---&...

u011522841的专栏 3553

Python脚本自动化芯片设计?PyAether实战教程带你玩转EDA

本文通过PyAether实战教程,详细介绍了如何利用Python脚本实现芯片设计自动化。内容涵盖环境搭建、核心对象模型解析,并重点演示了原理图自动生成、参数化单元创建及设计验证流程集成,帮助EDA工程师从重复性手动操作中解放,显著提升设计效率与一致性。

e4f5g6h的博客 1316

RT-Thread DFS 虚拟文件系统:3层架构解析与 FatFs/SPI Flash 实战挂载

本文深入解析RT-Thread DFS虚拟文件系统的3层架构设计,重点介绍FatFs在SPI Flash上的实战挂载方法。通过POSIX接口层、虚拟文件系统层和设备抽象层的协同工作,DFS实现了多文件系统共存与存储介质无关性,为嵌入式开发提供高效数据管理方案。文章包含详细的配置步骤、性能优化技巧和故障排查指南,帮助开发者快速掌握RT-Thread文件系统的核心应用。

weixin_30617797的博客 438

从波士顿动力SpotMini拆解看四足机器人机械设计:关节布局与电机选型的5个关键决策点

本文深入解析波士顿动力SpotMini四足机器人的机械设计,聚焦关节布局与电机选型的5个关键决策点。通过拆解髋关节偏移距、膝关节传动链、电机热管理等核心设计,揭示商业级四足机器人的工程智慧,为工业巡检、物流机器人等应用提供实用参考。

postgres8guard的博客 893

从仿真到部署:基于ROS2与Gazebo的UR5e机械臂全流程控制实践

本文详细介绍了基于ROS2与Gazebo的UR5e机械臂全流程控制实践,从环境准备、模型构建到控制器开发和仿真优化,最终实现真实机器人部署。通过实战案例和避坑指南,帮助开发者掌握机器人仿真与控制的关键技术,提升UR5e机械臂在物料分拣等任务中的性能与稳定性。

weixin_29184371的博客 288

rt-thread下调试elmfat 问题记录

硬件平台:stm32f107 SPI flash:w25q32 RTT版本:v2.1 w25q32的驱动大神们已经写好(w25qxx.c),我只需要照猫画虎的实现相应SPI的驱动程序即可(bsp例程都有),如此spi flash就可以读写了。查看device列表如下: 接着启用DFS功能和ELMFAT类型文件系统,并挂载文件系统名为“elm”的文件系统到介质为flash0的...

650

SpringCloud2025+SpringBoot3.5.0动态路由503问题排查与负载均衡依赖解析

本文详细排查了SpringCloud 2025与SpringBoot 3.5.0环境下,Spring Cloud Gateway动态路由返回503错误的根本原因。核心问题在于新版网关未默认集成负载均衡器,导致无法解析lb://服务名。通过对比静态路由与动态路由,定位到需显式引入spring-cloud-starter-loadbalancer依赖,并提供了完整的解决方案与最佳实践配置。

s3t4u的博客 504

RT-Thread:在运行RTT的GD32E103的Flash芯片上挂载文件系统

文章目录前言一、pandas是什么?1.引入库2.读入数据总结 前言 一、pandas是什么? 添加文件件 添加路径 加大栈空间 加大动态内存池 运行成功 内存总使用情况 1.引入库 代码如下(示例): import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings('ignore')

小破孩的博客 1503

避开这5个坑!Tushare数据获取与清洗的常见问题解决方案

本文详细解析了使用Tushare进行金融数据分析时常见的5大问题,包括Token失效、数据缺失、频率限制等,并提供了Python实战解决方案。通过智能填充策略、队列化管理和分层存储设计,帮助开发者高效获取和清洗金融数据,提升量化分析效率。特别适合金融数据分析师和Python开发者参考。

f9g0h的博客 421

ruoyi-nbcio-plus基于vue3的flowable服务任务的升级修改

ruoyi-nbcio-plus基于vue3的flowable服务任务的升级修改

宁波阿成的博客 847

RT-Thread 学习笔记(六)--- 开启基于SPI Flash的elmfat文件系统(上)

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2 硬件环境:Armfly STM32F103ZE-EK v3.0开发板 参考文章:RT-Thread编程指南 在RT-Thread默认的是SD卡作为文件系统挂载,代码如下: /* Filesystem Initi

aping_cs_dn的专栏 1万+

12027.linux flash驱动之IS25LP01G/IS25WWP01G

一页:512字节 --> 扇区 4096字节 --> 块 32k,64k, 层层递进关系。

写给自己的笔记 2289

RT-Thread星火一号开发板BSP进阶:如何用ENV工具开启SD卡和W25Q128 Flash支持

本文详细介绍了如何在RT-Thread星火一号开发板上使用ENV工具配置SD卡和W25Q128 Flash支持。通过实战步骤和代码示例,帮助开发者快速启用存储设备并挂载文件系统,适用于STM32F407开发板的存储扩展需求。

weixin_33739523的博客 675

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

RT-Thread 学习笔记(八)---开启基于SPI Flash的elmfat文件系统(下)

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2 硬件环境:Armfly STM32F103ZE-EK v3.0开发板 参考文章:RT-Thread编程指南 [RTthread]新版本RTT中的SPI驱动框架 Github托管的Realtouch分支中examples目录

aping_cs_dn的专栏 8853

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

RT-Thread DFS 排错指南:解决文件系统挂载失败的 5 个常见根因与修复

本文深入解析RT-Thread DFS文件系统挂载失败的5大常见问题,包括设备未注册、扇区大小不匹配、长文件名配置冲突等,提供详细的解决方案和调试技巧。通过实战案例和代码示例,帮助开发者快速定位并修复DFS虚拟文件系统问题,确保嵌入式系统稳定运行。

weixin_33874713的博客 411

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

STM32F407+W25Q128上跑RT-Thread文件系统:DFS+elm-FAT+SFUD实战

虚拟文件系统(VFS)为嵌入式应用提供统一的POSIX文件操作接口,屏蔽底层存储介质差异。其核心原理是通过块设备抽象层将SPI Flash等硬件封装为标准块设备,再由elm-FAT等文件系统实现管理扇区分配与目录结构。在STM32F407与W25Q128平台上,结合RT-Thread的DFS、elm-FAT和SFUD组件,可快速构建稳定可靠的嵌入式文件系统,支持数据记录、固件备份与远程导出等场景。本文分享从块设备注册到文件读写的完整工程实践与避坑经验。

weixin_34195142的博客 265

RT-Thread—FAL与EasyFlash组件移植

一、FAL管理与示例   FAL (Flash Abstraction Layer) Flash 抽象层,是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层,对上层统一了 Flash 及 分区操作的 API ,FAL 框架图如下:   从上图可以看出FAL抽象层位于SFUD框架的上层,可以将多个Flash硬件(包括片内Flash和片外Flash)统一进行管理,并向上层比如DFS文件系统层提供对底层多个Flash硬件的统一访问接口,方便上层应用对底层

鸿墨轩 2224

STM32F407 上基于 RT-Thread 与 W25Q128 的 FAT 文件系统移植实战

虚拟文件系统(VFS)通过抽象物理存储接口,将 Flash 扇区操作转化为标准文件读写,显著提升嵌入式存储管理的灵活性。其核心原理在于分层驱动架构,结合 SPI 总线与 Flash 通用驱动(SFUD),实现块设备到文件系统的无缝对接。在 STM32F407 与 W25Q128 的典型应用中,借助 RT-Thread 的 DFS 框架和 elm-FAT 组件,开发者可快速构建类似 U 盘的文件管理能力,适用于配置存储、日志记录及数据缓存等场景。SPI Flash 文件系统移植的关键在于扇区大小匹配与底层通信

weixin_33912453的博客 206

RT-Thread DFS文件系统集成:W25Q128+ELM FATFS实战

嵌入式文件系统是实现数据持久化与结构化管理的核心技术,其本质是通过虚拟文件系统(VFS)抽象硬件差异,将底层块设备(如SPI Flash)映射为标准POSIX接口。RT-Thread的DFS框架以分层设计(设备驱动→DFS抽象→文件系统→VFS)支撑轻量级、可裁剪的工程落地,关键技术在于扇区对齐与擦除写入协同——尤其在W25Q128等SPI Flash上,必须严格匹配物理擦除单元(4096字节)与ELM FATFS逻辑扇区配置,否则导致挂载失败或数据损坏。该方案广泛应用于工业日志存储、固件升级、配置管理等需

juice的博客 644
上一篇: RT-Thread 学习笔记(六)--- 开启基于SPI Flash的elmfat文件系统(上)
下一篇: RT-Thread 学习笔记(八)---开启基于SPI Flash的elmfat文件系统(下)
aping_cs_dn
博客等级 码龄19年 188粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aping_cs_dn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值