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

目录

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.

上一篇:Spring MVC 中的拦截器的使用“拦截器基本配置” 和 “拦截器高级配置”


下一篇:ServiceNow UI Jelly模板注入漏洞复现(CVE-2024-4879)