如何在单片机外部Flash存储器上部署高效文件系统:从原理到实现

news2024/11/15 8:09:13

目录

1.Littlefs文件系统

1.1文件系统简介

2  Littlefs文件系统移植到单片机上

2.1 添加源代码

2.2 编辑接口函数

 2.3 测试代码


1.Littlefs文件系统

1.1文件系统简介

littlefs文件系统源码下载地址:littlefs-project/littlefs: A little fail-safe filesystem designed for microcontrollers (github.com)

 

LittleFS 由ARM官方发布,ARM mbedOS的官方推荐文件系统,具有轻量级,掉电安全的特性。主要用在微控制器和flash上,特点如下:

· 掉电恢复,在写入时即使复位或者掉电也可以恢复到上一个正确的状态。
· 擦写均衡,有效延长flash的使用寿命。例如W25QXX系列的spi接口的flash,擦写次数大概在10万次,如果是操作flash比较频繁那么这10万次很快就会到达上限从而导致芯片废掉。
· 有限的RAM/ROM,相对于FATFS节省ROM和RAM空间

 · 缺点:不兼容windows。

2. Littlefs文件系统移植到单片机上

2.1 添加源代码

从github上下载好源代码之后,将他放在我们的工程下:

然后再创建一个C文件用于存放我们的接口函数:

笔者采用的是动态内存分配方式,如果各位也想采用动态内存的分配方式的话,需要在自己的单片机上写一个简单的程序测试一下自己的单片机上是否支持malloc()和free()两个函数;

2.2 编辑接口函数

通过查阅Littlefs文件系统的官方REAMD.md文档,以下是给出的示例代码:

#include "lfs.h"

// variables used by the filesystem
lfs_t lfs;
lfs_file_t file;

// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
    // block device operations
    .read  = user_provided_block_device_read,
    .prog  = user_provided_block_device_prog,
    .erase = user_provided_block_device_erase,
    .sync  = user_provided_block_device_sync,

    // block device configuration
    .read_size = 16,
    .prog_size = 16,
    .block_size = 4096,
    .block_count = 128,
    .cache_size = 16,
    .lookahead_size = 16,
    .block_cycles = 500,
};

// entry point
int main(void) {
    // mount the filesystem
    int err = lfs_mount(&lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err) {
        lfs_format(&lfs, &cfg);
        lfs_mount(&lfs, &cfg);
    }

    // read current count
    uint32_t boot_count = 0;
    lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
    lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));

    // update boot count
    boot_count += 1;
    lfs_file_rewind(&lfs, &file);
    lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(&lfs, &file);

    // release any resources we were using
    lfs_unmount(&lfs);

    // print the boot count
    printf("boot_count: %d\n", boot_count);
}

我们需要配置结构体struct lfs_config,填写我们自己的spi flash的相应的信息,笔者的spi flash的型号为W25QJVSSIQ,配置如下(这里我把他写成了一个函数):

接口函数主要就是cfg这个结构中的read、prog、erase、sync这四个函数指针,将这四个函数指针指向我们实际的FLASH操作函数即可,示例如下:

 2.3 测试代码

完整的测试代码如下:

