相关文章:littlefs文件系统适配norflash和nandflash_鸿蒙系统_hs977986979-华为开发者空间

1.下载源码

在github下载littlefs

littlefs-project/littlefs: A little fail-safe filesystem designed for microcontrollers

2.添加源码到工程

将四个文件加入工程lfs.c,lfs.h,lfs_util.c,lfs_util.h

修改lfs_util.h:

替换MALLOC和Free函数接口,由c库函数更改为freertos对应函数,及添加断言以便debug

index c1999fa..9dd9765 100644
--- a/Lib/littlefs/lfs_util.h
+++ b/Lib/littlefs/lfs_util.h
@@ -43,7 +43,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <inttypes.h>
-
+#include "FreeRTOS.h"
 #ifndef LFS_NO_MALLOC
 #include <stdlib.h>
 #endif
@@ -68,6 +68,7 @@ extern "C"
 // code footprint

 // Logging functions
+#define LFS_YES_TRACE
 #ifndef LFS_TRACE
 #ifdef LFS_YES_TRACE
 #define LFS_TRACE_(fmt, ...) \
@@ -113,6 +114,13 @@ extern "C"
 #ifndef LFS_NO_ASSERT
 #define LFS_ASSERT(test) assert(test)
 #else
+#define assert(x)            \
+    if ((x) == 0)                 \
+    {                             \
+        __asm volatile("ebreak"); \
+        for (;;)                  \
+            ;                     \
+    }
 #define LFS_ASSERT(test)
 #endif
 #endif
