简介
Spiffs是一种用于嵌入式目标上 SPI NOR flash 的文件系统
Spiffs的设计考虑到以下特点:
- 小型(嵌入式)系统,极少的 RAM
- 只能擦除大面积的数据(块)
- 擦除会将块中的所有位重置为1
- 写将1置为0
- 0只能通过擦除置为1
- 磨损平衡
下载源码
使用最新的 Tag: 0.3.7 (https://github.com/pellepl/spiffs/tree/0.3.7)
复制文件,添加工程
复制以下 8 个文件到你的工程目录,大部分文件在 /src 目录下,spiffs_config.h 在 /src/default 目录下。并添加当前目录到 include 搜索目录。
spiffs.h
spiffs_cache.c
spiffs_check.c
spiffs_config.h
spiffs_gc.c
spiffs_hydrogen.c
spiffs_nucleus.c
spiffs_nucleus.h
修改配置文件
spiffs_config.h
注释掉 #include "params_test.h"
//#include "params_test.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
修改以下两个宏为 1,有利于加快访问速度
#define SPIFFS_USE_MAGIC (1)
#define SPIFFS_USE_MAGIC_LENGTH (1)
// Enable this to have an identifiable spiffs filesystem. This will look for
// a magic in all sectors to determine if this is a valid spiffs system or
// not on mount point. If not, SPIFFS_format must be called prior to mounting
// again.
#ifndef SPIFFS_USE_MAGIC
#define SPIFFS_USE_MAGIC (1)
#endif
#if SPIFFS_USE_MAGIC
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
// enabled, the magic will also be dependent on the length of the filesystem.
// For example, a filesystem configured and formatted for 4 megabytes will not
// be accepted for mounting with a configuration defining the filesystem as 2
// megabytes.
#ifndef SPIFFS_USE_MAGIC_LENGTH
#define SPIFFS_USE_MAGIC_LENGTH (1)
#endif
#endif
通常都只使用一个SPIFFS文件系统,所以可以修改 #define SPIFFS_SINGLETON 1,可以简化后续传递的参数。
// Enable if only one spiffs instance with constant configuration will exist
// on the target. This will reduce calculations, flash and memory accesses.
// Parts of configuration must be defined below instead of at time of mount.
#ifndef SPIFFS_SINGLETON
#define SPIFFS_SINGLETON 1
#endif
以下为你使用的具体 SPI flash 相关的参数
SPIFFS_CFG_PHYS_SZ:flash 的物理存储空间大小,可以是 flash 的全部容量,也可以是部分,我这里使用的W25Q128,修改为 16MB (1024*1024*16)
SPIFFS_CFG_PHYS_ERASE_SZ:flash 的物理擦除的最小存储空间大小,参考芯片手册,为 4KB (4096)
SPIFFS_CFG_PHYS_ADDR:flash 的物理起始地址,通常为0,如果是分配部分空间,按实际需求设置
SPIFFS_CFG_LOG_PAGE_SZ:逻辑页,单次写入的最小空间,即使文件只有1个字节,也会占用整个逻辑页
SPIFFS_CFG_LOG_BLOCK_SZ:逻辑块,多个逻辑页组成逻辑块
#if SPIFFS_SINGLETON
// Instead of giving parameters in config struct, singleton build must
// give parameters in defines below.
#ifndef SPIFFS_CFG_PHYS_SZ
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
#endif
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (4096)
#endif
#ifndef SPIFFS_CFG_PHYS_ADDR
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
#endif
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
#endif
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
#endif
#endif
视具体的编译器类型,可能需要添加几种数据类型的别名
typedef uint32_t u32_t;
typedef uint16_t u16_t;
typedef uint8_t u8_t;
typedef int32_t s32_t;
typedef int16_t s16_t;
typedef int8_t s8_t;
更详细的配置和使用方法,可以参考原作者的 wiki (Home · pellepl/spiffs Wiki · GitHub)
添加初始化文件
spiffs.c
添加文件系统的全局变量 fs,已经文件系统需要使用的几个 buffer
#include <spiffs.h>
#include "w25q.h"
#include "common/log.h"
static spiffs fs;
static u8_t spiffs_work_buf[SPIFFS_CFG_LOG_PAGE_SZ() * 2];
static u8_t spiffs_fds[32 * 4];
static u8_t spiffs_cache_buf[(SPIFFS_CFG_LOG_PAGE_SZ() + 32) * 4];
实现 SPI flash 都、写、擦除功能的函数,并放入 cfg 结构体,实际实现跟 flash 型号相关,这里就没有具体展示了
static s32_t spiffs_flash_read(u32_t addr, u32_t size, u8_t* dst)
{
w25q_read(addr, dst, size);
return 0;
}
static s32_t spiffs_flash_write(u32_t addr, u32_t size, u8_t* src)
{
w25q_writeNoCheck(addr, src, size);
return 0;
}
static s32_t spiffs_flash_erase(u32_t addr, u32_t size)
{
u16_t sec_start = addr / W25Q_SCT_SIZE;
u16_t sec_end = size / W25Q_SCT_SIZE + sec_start;
for (int i = sec_start; i < sec_end; i++)
{
w25q_eraseSector(i);
}
return 0;
}
spiffs_config cfg =
{
.hal_read_f = spiffs_flash_read,
.hal_write_f = spiffs_flash_write,
.hal_erase_f = spiffs_flash_erase,
};
实现文件系统的初始化,调用 SPIFFS_mount mount 文件系统。
由于打开了宏 SPIFFS_USE_MAGIC,空白的 flash 是不能被识别成功的,返回 SPIFFS_ERR_NOT_A_FS,所以需要调用 SPIFFS_format 先格式化一次,然后就可以使用了。
s32_t spiffs_init(void)
{
int res = SPIFFS_mount(&fs,
&cfg,
spiffs_work_buf,
spiffs_fds,
sizeof(spiffs_fds),
spiffs_cache_buf,
sizeof(spiffs_cache_buf),
0);
if (SPIFFS_ERR_NOT_A_FS == res)
{
SPIFFS_unmount(&fs);
SPIFFS_format(&fs);
res = SPIFFS_mount(&fs,
&cfg,
spiffs_work_buf,
spiffs_fds,
sizeof(spiffs_fds),
spiffs_cache_buf,
sizeof(spiffs_cache_buf),
0);
}
return res;
}