void lfs_test()
{
	lfs_t 						lfs;
	lfs_file_t 					file;

	const char					*message = "Hello, LittleFS!";
	char 						buffer[100];
	lfs_ssize_t 				read_size;
	int							err;
	uint32_t					boot_count = 0;
	/* Configure the little fs file system */
	init_lfs_config();
	HAL_Delay(10);
	/* Mount the little fs file system */

	printf("Starting lfs_test\n");
	HAL_Delay(10);
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Mounting file system...\n");
#endif
	err = lfs_mount(&lfs, &cfg);
	if( err )
	{
		SPI_Flash_ChipErase();
		printf("start to fromat...\r\n");
		err = lfs_format( &lfs, &cfg );
		if( err )
		{
            printf("lfs_format error: %d\r\n", err);
            return ;
		}
		printf("format successful\n");
		err = lfs_mount(&lfs, &cfg);
		if (err)
		{
			printf("lfs_mount error: %d\r\n", err);
		    return;
		}
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("the first period okey\r\n");
#endif
	/* read current count */
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Opening file...\n");
#endif
	err = lfs_file_open( &lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
	if ( err )
	{
	    printf("lfs_file_open error: %d\r\n", err);
	    lfs_unmount(&lfs);
	    return;
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("File opened successfully\r\n");
#endif
	/* Read and start automatic counting */
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Reading boot count...\r\n");
#endif
	read_size = lfs_file_read( &lfs, &file, &boot_count, sizeof(boot_count) );
	if( read_size < 0 )
	{
		printf("lfs_file_read error :%d\r\n", read_size);
		lfs_file_close(&lfs, &file);
		lfs_unmount(&lfs);
		return;
	}
	else if( read_size == 0 )
	{
		boot_count = 0;
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Boot count read successfully: %d\r\n", boot_count);
#endif
	boot_count += 1;
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Rewinding file...\r\n");
#endif
	err = lfs_file_rewind( &lfs, &file);
	if (err)
	{
		printf("lfs_file_rewind error: %d\r\n", err);
		lfs_file_close(&lfs, &file);
		lfs_unmount(&lfs);
		return;
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("File rewinded successfully\r\n");
	littlefs_print("Writing new boot count...\r\n");
#endif
	err = lfs_file_write( &lfs, &file, &boot_count, sizeof(boot_count) );
	if (err < 0 )
	{
		printf("lfs_file_write error: %d\r\n", err);
		lfs_file_close(&lfs, &file);
		lfs_unmount(&lfs);
		return;
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("Closing file...\r\n");
#endif
	err = lfs_file_close(&lfs, &file);
	if (err < 0)
	{
		printf("lfs_file_write error: %d\r\n", err);
		return;
	}
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("File closed successfully\r\n");
	littlefs_print("Unmounting file system...\r\n");
#endif
	lfs_unmount(&lfs);
#ifdef CONFIG_LITTLEFS_DEBUG
	littlefs_print("File system unmounted successfully.\r\n");
#endif
	printf("boot_count:%d\r\n", boot_count);
	HAL_Delay(100);

}



最后在主函数中调用void test()函数,如果成功安装文件系统之后,我们每次按下复位键会发现boot_count每次都自加1.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1927286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity Shader学习笔记

Shader类型 类型详情Standard Surface Shader标准表面着色器&#xff0c;基于物理的着色系统&#xff0c;用于模拟各种材质效果&#xff0c;如石头、木材、玻璃、塑料和金属等。Unlit Shader最简单的着色器&#xff0c;不包含光照但包含雾效&#xff0c;只由最基础的Vertex Sh…

Pytorch使用Dataset加载数据

1、前言&#xff1a; 在阅读之前&#xff0c;需要配置好对应pytorch版本。 对于一般学习&#xff0c;使用cpu版本的即可。参考教程点我 导入pytorch包&#xff0c;使用如下命令即可。 import torch # 注意虽然叫pytorch&#xff0c;但是在引用时是引用torch2、神经网络获取…

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

六、STM32F4+标准库+LWIP2.1.2移植+无操作系统

最快最简单的移植LWIP协议栈&#xff0c;可改可不改的东西统一不修改。后期学会了有能力了再回过头来修改&#xff0c;操作复杂理论复杂&#xff0c;同时讲解对新手不是很友好&#xff0c;故此此文档只讲操作无任何理论讲解。 零、所需文件及环境 1、第四章建立好的串…

51单片机11(蜂鸣器硬件设计和软件设计)

一、蜂鸣器硬件设计 1、 2、上面两张图&#xff0c;是针对不同产品的电路图。像左边这一块&#xff0c;是我们的A2&#xff0c;A3&#xff0c;A4的一个产品对应的一个封闭器的硬件电路。而右边的这一块是对应的A5到A7的一个硬件电路。因为A5到A7的一个产品&#xff0c;它的各…

排序算法3_冒泡排序、快速排序

一、冒泡排序 1.1 冒泡排序定义和思路 冒泡排序的基本思想是&#xff1a;通过相邻两个元素之间的比较和交换&#xff0c;使较大的元素逐渐从前面移向后面&#xff08;升序&#xff09;&#xff0c;就像水底下的气泡一样逐渐向上冒泡&#xff0c;所以被称为“冒泡”排序。  在…

【YOLOv8】 用YOLOv8实现数字式工业仪表智能读数(二)

上一篇圆形表盘指针式仪表的项目受到很多人的关注&#xff0c;咱们一鼓作气&#xff0c;把数字式工业仪表的智能读数也研究一下。本篇主要讲如何用YOLOV8实现数字式工业仪表的自动读数&#xff0c;并将读数结果进行输出&#xff0c;若需要完整数据集和源代码可以私信。 目录 &…

王牌站士Ⅹ---人工智能中的数据隐私:PII 与个人信息

前言 今天&#xff0c;我将讨论如何区分美国和全球范围内不断涌现的数据隐私法所涵盖和不涵盖的数据类型。不同类型的数据受到更严格的保护&#xff0c;具体取决于司法管辖区&#xff0c;因此&#xff0c;如果您使用个人数据进行分析或机器学习&#xff0c;了解这一点很重要。…

痛心!不会用ChatGPT,差点错失一个亿

ChatGPT爆火这么久,今天我们也来聊聊GPT的玩法。等下,什么?你没听说过?没用过? 没听过没用过的朋友们,你们知道当我听到这回答的时候是多么痛心疾首吗? 为了让你们更直观的感受到,举个栗子,如果你用了GPT,就不需要抓耳挠腮的想方案了;如果你用了GPT,或许工作学习效…

MySQL 数据库 - 事务

MySQL 数据库&#xff08;基础&#xff09;- 事务 事务简介 事务 是一组操作集合&#xff0c;他是一个不可分割的工作单位&#xff0c;事务会把所有的操作看作是一个整体一起向系统发送请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 比如&#xff1a;张…

《Python数据科学之三:探索性数据分析与可视化》

《Python数据科学之三&#xff1a;探索性数据分析与可视化》 在数据科学项目中&#xff0c;探索性数据分析&#xff08;EDA&#xff09;和数据可视化是至关重要的步骤。它们帮助数据科学家理解数据的特征、发现数据中的模式和异常值&#xff0c;从而为后续的数据分析和机器学习…

python-29-零基础自学python-json、函数等存取用户数据+验证用户信息

学习内容&#xff1a;《python编程&#xff1a;从入门到实践》第二版 知识点&#xff1a; 如何验证用户、try-except-else处理异常 if判断、def方法及拆解方法 json引入、存储、读取 return none和return变量返回值很重要 answer 1 和answer “1”在使用后的区别 练习内容…

IDEA创建项目模块右边缺少Maven的解决

一、问题描述 我们在创建项目模块时&#xff0c;创建为Maven工程&#xff0c;创建后只是普通工程&#xff0c;idea右边缺少Mavenue标识管理 如图 二、问题的解决方法 在模块的pom.xml文件&#xff0c;点击选项&#xff0c;添加为Maven工程 如图 至此&#xff0c;创建maven工程…

2-34 小波神经网络采用传统 BP 算法

小波神经网络采用传统 BP 算法&#xff0c;存在收敛速度慢和易陷入局部极小值两个突出弱点。建立了基于遗传算法的小波神经网络股票预测模型 GA-WNN。该模型结合了遗传算法的全局优化搜索能力以及小波神经网络良好的时频局部特性。运用 MATLAB 对拟合和预测过程进行仿真。结果表…

COLING 2024 | AlphaFin:基于LLM的股票预测大模型,显著提高预测能力

COLING 2024 | AlphaFin&#xff1a;基于LLM的股票预测大模型&#xff0c;显著提高预测能力 发布于 2024-06-13 18:31:49 目前&#xff0c;机器学习和深度学习算法&#xff08;ML&DL&#xff09;已被广泛应用于股票趋势预测&#xff0c;并取得了显著进展。然而&#xff0c…

CSS在页面中使用的三种方式:行内样式、内嵌式样式表、链接式样式表

CSS样式如何在页面中使用&#xff0c;包含三种方式&#xff1a;行内样式、内嵌式样式表、链接式样式表。 CSS样式的使用系列博文&#xff1a; 《CSS在页面中使用的三种方式&#xff1a;行内样式、内嵌式样式表、链接式样式表》 《CSS选择器&#xff1a;基本选择器、复合选择器、…

Android TabLayout+ViewPager2如何优雅的实现联动详解

一、介绍 Android开发过程中&#xff0c;我们经常会遇到滑动导航栏的做法&#xff0c;之前的做法就是我们通过ViewGroup来转动&#xff0c;然后通过大量的自定义来完成&#xff0c;将导航栏item与viewpage 滑动&#xff0c;达到业务需求 二、现实方案 通过介绍&#xff0c;我…

Springboot 校园安全通事件报告小程序-计算机毕业设计源码02445

Springboot 校园安全通事件报告小程序系统 摘 要 随着中国经济的飞速增长&#xff0c;消费者的智能化水平不断提高&#xff0c;许多智能手机和相关的软件正在得到更多的关注和支持。其中&#xff0c;校园安全通事件报告小程序系统更是深得消费者的喜爱&#xff0c;它的出现极大…

揭秘|SSL证书年度费用:网络安全预算规划指南

在数字化时代&#xff0c;网络安全已成为企业不可或缺的一部分。对于任何在线业务而言&#xff0c;保护客户数据和维护网站安全至关重要。其中&#xff0c;SSL&#xff08;Secure Sockets Layer&#xff09;证书扮演着关键角色&#xff0c;它通过加密网站与用户之间的通信来确保…

[JS]Generator

介绍 Generator函数是 ES6 提供的一种异步编程解决方案, async是该方案的语法糖 核心语法 Generator对象由生成器函数返回, 并且它符合可迭代协议和迭代器协议 生成器函数在执行时能暂停, 后面又从暂停处继续执行 <script>// 1.定义生成器函数function* testGenerato…