stm32f103rct6+freertos+platformio LittleFS移植记录
本文介绍了将LittleFS文件系统适配到NOR Flash和NAND Flash的步骤。主要内容包括:1)从GitHub获取LittleFS源码并集成到工程中;2)修改内存管理函数为FreeRTOS接口;3)实现底层Flash读写接口函数;4)在STM32F103+FreeRTOS平台测试验证。通过重写read、prog、erase和sync函数,实现了LittleFS对W25Q系列Flash的
相关文章: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_size 和 block_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的数据不会丢失:

更多推荐



所有评论(0)