5分钟用STM32的内置Flash做一个超小U盘9 ]9 G3 Q2 u. b) l. H2 n& t+ B$ U
可以用来实现驱动的自动安装功能,或是通过Ini文件配置硬件4 T8 O- A# c1 g. i9 F$ W4 N
Build a mini U-Disk in STM32 in 5 minutes, W& `+ [, y" \/ l* x
Install device driver automatically
; U: R2 c8 k: Q3 d5 o) q' c& [Or config hardware through visiable ini file& g- f) V1 H8 r+ p; P |
开发环境6 w5 @1 d) |8 ~3 C# o
IDE&Compiler IAR 4.42 32K 限制版
" |$ {5 j- ?* h! ?USB固件库 2.017 u2 D6 i( Z- {# y% D
硬件 万利199元开发板 STM3210B-LK1
- `" w+ @7 M$ O! V( Z# i) D% e2 N5分钟要实现一个完整的Usb Mass Storage功能是不现实的,好在网络如此发达,并不是每件事情都需要从轮子做起。& s K3 i. A/ b: _" A$ T* I
ST的官方网站的UM0424中有一个关于使用STM32做Mass Storage的例子,这个mini U盘就是根据这个例子修改而来的: b# j: i; H, m# b/ Z8 t
ST官网的库已经更新到3.0,我用的UM0424是2.20的,故在上传了这个老版本的库
6 w& \9 b1 _+ Q4 g这个库中没有任何关于文件系统的代码,即文件系统的实现都是由操作系统完成的,这个库中只需要对操作系统发过来的读取与写入命令负责即可。1 C7 g4 G. G# _
库中的mass_mal.c为文件系统与存储介质的访问接口(Medium Access Layer interface),负责将文件存储在实际的介质上,如NAND-Flash,SD卡等6 h5 o, ~+ s7 X# |1 O& j9 R( ]) k1 c
我们需要把文件存储在STM32的内部Flash中,因此更改这里的接口即可
" k) @6 l: U. ?4 I7 G' Dmass_mal向外提供了四个函数
% a% t2 n; w7 s2 L5 \/ Uu16 MAL_Init (u8 lun);% J8 ]" p8 q/ Y \
初始化介质,由于是内部Flash,为了能写入,只需Unlock FLASH2 c+ }! r% e0 n8 T6 a, g- G, `9 ?; S
u16 MAL_GetStatus (u8 lun);
6 V& R! J. }' f0 r: K; o c8 }读取介质的参数,页大小,总页数,以及总大小,这个视STM32的内Flash情况而定,为文件系统format介质提供依据+ }) T; j5 k& j" e" {
u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length);4 q4 o- r1 h9 E; N
读取介质上的一块区域8 `1 b# d4 ^5 i, N
u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length);0 h/ `$ v* j: S, @- C
写入介质上的一块区域
" Q) W/ ~* P! F/ z这里的Memory_Offset是从零偏移开始的,用作U盘的STM32内部Flash需要从代码之后开始$ J3 e+ E4 W5 }6 z3 L0 F
我这里编译结束后代码在0x0800252B,取mini U盘开始地址为0x08003000/ i j+ H! A4 K1 G1 S/ U
万利板上的芯片为103VBT6,Flash为64K,还剩余52K即0xD000,每一页为1K
! ~1 f, f2 ^: z0 }根据以上信息,mass_mal更改为:" S9 S4 u1 R8 ~1 r
- Z* B5 W# m9 ~ E* v, Y' p* L3 ~
/*0001*/ #include "platform_config.h" c4 |7 A s9 B8 @9 A
/*0002*/ #ifdef USE_STM3210E_EVAL H" H6 |9 a* Y T @
/*0003*/ #include "sdcard.h" ! s6 i' E0 E7 }- p# o5 B
/*0004*/ #else / X# e) \6 L4 i4 F- y/ Q; V5 O/ D
/*0005*/ #include "msd.h" / T: o+ Z0 \8 ^3 Z3 D6 ~
/*0006*/ #endif ! N. v; K. b2 ^' ^* L
/*0007*/ #include "fsmc_nand.h"
# P8 L% ?8 c3 W# K% j/*0008*/ #include "nand_if.h"
3 w- T" e8 P, A! R; \% M/*0009*/ #include "mass_mal.h"
E- v$ i/ j- B( B- F' f9 X3 a6 q/*0010*/
! D/ b" k& |! {. G0 O T/ O/*0011*/ /* Private typedef -----------------------------------------------------------*/
+ u# s3 R# E) ^. w( t" z8 ?- [1 S/*0012*/ /* Private define ------------------------------------------------------------*/ 4 f" `% g+ h0 E, b. x3 ]9 k
/*0013*/ #define FLASH_START_ADDR 0x08003000 // Flash start address
3 r: G0 v7 C) o2 q* K+ `/*0014*/ #define FLASH_SIZE 0xD000 //
4 g% O& \* |8 E2 i7 J' g# E# b7 |7 m/*0015*/ #define FLASH_PAGE_SIZE 0x400 // 1K per page
; B! V' A9 W. A/*0016*/ #define FLASH_WAIT_TIMEOUT 100000 0 V8 i) t6 {+ F7 |$ p. B( }, I
/*0017*/ # Z, r% `& A$ Q! g1 v( u5 R7 v
/*0018*/ /* Private macro -------------------------------------------------------------*/
i- y- A: i2 Q4 R* C/*0019*/ /* Private variables ---------------------------------------------------------*/ 4 W% i" E! d& n7 A7 e( E! o
/*0020*/ u32 Mass_Memory_Size[2];
8 C9 t5 r1 e2 Z1 \! Q5 Z- W/*0021*/ u32 Mass_Block_Size[2]; . u$ s+ A% l. o
/*0022*/ u32 Mass_Block_Count[2];
' W3 u8 w0 _. J" h, I; S/*0023*/ 9 D0 v# O- h: ~( v8 n0 Y0 O! k
/*0024*/ u16 MAL_Init(u8 lun)
, F' l: L, k3 S V/*0025*/ {
- R& C. t" {# T0 o; o/*0026*/ FLASH_Unlock();
" y" Y: z& @3 Y6 U0 H& y/*0027*/ return lun == 0 ? MAL_OK : MAL_FAIL; + d) Q4 M& S" ?4 d% A# n9 g
/*0028*/ }
I7 A$ [* Y) e! N% o" V/*0029*/
3 j- z: `3 c1 D7 R" ]( i8 z4 ? D/ U/*0030*/ u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
- p0 Q% B& a1 e1 q& j+ H8 n/*0031*/ { 9 i" Z" C7 J, k/ f) ~* m% M8 W# x
/*0032*/ if(lun == 0){ d9 v9 U# s0 i v7 `
/*0033*/ for(u16 i=0; i2]);
# b0 n# ]/ ?. t/*0044*/ } 8 |" Y4 p% q6 E+ q
/*0045*/ return MAL_OK;
% z1 g, t1 k1 O" h; h" q* S5 ^/ w/*0046*/ }
( ]& j! ~" `5 }/ A0 o/*0047*/ return MAL_FAIL; / a6 m7 H# X2 q
/*0048*/ } - Y7 ?/ L8 J( y/ \. n, e
/*0049*/ ; ~* R) y3 z9 y8 R) s- J
/*0050*/ u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length)
. ?9 v. u- ?# j B3 [0 [0 ]/*0051*/ {
6 y1 ?6 p0 _ b' s3 D/*0052*/ if(lun == 0){ # R7 `" s* g% E* C! m. a4 Y
/*0053*/ for(u16 i=0;i>2] = ((vu32*)(FLASH_START_ADDR + Memory_Offset))[i>>2]; ) Y* m' f8 N( s v/ [) x
/*0055*/ }
) R1 `9 w4 o% m1 U: w, o" l/ K- ~: A/*0056*/ return MAL_OK; ! t7 w9 t2 t+ i
/*0057*/ }
1 A3 e* a [5 z8 q! q) F B/*0058*/ return MAL_FAIL;
; y& i/ Q0 ?& I; Q/*0059*/ }
- l. u8 G6 s( ]9 }9 _4 B& k+ |/*0060*/
2 A, z% O, `2 R+ l" N* L9 s/*0061*/ u16 MAL_GetStatus (u8 lun) }3 I; u5 d& `) r
/*0062*/ {
, g5 l! Q3 y! V: @3 M& G/*0063*/ if(lun == 0){
5 P' q! O; F$ N. |, ^9 ]/*0064*/ Mass_Block_Count[0] = FLASH_SIZE/FLASH_PAGE_SIZE; # d+ [+ Z! p' l9 U
/*0065*/ Mass_Block_Size[0] = FLASH_PAGE_SIZE;
7 V( q( o A' V N8 Z4 Z8 i( ~/ f' u/*0066*/ Mass_Memory_Size[0] = FLASH_SIZE; # J2 I8 {6 t4 b9 D
/*0067*/ GPIO_SetBits(USB_LED_PORT, GPIO_Pin_7); ; v3 I7 H+ x1 q9 O1 ]4 W
/*0068*/ return MAL_OK;
3 a& A1 z1 l) f/ h% _% T/*0069*/ }
/ d- s( y$ y! u0 }" m/*0070*/ GPIO_ResetBits(USB_LED_PORT, GPIO_Pin_7);
* I- J4 t. x/ Y1 t& t2 a/*0071*/ return MAL_FAIL; ! A* t& X0 H4 t2 O
/*0072*/ } ) u" h2 Q2 d$ f) Q# m# P
/*0073*/
9 |3 A0 {$ Z/ \( {4 J: j6 k' Y* V7 z0 H) z9 I: X& C% g: z
改好了之后文件的存储目标就变成了STM32的内部Flash" v* U4 P# c8 Y6 C
实际运行中还有一个问题,那就是在memory.c中Data_Buffer定义大小为512Bytes,这里我们的Flash是1K一页,要将Data_Buffer重新定义成1KBytes的+ U& _# Y2 g$ q
u32 Data_Buffer[BULK_MAX_PACKET_SIZE *4]; /* 1024 bytes*/
/ x1 V& E8 N9 u* V) Q# |# p编译好后烧到板子上,电脑会提示格式化磁盘,格式化后就可以像一般的U盘那样使用这个mini U盘了
1 I) M/ n4 n( @. H虽然小了点,但是装个驱动程序、写点广告什么的还是够用了6 H* n0 \; F' a8 Y
想要的文件放好后可以将写入Flash的代码去掉,这样可以避免用户修改内容
0 e. F7 }: G* ? |