5分钟用STM32的内置Flash做一个超小U盘$ q* R8 A! I& Q V K: q8 e# L$ l2 E
可以用来实现驱动的自动安装功能,或是通过Ini文件配置硬件
0 u+ n! ^+ @/ U# J- o3 a/ g0 jBuild a mini U-Disk in STM32 in 5 minutes
/ U8 [. ^+ Y% gInstall device driver automatically
8 o2 k8 @+ q# ] tOr config hardware through visiable ini file: E- b/ E" U, A- D% \' }
开发环境
* J o/ _- F7 x! YIDE&Compiler IAR 4.42 32K 限制版! g. x0 L' Y6 G
USB固件库 2.016 K/ G. ^3 L* \4 u' y( M) L8 X" b
硬件 万利199元开发板 STM3210B-LK1
# T/ H# ?! { G% v. v" b5分钟要实现一个完整的Usb Mass Storage功能是不现实的,好在网络如此发达,并不是每件事情都需要从轮子做起。. f9 X; A7 B; p$ y4 D& G( r9 S
ST的官方网站的UM0424中有一个关于使用STM32做Mass Storage的例子,这个mini U盘就是根据这个例子修改而来的' I, }2 ?# r5 v: ~
ST官网的库已经更新到3.0,我用的UM0424是2.20的,故在上传了这个老版本的库
( E) [/ L3 G6 ^5 e/ b; f3 D O这个库中没有任何关于文件系统的代码,即文件系统的实现都是由操作系统完成的,这个库中只需要对操作系统发过来的读取与写入命令负责即可。
7 g) U; N6 ?" z' B库中的mass_mal.c为文件系统与存储介质的访问接口(Medium Access Layer interface),负责将文件存储在实际的介质上,如NAND-Flash,SD卡等7 {5 D. @& j7 r6 F8 y- t. D
我们需要把文件存储在STM32的内部Flash中,因此更改这里的接口即可
' D; R: d9 a2 c- emass_mal向外提供了四个函数1 R' M7 n- ]+ v) v' }
u16 MAL_Init (u8 lun);1 o' U- W8 E; R" b
初始化介质,由于是内部Flash,为了能写入,只需Unlock FLASH i7 ?$ Z( _. F- u3 b5 z$ Z
u16 MAL_GetStatus (u8 lun);, q; C% u: t4 O A( v
读取介质的参数,页大小,总页数,以及总大小,这个视STM32的内Flash情况而定,为文件系统format介质提供依据4 H' {* j% M; H0 w/ z5 ?7 ^
u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length);7 [. m, e* j! b8 l/ ^( n9 S" q
读取介质上的一块区域
8 V$ p) K7 C7 r6 s2 ^u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length);
0 [; _% h* Q& C8 q+ ]8 r% M写入介质上的一块区域% p! C, E9 T" x* g4 @( P- D
这里的Memory_Offset是从零偏移开始的,用作U盘的STM32内部Flash需要从代码之后开始2 c, A; D2 l5 x/ z! l
我这里编译结束后代码在0x0800252B,取mini U盘开始地址为0x08003000
1 p1 J' T2 U7 E7 p万利板上的芯片为103VBT6,Flash为64K,还剩余52K即0xD000,每一页为1K
# D0 U% j' k& `8 m0 G根据以上信息,mass_mal更改为:0 c, H/ h) |1 v9 v
. ?" b3 W; R( f. P- g
/*0001*/ #include "platform_config.h" 3 {% M& `0 e, P1 k
/*0002*/ #ifdef USE_STM3210E_EVAL $ [% ^( E A9 S
/*0003*/ #include "sdcard.h" ' z" C! Z" @' u- n8 ~- R
/*0004*/ #else * l- k+ ^4 q9 D0 H( C6 l' q1 h
/*0005*/ #include "msd.h"
1 K# f$ `/ T5 { _6 x$ t/*0006*/ #endif + T0 F$ s9 Q( p' b' t
/*0007*/ #include "fsmc_nand.h"
$ y: B2 k; K0 J4 s& I/*0008*/ #include "nand_if.h" 3 a8 c& D! C' s1 D2 A- X
/*0009*/ #include "mass_mal.h" - D A; P2 l; Q: p8 @2 T
/*0010*/
, K9 O' l3 r6 v& z$ T/*0011*/ /* Private typedef -----------------------------------------------------------*/
5 E7 q( y/ i0 s8 E$ E- p) ?/*0012*/ /* Private define ------------------------------------------------------------*/
& M* B, d+ H8 o6 t/ q/*0013*/ #define FLASH_START_ADDR 0x08003000 // Flash start address
4 o/ D4 @& W0 H# p& M6 I6 x/*0014*/ #define FLASH_SIZE 0xD000 // + h1 v2 F Z3 M# ^3 x3 E, I
/*0015*/ #define FLASH_PAGE_SIZE 0x400 // 1K per page
1 ~5 b9 M" Q, q" p( L/*0016*/ #define FLASH_WAIT_TIMEOUT 100000
" x1 @% V2 c2 t: c( H6 I& r/*0017*/ + N2 ?$ Z9 K7 X4 }6 M
/*0018*/ /* Private macro -------------------------------------------------------------*/
- z1 j: g0 s& y7 o; g/*0019*/ /* Private variables ---------------------------------------------------------*/
+ o) @. ?! z* t3 z2 z, U: K; X/*0020*/ u32 Mass_Memory_Size[2]; " O; p( R5 h* j `$ B3 q d+ X
/*0021*/ u32 Mass_Block_Size[2]; 0 W' O+ h+ j8 Y* b: h- ^7 e
/*0022*/ u32 Mass_Block_Count[2];
- k# T, b+ f5 P4 N/*0023*/
# z4 U3 g5 s0 n0 d% @ @9 g/*0024*/ u16 MAL_Init(u8 lun)
8 z% y2 l6 l5 K/*0025*/ {
2 n1 p: L# a x0 o8 W% O; n/*0026*/ FLASH_Unlock(); ( X# ?+ z& v0 L+ U0 k/ y
/*0027*/ return lun == 0 ? MAL_OK : MAL_FAIL; , {5 R8 r2 O* w. R
/*0028*/ } 0 n- y2 b3 d# u1 t6 \. C: Q0 T
/*0029*/
: F4 D1 u. ]$ M8 ~$ }7 M/*0030*/ u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length) $ L. r$ l$ M& h0 `
/*0031*/ { 4 W! }9 ~' ]* v2 a8 z
/*0032*/ if(lun == 0){
" K3 Q# s3 X+ X$ n+ H/*0033*/ for(u16 i=0; i2]);
. L: E3 u; ` m3 i0 d- b7 E9 `. y/*0044*/ }
# b' h% \9 C# \1 ~/*0045*/ return MAL_OK;
4 M* \8 L; [$ V( ?6 @/*0046*/ }
- W& {7 ~- X T% Z* d. c/*0047*/ return MAL_FAIL;
8 V8 ~% @( l' `/*0048*/ }
+ E% M) v5 a4 D* Y/*0049*/
3 O; |7 S( ? m9 p" W0 t8 Y, V4 c* U/*0050*/ u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length) % x/ O) s, n7 U8 K* U
/*0051*/ {
5 S+ g8 i4 z3 G/ k, @. j; `/*0052*/ if(lun == 0){
2 e2 E/ \# p- [) T6 F) I/*0053*/ for(u16 i=0;i>2] = ((vu32*)(FLASH_START_ADDR + Memory_Offset))[i>>2];
, j/ G7 G# @- Y, A6 |! N3 o/*0055*/ } " h. Q8 \' c' q. B
/*0056*/ return MAL_OK;
! h9 e3 e6 T$ x/*0057*/ }
% u. G- l0 c- @/ V2 I) M( f/*0058*/ return MAL_FAIL; 6 q; }5 v1 U, x( W; o. X4 ?" o% w& d
/*0059*/ }
& A& y! g( c) {5 h/*0060*/
) z8 ]' V% K. Q: u. q6 \4 p/*0061*/ u16 MAL_GetStatus (u8 lun) ' U6 S# C- B+ O$ V' r2 ?
/*0062*/ {
( {) B* B- @. ~) l6 T3 X) [/*0063*/ if(lun == 0){ " f. X' C; A: i/ [
/*0064*/ Mass_Block_Count[0] = FLASH_SIZE/FLASH_PAGE_SIZE; 8 T( L7 M, {: p
/*0065*/ Mass_Block_Size[0] = FLASH_PAGE_SIZE;
& [: V! Q( O0 c. k: V- p/*0066*/ Mass_Memory_Size[0] = FLASH_SIZE;
0 L4 D7 x' `; P3 l& I1 E: n; z/*0067*/ GPIO_SetBits(USB_LED_PORT, GPIO_Pin_7); + v8 i4 f l" y9 D3 M# ?& _
/*0068*/ return MAL_OK; 1 t, I' |$ X: p
/*0069*/ }
6 ~0 |) o( {5 {7 [/*0070*/ GPIO_ResetBits(USB_LED_PORT, GPIO_Pin_7);
2 Z6 `% a/ B7 o! q, {3 \/*0071*/ return MAL_FAIL;
8 L7 O$ s# x& ]( a9 g' y3 v5 x/*0072*/ } 5 R- X- L0 N5 A. e; Y$ a+ U0 n
/*0073*/
. b6 Q |8 t" e2 [
4 L& B6 B! u3 t8 e, L改好了之后文件的存储目标就变成了STM32的内部Flash! n. |, ~8 R( f( g, G/ z7 ~1 ~
实际运行中还有一个问题,那就是在memory.c中Data_Buffer定义大小为512Bytes,这里我们的Flash是1K一页,要将Data_Buffer重新定义成1KBytes的1 d `7 ?9 D, x( U
u32 Data_Buffer[BULK_MAX_PACKET_SIZE *4]; /* 1024 bytes*/
0 j( s; e d) J编译好后烧到板子上,电脑会提示格式化磁盘,格式化后就可以像一般的U盘那样使用这个mini U盘了) N3 X3 D y5 U: w$ ^) B
虽然小了点,但是装个驱动程序、写点广告什么的还是够用了, N& L# P- |$ C" }6 c% g& N& u1 L# I
想要的文件放好后可以将写入Flash的代码去掉,这样可以避免用户修改内容' s1 h' y, \0 ?3 C2 |! d% c* x4 u0 R
|