5分钟用STM32的内置Flash做一个超小U盘1 X( Z7 J0 p0 W6 l2 N
可以用来实现驱动的自动安装功能,或是通过Ini文件配置硬件. Z+ N# E' _. j9 K3 F) o) u
Build a mini U-Disk in STM32 in 5 minutes6 J6 i/ n7 L' \; ]0 m
Install device driver automatically% |1 {/ p! |$ k$ Q; F8 o& s, |
Or config hardware through visiable ini file$ w, \# p: R! c) ^8 f, I& t5 M: u
开发环境5 z) n5 w" A1 B k; N
IDE&Compiler IAR 4.42 32K 限制版
9 r; q* y6 G" j3 ]USB固件库 2.01
" f/ v# D( _: r h7 @硬件 万利199元开发板 STM3210B-LK1! e3 f' l( x3 A( ~" i
5分钟要实现一个完整的Usb Mass Storage功能是不现实的,好在网络如此发达,并不是每件事情都需要从轮子做起。
+ a4 \* c; i8 v2 q/ S: h1 JST的官方网站的UM0424中有一个关于使用STM32做Mass Storage的例子,这个mini U盘就是根据这个例子修改而来的
9 V K+ q1 R) m% F" |4 K5 gST官网的库已经更新到3.0,我用的UM0424是2.20的,故在上传了这个老版本的库 * S( _/ z: m9 M/ K6 B; ]/ ]
这个库中没有任何关于文件系统的代码,即文件系统的实现都是由操作系统完成的,这个库中只需要对操作系统发过来的读取与写入命令负责即可。& T7 B. v2 a: I( v b2 _5 }
库中的mass_mal.c为文件系统与存储介质的访问接口(Medium Access Layer interface),负责将文件存储在实际的介质上,如NAND-Flash,SD卡等
1 V% T c3 t5 H2 w我们需要把文件存储在STM32的内部Flash中,因此更改这里的接口即可
* O0 F ?3 }1 |& Ymass_mal向外提供了四个函数# W! Y) q L" f* j
u16 MAL_Init (u8 lun);& i9 X1 ], N0 [- N- U0 Q a8 c
初始化介质,由于是内部Flash,为了能写入,只需Unlock FLASH5 f* j* c+ M: q. {# N7 n& T, k- \
u16 MAL_GetStatus (u8 lun);
( |, k% g+ @! ~& L h( i6 l读取介质的参数,页大小,总页数,以及总大小,这个视STM32的内Flash情况而定,为文件系统format介质提供依据
5 J t3 L3 t! W, `( Bu16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length);1 p `! p/ o. u
读取介质上的一块区域% X; L# K; q9 i5 m( P& w9 l/ T' I& g
u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length);
' N9 P. Y! Q) W写入介质上的一块区域
3 k0 M: G7 A) u) a9 [3 `7 i# M' N# J这里的Memory_Offset是从零偏移开始的,用作U盘的STM32内部Flash需要从代码之后开始# [! i: b+ B: V8 G4 C2 O" f9 X1 B
我这里编译结束后代码在0x0800252B,取mini U盘开始地址为0x08003000
5 v! Q% E! m8 Z2 s- k: @& ^1 q" ]. W2 L万利板上的芯片为103VBT6,Flash为64K,还剩余52K即0xD000,每一页为1K5 T5 k9 B% v; x) T
根据以上信息,mass_mal更改为:
' s7 G% u% x, I F% H5 S% @4 `. c; i: }
/*0001*/ #include "platform_config.h" / b6 C- }+ u s" d9 R4 G0 r
/*0002*/ #ifdef USE_STM3210E_EVAL 1 h9 }' C. M2 c) z
/*0003*/ #include "sdcard.h"
p9 \+ B v( w3 D3 u7 T- D/*0004*/ #else
R6 F! t5 w5 \& X4 C) V4 k! G( N/*0005*/ #include "msd.h"
8 n9 \5 P: }. I/*0006*/ #endif ( V2 T6 a# W$ l/ b: m6 R! r
/*0007*/ #include "fsmc_nand.h"
- M/ v, g5 r# W* R/*0008*/ #include "nand_if.h" 1 ~ ^% G$ f ]7 J
/*0009*/ #include "mass_mal.h"
+ I: N2 ^# ^, w4 U! y# U, ?/*0010*/
9 d$ l5 N' I! ^; W7 ^; o" Z- O0 k/*0011*/ /* Private typedef -----------------------------------------------------------*/
5 C# ~* d, @/ B1 q, w" X9 u, |/*0012*/ /* Private define ------------------------------------------------------------*/
) H, Q2 n) h# a9 }/*0013*/ #define FLASH_START_ADDR 0x08003000 // Flash start address ( g5 _) H1 f- }( }+ T
/*0014*/ #define FLASH_SIZE 0xD000 //
$ l: ^1 M( N2 l% }: n# c/*0015*/ #define FLASH_PAGE_SIZE 0x400 // 1K per page ! b2 y7 ~" I2 |: c
/*0016*/ #define FLASH_WAIT_TIMEOUT 100000
. C6 Y9 g8 N; v5 x: p+ S/*0017*/ ( M- U2 b O& {" d0 z P; `- W
/*0018*/ /* Private macro -------------------------------------------------------------*/ ; K$ y' ] g( H0 _6 O. N0 ^9 }
/*0019*/ /* Private variables ---------------------------------------------------------*/
/ ^, @) d. u$ d2 C0 e2 J/*0020*/ u32 Mass_Memory_Size[2]; 8 S$ A2 d7 P# S9 d% l: U
/*0021*/ u32 Mass_Block_Size[2];
$ \! R% U) a( U. v/*0022*/ u32 Mass_Block_Count[2]; ) x$ m& f, o! h- K6 G: V" \ A
/*0023*/ 1 _. V3 F+ ?, X) ~
/*0024*/ u16 MAL_Init(u8 lun) + x* U6 m$ a: R
/*0025*/ { . ]8 X! m( Q$ i9 s
/*0026*/ FLASH_Unlock();
% W$ @: K; P S0 a/ V/ q- _/*0027*/ return lun == 0 ? MAL_OK : MAL_FAIL;
6 t3 B0 H3 c" s/*0028*/ } ( m3 C: N a3 v% u6 \1 F/ U! H
/*0029*/
- p) X4 y. A: u8 x, D& Z: ?/*0030*/ u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
/ y6 n' ]; m2 x3 K# w, t' D% l/*0031*/ {
8 t6 M9 V: W) X# x. f* U4 a! h7 ^/*0032*/ if(lun == 0){ 7 f$ m0 g- J/ V- R' b9 D+ @
/*0033*/ for(u16 i=0; i2]);
7 K7 a( h$ E7 w4 o; h/*0044*/ }
- K* v, @# ]2 @/*0045*/ return MAL_OK; . a2 ?) j+ ]0 w2 M* P4 H' J
/*0046*/ }
9 \# o- y" [/ J4 v% O5 R! t' v/*0047*/ return MAL_FAIL;
9 _% R) p" a z: p/ z/*0048*/ } - Q" v& G4 }1 y6 p# |( N
/*0049*/ : a- a" S" c* w+ a Q5 |$ @3 T
/*0050*/ u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length)
% L3 n5 x! N2 F- z/*0051*/ { & ^% Y, t' a' X/ i- @) i
/*0052*/ if(lun == 0){
+ O8 ?1 b* R/ W* ?/*0053*/ for(u16 i=0;i>2] = ((vu32*)(FLASH_START_ADDR + Memory_Offset))[i>>2]; / o$ R5 K5 S/ n1 W* D3 e& X% B
/*0055*/ }
, J; ` [9 Z* ?; {( I* I/*0056*/ return MAL_OK; 6 ]. r1 V; s& W x. w% `
/*0057*/ }
0 Q! Q+ H$ K4 D- g, q/ y/*0058*/ return MAL_FAIL;
8 @* {, b$ ~7 ]7 J5 G9 l) B8 j/*0059*/ } 2 k9 V/ x6 {+ p5 m- k8 C7 H
/*0060*/ $ A: t7 O i5 H9 s6 q& j3 ]& z$ P
/*0061*/ u16 MAL_GetStatus (u8 lun) - i8 W, |. g+ N8 a
/*0062*/ {
+ o) i* f2 W$ U3 ]" O% A/*0063*/ if(lun == 0){
5 q3 G" `0 L3 b" p( f/*0064*/ Mass_Block_Count[0] = FLASH_SIZE/FLASH_PAGE_SIZE; / }5 g; E/ B- q7 C+ |- x
/*0065*/ Mass_Block_Size[0] = FLASH_PAGE_SIZE;
/ ?- d) ?; Z( g+ ~/ f/*0066*/ Mass_Memory_Size[0] = FLASH_SIZE; 6 l- k: S8 E" t
/*0067*/ GPIO_SetBits(USB_LED_PORT, GPIO_Pin_7); * n( o8 s+ D, U7 d
/*0068*/ return MAL_OK; ) ]% W$ w* M. b) B5 U! G6 J5 x
/*0069*/ } & |1 u& x" r7 X
/*0070*/ GPIO_ResetBits(USB_LED_PORT, GPIO_Pin_7);
' M- [( t2 ~6 R/*0071*/ return MAL_FAIL; 1 i- M0 Q" `4 b8 P/ l1 H
/*0072*/ } $ Y F# g" ?4 T' V# S
/*0073*/ " ~) b* g3 {) s, ?* t4 P% j& ^1 ^1 f/ z
* h! t2 d# n3 c& `; o改好了之后文件的存储目标就变成了STM32的内部Flash
5 o+ {, Q! y9 ?8 O实际运行中还有一个问题,那就是在memory.c中Data_Buffer定义大小为512Bytes,这里我们的Flash是1K一页,要将Data_Buffer重新定义成1KBytes的
3 p) K. r# H2 T% P$ `$ y" Iu32 Data_Buffer[BULK_MAX_PACKET_SIZE *4]; /* 1024 bytes*/! c- y( R8 s5 w. E+ f. v
编译好后烧到板子上,电脑会提示格式化磁盘,格式化后就可以像一般的U盘那样使用这个mini U盘了" d" I% {# a H/ I9 ]
虽然小了点,但是装个驱动程序、写点广告什么的还是够用了2 H; f. c+ X/ E% ^' z! v% d/ R
想要的文件放好后可以将写入Flash的代码去掉,这样可以避免用户修改内容
/ _$ |0 K5 f$ n- ] c; J) n' O |