[转载]STM32CubeMX配置文件系统FATFS2 a( ~2 @: d. I5 s
http://www.waveshare.net/study/article-657-1.html
9 |; K" A" H) G; z(出处:微雪课堂)1 j0 O5 b- N( d0 z8 j
FATFS简介3 J! x( C% r+ I/ [3 y/ y* B
# U) P7 B2 s1 F' n9 k
FatFS是一个为小型嵌入式系统设计的通用FAT(File Allocation Table)文件系统模块。FatFs 的编写遵循ANSI C,并且完全与磁盘I/O层分开。它可以被嵌入到低成本的微控制器中,如AVR, 8051, PIC, ARM等等。兼容Windows文件系统。3 ~5 h% z: d8 [; m" `' l
关于FATFS文件系统的API函数介绍,底层移植接口和例程等可以查到FATFS官网。( }+ ^# m7 h" Z5 E
( V+ T* m5 ? G: S7 j. sFATFS官网:http://elm-chan.org/fsw/ff/00index_e.html
, r# m! ?, P. d* i6 f; d2 I# j
$ n' x' f. @* ?. G# Z4 ?+ W4 a" }9 u
结合STM32cubeMX软件移植FATFS文件系统非常简单。本章程序在上一章SDMMC工程的基础上修改,复制串口SDMMC的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。在中间件中选择SD卡,在SD上建立文件系统。
5 Z5 q3 @4 L% ?4 q9 k3 o8 K4 R P
/ v( b3 r. q" b, w3 @5 ^$ c6 ~
在FATFS配置中选择简体中文字GBK编码支持中文,使能长文件名,缓存存储在堆(STACK)中。
* t4 y! }/ z) ^' R
* ^) A2 k; S+ T ~, W 点击菜单栏中Project->Setting修改堆的大小,堆设置为0x1000。(注意:由于刚才设置长文件名动态缓存存储在堆中,故需要增大堆大小,如果不修改则程序运行时堆会生成溢出,程序进入硬件错误中断(HardFault),死循环)。
: U* X2 v1 _/ r5 e+ k
& A9 q+ p1 K9 [" n6 W4 z6 ~ k5 V 生成报告以及代码,编译程序。在fatfs.c文件中可以看到FATFS初始化函数。在bsp_drver_sd.c文件中可以看到SD卡的板级操作函数,包括SD初始化,读写擦除块操作函数。在sd_diskio.c文件中可以看到FATFS文件系统移植的底层操作函数。! n& S% S+ p3 d4 c
4 }3 g+ P# M5 Y3 V( W3 O) l 删除上一章SDMMC的应用程序。在main.c文件前添加变量。fs为文件系统工作区,fil为文件对象结构的指针。rtext/wtext分别为读写缓存,bytesread/byteswritten分别存储读写的字节数。filename存储文件名(FATFS文件系统配置时使能了长文件名,最长255字节,若不支持长文件名,则文件名最多8个字节)。+ i q2 t# @2 ~, {) v2 F Z9 t1 U+ y
- /* USER CODE BEGIN PV */
6 V8 N- p) i; }" k - /* Private variables ---------------------------------------------------------*/# J$ u: n- Z' q& p, ]5 Q2 F) d" }
- FATFS fs; // Work area (file system object) for logical drive
7 t4 M0 j0 h& l2 ^% V2 W' Q- } - FIL fil; // file objects: y" a( G j' H, r3 f6 M) N4 Z7 T
- ; C# C( e/ {8 ~$ V, F' \% ]
- uint32_t byteswritten; /* File write counts */; a& h& w' \# X% t1 z
- uint32_t bytesread; /* File read counts */
6 K2 F; O! L) y. g; w0 ` - uint8_t wtext[] = "This is STM32 working with FatFs"; /* File write buffer */, [7 A0 b8 `" X4 L3 @5 O0 w1 [. k
- uint8_t rtext[100]; /* File read buffers */# ] i1 j0 D' ?8 a
- char filename[] = "STM32cube.txt";
0 o6 \ E4 q# J, _ - /* USER CODE END PV */
# l4 \, ]: |0 x; n( C. S/ f' r0 Y
复制代码 在main函数中添加应用程序。程序中首先注册一个文件系统对象,然后新建STM32cube.txt文件,将数据写文件中再读出来,判断文件系统是否工作正常。' E r, g% N$ M, j
- /* USER CODE BEGIN 2 */
3 P- j1 h; N9 w - printf("\r\n ****** FatFs Example ******\r\n\r\n");
, Y' v4 H1 _4 G6 h7 B) y - - v% @& h2 B2 r* e
- /*##-1- Register the file system object to the FatFs module ##############*/
+ z) G' r5 u+ |# I - retSD = f_mount(&fs, "", 0);5 G% q- A) u4 p" S1 g
- if(retSD) }% G! {0 l5 X) |* w
- {
: x* I3 R% f$ r: w* X - printf(" mount error : %d \r\n",retSD);
/ ]9 B. N- ~" x; B6 y% ]3 V - Error_Handler();9 \& F" q1 O5 @! Z
- }; y. ]* q; P3 ^8 A! @( f1 z: `
- else; i# G1 e( \" X2 ]
- printf(" mount sucess!!! \r\n");
; p. n) H* ]0 ~& B% ^ - : L( }8 ?& v( t# S3 m5 K
- /*##-2- Create and Open new text file objects with write access ######*/
' h, s# n1 k' h1 s; X- ~' ? - retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);2 g3 x/ }% a' \ ~5 W; ^+ E2 F
- if(retSD)
8 Z8 W' J% i* R! S8 i1 J# X - printf(" open file error : %d\r\n",retSD);5 i1 U# \7 D+ Y( u. b" J% K0 p
- else0 B$ N: W( B0 ?5 ?% j/ s$ |
- printf(" open file sucess!!! \r\n");
* r9 ]: Z3 ?2 ]" [; ~ -
% P! T* J S2 h - /*##-3- Write data to the text files ###############################*/
/ ]) E, B! u% f+ y6 k, c4 G3 S - retSD = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);
& `; G- f* m) k" c0 v9 V - if(retSD) @2 o4 _6 W" x9 [1 E0 a
- printf(" write file error : %d\r\n",retSD);
8 v- i( y, Q- @3 I3 o2 A9 w - else
) g/ r5 w ~" }8 C9 n, A - {" @$ @: ~/ c( p6 M
- printf(" write file sucess!!! \r\n");
8 Q" j" r: H0 ?( g2 a4 Q. l - printf(" write Data : %s\r\n",wtext);$ ^/ M3 g) n" \/ e- n
- }7 j* p& \3 D4 d1 [* \2 |% C
- * K, b& N9 p" t# e
- /*##-4- Close the open text files ################################*/( W6 ~ g8 f5 G; J0 z1 j
- retSD = f_close(&fil);
, V% o7 x0 W V J - if(retSD)2 O8 q% A. T8 ]6 i2 e" z
- printf(" close error : %d\r\n",retSD);- j' F8 ?2 d4 Z4 y4 W% S
- else
+ ?4 s( y# C- C0 C, l - printf(" close sucess!!! \r\n");2 M7 @; d! u6 w$ N# f; `# P, P2 O
- , F; A- W R- o; j
- /*##-5- Open the text files object with read access ##############*/4 V) V& j9 L5 T9 K; r
- retSD = f_open(&fil, filename, FA_READ);1 g' B0 ]& ~" e$ l5 ]) |
- if(retSD)6 i, `! t- ]8 b x2 u
- printf(" open file error : %d\r\n",retSD);, F% ]9 g2 |: e% F( H$ i* {9 G
- else
; e O7 k2 S) w$ E - printf(" open file sucess!!! \r\n");
" `/ t7 U5 V$ W! |+ w/ s, M - . q$ S) C4 ~! p# g8 l) R; O% ?
- /*##-6- Read data from the text files ##########################*/5 m$ d' Y/ p# s, G# b
- retSD = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);
" E- Q. q! ]' M; h; f7 m, R - if(retSD)$ m# ? h/ ^, R' P6 p$ ?1 s
- printf(" read error!!! %d\r\n",retSD);
4 v1 C3 g0 g6 V/ ^. F5 e - else
3 a, D2 `! t1 {# |+ u - {
' P0 D7 k# X# \, [' B# [ - printf(" read sucess!!! \r\n");* S3 Y. F1 e! F
- printf(" read Data : %s\r\n",rtext);
2 U5 |* Q0 v. v# _- `. N. z* { - }
8 L! C9 p# Z: D - / S2 C8 [- y8 v, ~
- /*##-7- Close the open text files ############################*/) h5 U; A8 ?) }' e1 C4 c
- retSD = f_close(&fil);& Q3 d+ F. H, ~
- if(retSD)
8 i" R" g* u# s# C Q/ T - printf(" close error!!! %d\r\n",retSD);5 r5 j. D2 m( ~
- else
2 U1 s: l* H. j) c* W - printf(" close sucess!!! \r\n");' b" P3 r- V3 Q: \/ N) `: m
- ' f( w5 P$ _0 l* j" \
- /*##-8- Compare read data with the expected data ############*/
0 |1 W H1 `8 _0 G$ u) e$ w - if(bytesread == byteswritten)" C* d! p5 ?: n8 }, ~
- {
$ _5 {* J/ |9 | - printf(" FatFs is working well!!!\r\n");
2 w% D! U4 v% j - }
' T; V; |$ ]% \2 r - /* USER CODE END 2 */
复制代码 在main.c文件后面添加错误处理函数。
* Q! |0 v: G( @3 Z! Y6 ^- /* USER CODE BEGIN 4 */
/ Z" Q3 T7 ]5 S) v7 D - static void Error_Handler(void)
& H* L4 F9 ] k# B& E5 O) o - {1 u1 I( c. I- F+ I
- printf("something wrong ....\r\n");$ d- f5 N9 [8 D2 w
- /* User may add here some code to deal with this error */
+ F( f, m8 k# Q6 n7 N6 ]9 A+ U# n( ]: Z - while(1). |' t8 m+ d# W: A$ l. ]( X
- {
9 f; W: O$ v- l, l - }, F/ [% t) \7 i( S; t5 [
- }
9 m0 Y! y& Y. _/ j& w" Z5 O b, r - /* USER CODE END 4 */
复制代码 在main.c文件前面添加错误处理函数声明。 v4 G, H$ P- t- O
- /* USER CODE BEGIN PFP */9 E- z9 I7 i! {) P0 y; N1 L
- /* Private function prototypes -----------------------------------------------*/
- V, e8 M1 a0 r( I, \- i* o - static void Error_Handler(void);
0 X/ u$ g! v. T7 S; N4 j0 Y& G - /* USER CODE END PFP */
复制代码 编译程序并下载到开发板。将Micro SD卡插入Micro SD Storage Board中,再插到Open746I-C开发的SDMMC接口中。打开串口调试助手,设置波特率为115200,按下复位串口助手上面会显示如下信息。
% N4 l4 y+ z/ s$ k# G7 a
5 G Y( ?% O" N: L下载简介一下FATFS的几个操作函数。
) g0 B; L3 G Z% S- z5 V1.f_mount
4 n3 a4 F6 e5 A7 z在FatFs模块上注册、注销一个工作区(文件系统对象)。/ l$ A1 G& l, K" X
- FRESULT f_mount (
L. `0 } s' Q - FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/
; ?# W, X, ?- u2 l - const TCHAR* path, /* Logical drive number to be mounted/unmounted */
; V0 f0 f w, R4 J# B - BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */
- v# O1 B! L6 y: I% ` - )
复制代码 参数
7 j Z$ P ?6 Z* `+ l# g- J5 Zfs 工作区(文件系统对象)指针
/ d U1 Y' u9 \. p; B$ ypath 注册/注销工作区的逻辑驱动器号( D8 U7 x$ X* l( w9 s# O
opt 注册或注销选项
/ ?3 O3 ~: x' \2 x
& }$ {( q2 P6 y6 @6 Z9 c5 Q, Q+ J7 S5 w/ t
: E* d: N) t# j9 ]; b& _6 A' j! U7 q [
2.f_open$ ]: U& s) @/ S4 r: b
创建/打开一个文件对象
& F6 n/ V. r1 ~: @# G. P0 x- FRESULT f_open (
q" ~' d) N, r1 \2 a - FIL* fp, /* Pointer to the blank file object */6 X( o4 D2 H/ P7 C1 l( r& A
- const TCHAR* path, /* Pointer to the file name */! J# p0 g3 N) c5 n) ~% d0 O
- BYTE mode /* Access mode and file open mode flags */4 \3 z9 `7 v; `8 Z x
- )
复制代码 fp 将被创建的文件对象结构的指针) m T8 t6 d* {6 o
path 文件名指针,指定将创建或打开的文件名) b& B( K, V( x7 i
mode 访问类型和打开方法,由一下标准的一个组合指定的。, ^! m9 n* K8 {* d
0 Y7 D# w' u5 d* v6 v+ X& K2 g# O+ o+ C# |: l
模式 描述 A8 K9 }' p/ Y
FA_READ 指定读访问对象。可以从文件中读取数据。 与FA_WRITE 结 合可以进行读写访问。 " M. k, N* h, ^' k
FA_WRITE 指定写访问对象。可以向文件中写入数据。与FA_READ 结合 可以进行读写访问。
" c! V8 _ b& d: \4 l \& ZFA_OPEN_EXISTING 打开文件。如果文件不存在,则打开失败。(默认)
1 L1 ~: U6 ^5 a0 J( n) Z8 g' KFA_OPEN_ALWAYS 如果文件存在,则打开;否则,创建一个新文件。
6 m1 J& x# L. _7 D" LFA_CREATE_NEW 创建一个新文件。如果文件已存在,则创建失败。 + y& |2 D7 V# J
FA_CREATE_ALWAYS 创建一个新文件。如果文件已存在,则它将被截断并覆盖。5 i+ j- y, G& E6 I+ b# F
# k3 f1 w. E: m' q7 s* y
9 O+ i c/ d; A F3.f_close
) D) y' p. c [( J" ^关闭一个打开的文件
1 q( @, t: M* @ Q" \: X! H6 N- FRESULT f_close (4 ^1 }" E2 k8 l4 z" o# z' m
- FIL *fp /* Pointer to the file object to be closed */
: s+ ?" O. _- M: [" _0 B - )
复制代码 fp 指向将被关闭的已打开的文件对象结构的指针。
/ I& r$ z4 m5 R0 F+ h* N* g' m$ k- i" Z
6 P$ f& E- o' ]- G( Z0 Y4.f_read, A6 a' J7 N* `) _4 u
从一个打开的文件中读取数据# x" \9 A$ x1 z
- FRESULT f_read (% k2 f3 Q1 Q( U1 C! }0 |. C
- FIL* fp, /* Pointer to the file object */9 Q! B2 `& c0 H3 g$ B
- void* buff, /* Pointer to data buffer */. e4 J3 I3 P1 p$ \
- UINT btr, /* Number of bytes to read */
& y7 M, o$ v7 j* T2 A - UINT* br /* Pointer to number of bytes read *// \3 Y3 S2 Q' P t
- )
复制代码 fp 指向将被读取的已打开的文件对象结构的指针: _6 h {. V+ {5 ?2 f
; Z, S( `' X, \- V& A8 S! [buff 指向存储读取数据的缓冲区的指针4 {1 R! u" Q1 d
btr 要读取的字节数0 o4 S: n; I y9 E. w% P* L4 G
br 指向返回已读取字节数的UINT变量的指针,返回为实际读取的字节数。. ]- P4 Q$ ~5 o+ c' ~
6 c# Y. S/ j7 ~' e1 s) Z5 P
' e" h7 [# F- z1 ^/ s" Y0 D2 Y5.f_write/ [- `; e7 c, d8 N1 v5 d b! \
写入数据到一个已打开的文件$ ^/ l, B# f) c, w) L2 A! R' L! f
- FRESULT f_write ( ~0 d. p" Z& e
- FIL* fp, /* Pointer to the file object */; ^* o8 v0 ?2 n' n/ ?3 f
- const void *buff, /* Pointer to the data to be written */
- [- ?$ S4 [' L5 ^ - UINT btw, /* Number of bytes to write */
D9 l* [2 }- z7 _8 `, R+ U - UINT* bw /* Pointer to number of bytes written */
- p2 _# K, t# z" ?, W - )
复制代码 fp 指向将被写入的已打开的文件对象结构的指针
! c. E' d' l0 ^/ u$ j2 @) f/ d6 S% K
buff 指向存储写入数据的缓冲区的指针6 o' r* v) y) e( x4 }& k4 E6 ]3 G
btr 要写入的字节数9 Z3 R. P4 s4 P; B" e! _
br 指向返回已写入字节数的UINT变量的指针,返回为实际写入的字节数。
- M6 r- }+ Q0 e9 r, L( ~+ A q6 l5 z4 q$ e- r
: O( W' X+ h& h/ r2 Z6 U
另外FatFs还有很多API操作函数,在这里不再作详细的介绍,详细信息请查看FatFs文件系统官网。7 Q2 Z4 A9 v5 x* w% C
5 T* n/ r2 ~3 D) l3 @) s* M5 C, g! X
# y' Q% Y& q. D" {
3 M6 J3 O# Q+ U3 u/ X& F+ W2 _, D$ f$ X2 p3 j' S
6 [# B% ~/ m! _; M2 E/ V
/ c3 M0 r' |8 d1 J5 D, |3 E/ |* d
9 L, c3 a( p, b9 s" }4 U$ A- [8 C4 z+ ^1 w ?2 ]6 K
|