本帖最后由 huangxuejia-29212 于 2018-6-3 22:47 编辑 : r {0 N) ~9 i9 J
/ }7 F- U+ r4 `$ ?6 w+ O
SPIFFS文件系统,有什么特别呢?
- e! O1 J$ g1 {! Z从名字就可知,这是一个用于SPI FLASH的file system。6 [- k0 m$ v# {4 X* D
现在好像在ESP8266上用的很多,感觉慢慢有的人气了。% l0 B N( I+ ~+ v0 v# U( ~) o
从特性上说,这个文件系统用很少的RAM资源。
7 _9 d @8 V) C, O. r. c但是,我最后会吐槽吐槽这个特性的。
+ V7 y% |; w+ P网络上资源不多,好在github上说明文档挺全。
; Y7 x7 }8 ~, l3 v. f6 ]' g github地址:http://github.com/pellepl/spiffs8 K" V: ?7 ?" A' @, O* w
最新版本是0.3.7.
) ], o: W: L. t# e6 V0 r3 [目录结构如下:
" b2 S# }6 G! w; l; P ' Z: N9 ^, S% K1 c
添加到工程的文件如下:( J% u; x$ f+ _7 F% i
 : h% d, E7 @- |' C K' N
移植概述
) v3 N( e- ?3 D3 Z) K, {7 e下面我们说说移植的过程。
1 L5 o* k; t& f k9 Y1. 配置
# S- ? K" T: {* Q) Cspiffs-0.3.7\src\default下有一个默认的配置文件,spiffs_config.h。# v; K# ^8 I$ ~. d1 e5 r
为了方便,拷贝一个到spiffs-0.3.7\src。
) t1 Y' P2 E. L, T/ ~0 @) t6 R在工程中,头文件搜索路径,只包含src路径,不要包含\src\default。
+ Q3 s% p* T. Y; {. x0 }% t% q( v' hspiffs_config.h头部包含的头文件修改如下。; C8 ~7 I" _) S3 {+ H) d& ^
在这里也定义了变量名。 - //#include <stdio.h>6 z) E/ o/ Y8 Z9 q" {/ e; c
- #include <stdlib.h>( b" F% z6 w) B) [$ S
- #include <string.h>3 L5 q8 ]3 C- }0 y/ _& l
- #include <stddef.h>
# [* R+ a' Y. f - #include "stm32f4xx.h"& F. a2 @$ C# M: i I. c8 F
- + @8 K: R6 q G& ?- o
- typedef u32 u32_t;
( E, d: b9 p' o - typedef u16 u16_t;
1 z$ j* S: d( u1 u! M - typedef u8 u8_t;
- [- h4 ~3 L: l. T - / N- `. f9 g8 `) l
- typedef s32 s32_t;* f1 W: B, D. {3 g2 n" Q- H- @
- typedef s16 s16_t;
: d B9 F# o* r; y" Q - typedef s8 s8_t;
复制代码
7 E6 H9 ~! _$ M& H" Z$ d修改几个宏定义 - #ifndef SPIFFS_USE_MAGIC* r& s& }+ O7 W: p
- #define SPIFFS_USE_MAGIC (1)8 d( z' L/ s3 s* f% `* m+ j: T8 v& ~
- #endif2 o( S$ l" Z* n0 ~6 ?$ h& i
& m! m0 k# S0 l4 h5 G- #ifndef SPIFFS_USE_MAGIC_LENGTH0 g1 B4 f# h3 {. ?# v
- #define SPIFFS_USE_MAGIC_LENGTH (1)
8 W! W5 O5 A. b v - #endif
) G# z- w6 y3 n2 n8 Q- ~, C1 l3 w - #endif
复制代码 $ w5 `0 A) G# a0 y j* i
在spiffs-0.3.7\src\spiffs_nucleus.h文件中定义的联合用了一个gcc特性,在MDK编译会报错。
5 K% Y; R m# v, }在联合前增加一句代码#pragma anon_unions 即可。 -
" [( D" f9 X- Q: e. p" p; m- F [2 S - #pragma anon_unions ) T+ y( R2 r. s
- union {5 l+ H" C' S) j+ p( ] h
- // type read cache8 h8 O2 Z, j- M! o
- struct {) M, j& {, h2 ?& i5 `: G! R, i" @
- // read cache page index$ }4 s/ v2 Z1 t5 T- p/ V2 A
- spiffs_page_ix pix;
7 d/ L$ p: s; { `# { ? - };7 o* F9 h0 g- ~- V4 F& |% c
- #if SPIFFS_CACHE_WR* {% I& C9 M2 Q4 j8 h
- // type write cache
% R( h4 p; i: q5 t - struct {
& C; Q$ T; w( I- S# c# V - // write cache! m, q4 S0 ~- q9 X
- spiffs_obj_id obj_id;# J/ ?* b# G, b0 ^3 p/ t2 v1 x0 Y
- // offset in cache page
: }- u$ ~$ ^6 u) {3 _7 o - u32_t offset;
9 j# O2 Q: B# } H - // size of cache page
4 n3 k' w! c3 u% [ - u16_t size;
; V$ T0 O$ o- S6 y: n0 c - };
# {9 ^# c' @8 [ - #endif
! C7 X! c' D8 O, C3 Y Z ^ - };- s" |& X! x& N; W
- } spiffs_cache_page;
复制代码
; S5 l4 G6 x# Y/ T; N: s- c2 应用
! t! F3 m2 C) W首先,
n; D" ^! w2 z* p要实现SPI FLASH操作函数,SPIFFS需要的函数格式如下 - s32_t core_spiflash_spiffs_read(u32_t addr, u32_t size, u8_t *dst);
1 o1 n2 b% i/ L5 v* h! P3 c - static s32_t core_spiflash_spiffs_write(u32_t addr, u32_t size, u8_t *src);8 F" ~; n+ I& F) \. R8 N
- static s32_t core_spiflash_spiffs_erase(u32_t addr, u32_t size);
复制代码
. Y' k: c7 J- f& P5 k第二,
4 q3 B3 j: s* v, N8 |$ s定义文件系统相关参数 - /*
" F3 x6 j4 H0 ]0 R - 文件系统配置4 S, T- E$ k1 |) m
- ! v8 j; a2 U0 F
- #define SPIFFS_SINGLETON (0) 这个宏配置为0,也就是支持多个spiffs
* p+ B& @1 Z, O - */( Z: g; [% Q, `1 Z6 {- k* H
- spiffs_config cfg=% `8 K& S- f5 v! e, c
- {
A8 Z7 r4 X, ~4 N4 B$ D8 F - /* 分配给SPIFFS的空间 要是逻辑扇区的整数倍*/, M1 q0 _/ ~* s- ^% P& H
- .phys_size = 1024*4*4*128,' w( i: T$ f0 A! O, [/ {. Q
- /* 起始地址 */
, J+ W1 V/ v* i6 b; Q3 g4 O - .phys_addr = 0,
& O! {* V, P& ^, m2 A+ u - /*8 h' {# X- f" R4 J4 o0 i9 M
- 物理扇区,也就是一次擦除的大小,要跟hal_erase_f函数擦除的一致
8 v/ t+ y0 \( u8 O/ h - */
0 L3 z/ R4 u' d8 B4 r - .phys_erase_block = 1024*4,
$ o8 P# M6 ]5 f. B' v& S& N) X9 [. X - /* 逻辑扇区,必须是物理扇区的整数倍
9 r8 W6 R$ a7 y; o* y4 Y& ? - 最好是: log_block_size/log_page_size = (32-512)+ W9 i7 z! V& q+ g: K
- */. c3 q5 u9 v1 _
- .log_block_size = 1024*4*4,
: u2 s, a% Q+ H6 b - /*逻辑页,通常是256*/9 Z+ |2 O2 R+ P: m7 D- a) a
- .log_page_size = LOG_PAGE_SIZE, 4 F/ t2 @" W0 D; O7 T- o
-
7 {7 ^6 l$ y% m/ D - .hal_read_f = core_spiflash_spiffs_read,* w; p7 u; P5 S" ?3 p
- .hal_write_f = core_spiflash_spiffs_write,! {" q8 S# x8 V f" ]& Z1 O# `
- .hal_erase_f = core_spiflash_spiffs_erase,% f ^4 b2 @( d) T( @# @
- / z* P# H. K" o6 u9 h
- };
复制代码 1 y4 p* |" O; [# [, C4 q9 {' C
第三,
4 ~; d8 n ~9 j g2 v, E4 K1 L$ p挂载文件系统,如果是第一次挂载会失败,需要卸载文件系统再格式化文件系统,最后重新挂载即可。 - /*文件系统结构体*/
% O- c, n% x0 M7 _1 h1 s* q - static spiffs fs;
. m7 y9 `6 E1 n. R% h& H7 I
9 p h Z. S$ S- /*页定义*/( D* i5 R* B7 G
- #define LOG_PAGE_SIZE 256! `: m9 V; Q/ P) c- v
- : m$ p1 U8 I: R1 _/ q( {. T1 r% ]
- static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];% _2 Z) D. V- w
- static u8_t spiffs_fds[32*4];8 C m5 ~: z. K5 X% b- ]
- static u8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
! t: i0 f" I. z
8 @' D8 b, s& U8 m2 C; M- /**7 ^) l% U# o$ v& |9 _& Z
- *@brief: ) k1 c: N0 L) k, U
- *@details: 格式化文件系统/ U9 N4 I, I# n
- *@param[in]
J6 [* w) T, A - *@param[out]
6 n& |, Z( Y2 w0 Z/ B - *@retval: N! E: z# l1 {- G$ J
- */- {1 M. W F# y8 l# B5 i
- void sys_spiffs_format(void)
& Y# m: A/ Q4 j, i4 {$ O - {( E2 }6 y! _; b+ y- F# U
- y( B! C2 D5 f3 w8 k# s" N- wjq_log(LOG_INFO, ">---format spiffs coreflash\r\n");6 W' Z% L, }- g8 l- j% b: v
, y+ g$ R) @+ L9 S5 ?* ^# f- /* 格式化之前要先unmount */
6 {2 N- C# x' w5 |% M2 l - SPIFFS_unmount(&fs);6 u7 M( d& x. ^- h: ^' t
-
& D- g6 u) J8 u5 j - SPIFFS_format(&fs);. n& X, y' S- u; ?4 ?
- ' V* k: P1 T2 x+ ]+ j% t
- int res = SPIFFS_mount(&fs,
/ z5 u, O' O3 k P! F7 Q5 O - &cfg,
2 {3 ~0 a8 @# F+ a# q/ W9 r - spiffs_work_buf,
+ \+ d9 P2 O$ ]5 a* f- O3 C7 f - spiffs_fds,' [+ j: A/ ]" \/ B1 S
- sizeof(spiffs_fds),
8 u# k/ U+ J* G3 d# T5 v$ R+ s9 a - spiffs_cache_buf,) U0 u6 g6 y9 i3 H0 H- Q$ v
- sizeof(spiffs_cache_buf),
) H" j- M4 K3 \) b - 0);
o% Q0 \! c6 a- n i* {* l - wjq_log(LOG_INFO, "mount res: %i\r\n", res);3 I% |4 I. m" G
- + f& u* |7 E2 S* K
- wjq_log(LOG_INFO, ">---format spiffs coreflash finish\r\n");6 a# D- w! i% F' a. s: \, X/ ~
" A/ C: a! B, F+ B5 N: d' a9 M) [- }
v% `6 ~9 x# G" \( l( N- h - /**
% E/ T' V4 r- k" I. c- R1 R - *@brief:
% Q( r8 o0 S+ S - *@details: 挂载spiffs文件系统4 x r+ ?- x% d& c. J# J* u' W
- *@param[in] 1 Y$ X0 K* J1 b7 ~. D! n9 d
- *@param[out] 1 W3 A5 ]$ f% s5 b+ f% h1 f% e
- *@retval:
7 O0 R/ i; ^! E1 U8 y - */
8 H2 M2 M, ^, I# o. B( k0 } - void sys_spiffs_mount_coreflash(void) 7 b, N" o/ c( l
- { - f% U2 t ?4 _9 Y
- int res = SPIFFS_mount(&fs,
: {% E7 `. \9 d5 b' T - &cfg,2 i' Q6 i: a- }3 V
- spiffs_work_buf,
: G% ^4 w2 Q7 w7 a/ [( N( z - spiffs_fds,
5 ]0 ^' r6 Q7 w9 x# K - sizeof(spiffs_fds),. s, W, A' g1 _5 }" |
- spiffs_cache_buf,
G- ?# }- I* W' @ - sizeof(spiffs_cache_buf),; M9 B$ g' i: e7 |+ z: F! E
- 0);( M% i* e+ X0 `- t( }
- wjq_log(LOG_INFO, "mount res: %i\r\n", res);
5 E' |3 n4 A; }- J; p5 E - 8 Z) i B* n; m6 u, I9 I
- if(SPIFFS_ERR_NOT_A_FS == res )/ ^! [' R' H. d% L% J! \' [
- {
/ ~- G3 }4 C( E5 A- H, m - sys_spiffs_format(); . ^: L: S# h8 s
- }
* u q5 R3 d6 L) [2 a) a$ y3 o - }
复制代码 , N& x" h0 v5 z1 e
然后,就可以进行基本读写测试啦。 ( v! u' R u. C* N3 ~
吐槽
! R7 z- O) G3 m: @' I# K7 c1) C1 Z4 T. t) Y4 x' M/ w" F
如果要好好用这个文件系统,需要多次测试找一个设置平衡点。
9 b$ A% ]2 t8 X8 V什么意思呢?也就是你这个文件系统如何配置。
6 Y7 `* l$ H( P8 f也就是spiffs_config中的:逻辑块多大,页设置多大。不同的设置会严重影响性能。
5 N9 J, L* t6 a$ ]# h* p% @) q3 N因为这个文件系统为了省内存,没有任何索引。
" R5 Y. q/ c+ D* `4 `7 ?" ^' N3 O具体细节大家自己分析,我就说一个事实: 打开一个文件,很可能要轮询所有BLOCK的第一页。
% }, L1 R& {% E7 |. M& R7 t当你BLOCK跟页设置小,数量就多,操作文件就会很慢很慢,,,,。1 Y4 b) K8 V5 s; e% a2 G9 h, ]
为什么这么慢?作者在WIKI上有说明。
2
$ o7 v1 j, {3 P( [目前还没有认真使用这个文件系统,但是总感觉它有点上不成下不就的感觉。
4 t$ o9 N Y; q, a7 @是的,嵌入式RAM紧张,但是嵌入式对速度也敏感啊!9 a: e+ r1 c: f4 q0 k: r
想起以前公司用的文件系统,速度不慢,RAM用得也不算多。# l6 y E( H$ F9 I
怎么做到呢?0 c5 J1 U! V1 n+ K
限制其他性能,例如,最多只能创建100个文件,文件系统最大只能到1M。! Y! R! O4 z( l# X
这样的限制对于单片机系统来说,其实是能用的。
4 ~8 Q0 V/ V# D0 a4 {7 L(带这个文件系统的产品估计出货也1000万台了吧) 9 \* n- Q) h3 p4 S" K3 |
移植源码! ^$ s: B c+ }- ^- s
这个仓库是个人写的一些代码,主要是按照经验进行了一些程序设计,自认为比大部分教程的例程代码要好。
& |" Z2 N/ g7 Y0 R* U3 C后续会慢慢添加各种外设驱动。大家拿来用即可。
( r5 i, [2 h4 @6 e欢迎商用,后果自负
$ o9 n7 n, p- R4 H. K3 o0 f2 {1 B7 [) [6 g1 E) I
|