@@ -246,7 +254,9 @@ static inline void *lfs_malloc(size_t size) {
 #if defined(LFS_MALLOC)
     return LFS_MALLOC(size);
 #elif !defined(LFS_NO_MALLOC)
-    return malloc(size);
+//     return malloc(size);
+        extern void *pvPortMalloc( size_t xWantedSize );
+        return pvPortMalloc(size);
 #else
     (void)size;
     return NULL;
@@ -258,7 +268,9 @@ static inline void lfs_free(void *p) {
 #if defined(LFS_FREE)
     LFS_FREE(p);
 #elif !defined(LFS_NO_MALLOC)
-    free(p);
+//     free(p);
+        extern void vPortFree( void *pv );
+        vPortFree(p);
 #else
     (void)p;
 #endif

3.新建lfs_port.c

重写cfg中,read,prog,erase,sync函数,本文默认设置为静态内存。另外底层实现在基于stm32 hal库实现驱动flash w25q16_stm32驱动w25q16-CSDN博客

在配置参数时,.block_size = 4096.block_count = 512 的原因可以从 W25Q16JV datasheet 中得到依据:

W25Q16 datasheet:W25Q16JVSSIQ -PDF数据手册-参考资料-立创商城

“Pages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or the entire chip (chip erase). The W25Q16JV has 512 erasable sectors and 32 erasable blocks respectively. The small 4KB sectors allow for greater flexibility in applications that require data and parameter storage.”

从这段原文可知:

  • 最小擦除单位是 4KB sector → 因此 .block_size = 4096

  • 器件共有 512 个 sector → 因此 .block_count = 512

这样一来,总容量 = 4096 × 512 = 2MB(16M-bit),与 W25Q16 的标称容量一致。

需要注意的是:block_sizeblock_count 的取值应根据实际使用的 NOR Flash 容量来确定。

以本文使用的 W25Q16 为例:
通过查阅 datasheet 可知,其最小擦除单位为 4KB,且共有 512 个可擦除 sector,因此 block_size 取 4096,block_count 取 512。

#define OFFSETBLOCK 		3
/**
 * lfs与底层flash读数据接口
 * @param  c
 * @param  block  块编号
 * @param  off    块内偏移地址
 * @param  buffer 用于存储读取到的数据
 * @param  size   要读取的字节数
 * @return
 */
static int lfs_deskio_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
	if(W25Qx_OK == w25qxx_read((uint8_t *)buffer, c->block_size * (OFFSETBLOCK+block) + off, size))
                return LFS_ERR_OK;
        else
                return LFS_ERR_IO;
}

/**
 * lfs与底层flash写数据接口
 * @param  c
 * @param  block  块编号
 * @param  off    块内偏移地址
 * @param  buffer 待写入的数据
 * @param  size   待写入数据的大小
 * @return
 */
static int lfs_deskio_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{

        if(W25Qx_OK == w25qxx_write((uint8_t *)buffer, c->block_size * (OFFSETBLOCK+block) + off, size))
                return LFS_ERR_OK;
        else
                return LFS_ERR_IO;
}

/**
 * lfs与底层flash擦除接口
 * @param  c
 * @param  block 块编号
 * @return
 */
static int lfs_deskio_erase(const struct lfs_config *c, lfs_block_t block)
{
        printf("block:%d,i:%d",block,(OFFSETBLOCK+block)*c->block_size);
	if(W25Qx_OK == w25qxx_erase_block((OFFSETBLOCK+block)*c->block_size))
	// int ret = w25qxx_erase_block((OFFSETBLOCK+block));
                return LFS_ERR_OK;
        else
                return LFS_ERR_IO;
}

static int lfs_deskio_sync(const struct lfs_config *c)
{
        if(W25Qx_OK == w25qxx_getstatus())
                return LFS_ERR_OK;
        else
                return LFS_ERR_IO;
}





///
/// 静态内存使用方式必须设定这四个缓存
///
__attribute__((aligned(4))) static uint8_t read_buffer[256];
__attribute__((aligned(4))) static uint8_t prog_buffer[256];
__attribute__((aligned(4))) static uint8_t lookahead_buffer[256];


const struct lfs_config lfs_w25qxx_cfg =
{
        // block device operations
        .read  = lfs_deskio_read,
        .prog  = lfs_deskio_prog,
        .erase = lfs_deskio_erase,
        .sync  = lfs_deskio_sync,

        // block device configuration
        .read_size = 256,
        .prog_size = 256,
        .block_size = 4096,
        .block_count = 512,
        .cache_size = 256,
        .lookahead_size = 128,
        .block_cycles = 500,

        .name_max=128,
        .file_max=128, 
        .attr_max=128,
        // .context=512,

        // 使用静态内存必须设置这几个缓存

        .read_buffer = read_buffer,
        .prog_buffer = prog_buffer,
        .lookahead_buffer = lookahead_buffer,
};

4.测试

运行环境:stm32f103rct6+freertos+platformio

测试代码:


int bytes_to_mb(uint32_t bytes) {
        // 1MB = 2^20 = 1048576 bytes
        // 先把 bytes 放大 1000 倍(为了获得小数点后三位)
        // 避免乘法溢出,uint64_t 容量要够大
        uint64_t bytes_x1000 = (uint64_t)bytes * 1000;

        // 整数除法,计算放大1000倍的 MB 数
        uint32_t mb_x1000 = (uint32_t)(bytes_x1000 >> 20); // 除以 2^20

        // 分离整数和小数部分
        uint32_t mb = mb_x1000 / 1000;
        uint32_t mb_frac = mb_x1000 % 1000;

        printf("Converted to: %u.%03u MB\n", mb, mb_frac);
        return 0;
}


int lfs_first_run(void){
        lfs_t lfs;
        lfs_file_t file;
        // w25qxx_erase_chip();
        // mount the filesystem
        int err = lfs_mount(&lfs, &lfs_w25qxx_cfg);

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

        // 检查剩余空间
        int total_blocks = lfs_w25qxx_cfg.block_count;
        int used_blocks = lfs_fs_size(&lfs);
        int free_blocks = total_blocks - used_blocks;
        printf("Free space: %d blocks (%d bytes)\n", 
        free_blocks, free_blocks * lfs_w25qxx_cfg.block_size);
        bytes_to_mb(free_blocks * lfs_w25qxx_cfg.block_size);


        // // 写入文件
        // lfs_file_t file;
        // lfs_file_open(&lfs, &file, "test.txt", LFS_O_WRONLY | LFS_O_CREAT);
        // lfs_file_write(&lfs, &file, "Hello World", 11);
        // lfs_file_close(&lfs, &file);

        // // 读取文件
        // lfs_file_open(&lfs, &file, "test.txt", LFS_O_RDONLY);
        // char buffer[64];
        // lfs_file_read(&lfs, &file, buffer, sizeof(buffer));
        // lfs_file_close(&lfs, &file);
        // printf("test.txt: %s\n", buffer);

        // // 删除文件
        // err = lfs_remove(&lfs, "test.txt");
        // if (err) {
        //         printf("remove test.txt fail\n");
        // }

        // 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);

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


        lfs_dir_t dir;
        struct lfs_info info;

        lfs_dir_open(&lfs, &dir, "/");
        while (lfs_dir_read(&lfs, &dir, &info)) {
        printf("%s (%s, size: %d)\n", 
                info.name,
                info.type == LFS_TYPE_REG ? "file" : "dir",
                info.size);
        }
        lfs_dir_close(&lfs, &dir);

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

测试结果,掉电后写入norflash的数据不会丢失:

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