5分钟用STM32的内置Flash做一个超小U盘
% {5 k# A) k3 v8 b6 q6 F" O可以用来实现驱动的自动安装功能,或是通过Ini文件配置硬件
_8 |8 l# I% PBuild a mini U-Disk in STM32 in 5 minutes
! V/ x% a- t( |, SInstall device driver automatically6 k- r3 @3 i9 i7 o
Or config hardware through visiable ini file
7 u3 n' N6 L' i' |3 S! a8 t开发环境* p& r- ?0 | f, y
IDE&Compiler IAR 4.42 32K 限制版
$ C; X0 W( V* Q' jUSB固件库 2.01( N- h5 d) q+ v/ k" k" R( R
硬件 万利199元开发板 STM3210B-LK1- |2 N+ U4 R* U# |
5分钟要实现一个完整的Usb Mass Storage功能是不现实的,好在网络如此发达,并不是每件事情都需要从轮子做起。
/ N( O5 O! o! \" l& y4 xST的官方网站的UM0424中有一个关于使用STM32做Mass Storage的例子,这个mini U盘就是根据这个例子修改而来的
: ]3 E& C5 G$ y, ? H0 L: Q" f& gST官网的库已经更新到3.0,我用的UM0424是2.20的,故在上传了这个老版本的库
( h# h& J( K" C3 N4 K: V这个库中没有任何关于文件系统的代码,即文件系统的实现都是由操作系统完成的,这个库中只需要对操作系统发过来的读取与写入命令负责即可。4 K4 b& i- z& I9 R9 c3 b
库中的mass_mal.c为文件系统与存储介质的访问接口(Medium Access Layer interface),负责将文件存储在实际的介质上,如NAND-Flash,SD卡等' Y" l' k" t/ m/ M
我们需要把文件存储在STM32的内部Flash中,因此更改这里的接口即可( T. A3 G: f4 B: v% t
mass_mal向外提供了四个函数
e' _0 {8 m; c7 b$ p9 }u16 MAL_Init (u8 lun);
$ Q# r# w* O |! Y3 ]: Q初始化介质,由于是内部Flash,为了能写入,只需Unlock FLASH! ^* A& e5 e. p$ a2 B4 Z8 q5 O9 Q+ \
u16 MAL_GetStatus (u8 lun);/ L+ G5 h* K. @) c. E3 U
读取介质的参数,页大小,总页数,以及总大小,这个视STM32的内Flash情况而定,为文件系统format介质提供依据$ H) Y2 U+ `1 l: b( T. t: b
u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length);
' N. W, Q" P \8 {! a# l& }读取介质上的一块区域
3 ]. E) {3 Y# Q1 B8 L5 j$ ], cu16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length);# Q; ]* s' r5 Z5 f" [
写入介质上的一块区域* l; W. L" N: ^5 l" E! V I
这里的Memory_Offset是从零偏移开始的,用作U盘的STM32内部Flash需要从代码之后开始
4 b% z9 R4 R. U* G9 k我这里编译结束后代码在0x0800252B,取mini U盘开始地址为0x080030005 k8 v7 ?5 Z0 V. Y4 U' z$ L8 d
万利板上的芯片为103VBT6,Flash为64K,还剩余52K即0xD000,每一页为1K
8 L& t( v+ ~7 U" v根据以上信息,mass_mal更改为:
; Q6 J3 g2 n4 v
% E; t$ [* O7 U/*0001*/ #include "platform_config.h" 8 T& h1 @3 Z9 {8 p! ]; _0 U
/*0002*/ #ifdef USE_STM3210E_EVAL
4 V1 K6 S/ A3 }: W/*0003*/ #include "sdcard.h"
7 T, X8 Y3 v, ?/ j- H, a/*0004*/ #else
0 b$ t& t- N' ?( Z6 E. H! E/*0005*/ #include "msd.h" 0 S7 }" a* s' n5 K
/*0006*/ #endif 5 j: F" [5 ~6 T/ h3 q, `
/*0007*/ #include "fsmc_nand.h"
5 W: @% }3 u X8 i/*0008*/ #include "nand_if.h"
, d& j7 D# B4 B7 r, n3 k' T3 B. x7 l/*0009*/ #include "mass_mal.h"
4 S! u) H- Q: p7 a/*0010*/ 8 _8 h- o% i/ _' \* c8 l
/*0011*/ /* Private typedef -----------------------------------------------------------*/ % l1 b, U) ~/ y7 C! u2 ]# @: c
/*0012*/ /* Private define ------------------------------------------------------------*/
# v: S. ~/ G2 }0 {2 i/*0013*/ #define FLASH_START_ADDR 0x08003000 // Flash start address # P+ H; X3 `' u
/*0014*/ #define FLASH_SIZE 0xD000 // $ I/ X% v* I/ U: q5 o
/*0015*/ #define FLASH_PAGE_SIZE 0x400 // 1K per page % K* M: B0 ?9 e4 u5 T# p9 C, z: t
/*0016*/ #define FLASH_WAIT_TIMEOUT 100000
1 V: d* n: t% d* W' u7 }/*0017*/ ! N! e& B2 ?3 P0 `$ W
/*0018*/ /* Private macro -------------------------------------------------------------*/
. E4 r, ?8 }* \$ s/*0019*/ /* Private variables ---------------------------------------------------------*/ 3 C5 E1 @: H* ]0 J7 E7 ]) F, Z2 J
/*0020*/ u32 Mass_Memory_Size[2]; # ^( s) K8 X7 ~+ ?/ L, z3 b
/*0021*/ u32 Mass_Block_Size[2];
4 t4 g5 f; t4 q- t/*0022*/ u32 Mass_Block_Count[2]; ' E- H" u) J6 G% o, S% {* `
/*0023*/
7 n4 b- Y$ w N! r/ [/*0024*/ u16 MAL_Init(u8 lun)
- }8 `1 e% H) D4 J/*0025*/ {
3 i. j6 q8 d+ l, U' F/*0026*/ FLASH_Unlock();
* M2 t: I! s. r/*0027*/ return lun == 0 ? MAL_OK : MAL_FAIL; 1 t, L% {# y9 H5 U
/*0028*/ }
- \( @1 r3 j5 U) {- N/*0029*/
8 p6 Q8 h5 ~- M/ B/*0030*/ u16 MAL_Write(u8 lun, u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
* ^* q1 B. @4 v/*0031*/ {
8 t# @! f+ s2 P$ Z" f/*0032*/ if(lun == 0){
. Z" O; t; L2 u0 K" @" T/*0033*/ for(u16 i=0; i2]);
w( p3 `1 O M( ? K4 v/*0044*/ }
' E; M) q- b2 N+ [+ V' c( H' o/ @/*0045*/ return MAL_OK;
! t7 @7 a* I2 z0 J: A/*0046*/ }
! J* C1 L- [! ~) ~4 z$ E# `1 h6 }" ~/*0047*/ return MAL_FAIL; . v6 M8 V! y, M) k! J! @
/*0048*/ } # B- R! Z+ A ]$ A+ L# m
/*0049*/
- F4 {; v+ x; N! |9 i0 A/*0050*/ u16 MAL_Read(u8 lun, u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length) $ D0 W8 Z8 [' D m/ U4 D6 M' S F
/*0051*/ { . D g, i5 h3 `/ P+ {: x# [& L4 C5 q8 l
/*0052*/ if(lun == 0){
. I" t- @3 ?* s; e0 w# n7 q/*0053*/ for(u16 i=0;i>2] = ((vu32*)(FLASH_START_ADDR + Memory_Offset))[i>>2]; 7 f$ t9 F- j$ p! ]& L
/*0055*/ } % A0 }1 `# a; l8 J8 o! D
/*0056*/ return MAL_OK;
1 [2 J. Y- \9 N. A/*0057*/ } f U) \8 Z/ `7 s/ |7 m" J
/*0058*/ return MAL_FAIL; 0 K. \5 k0 G( _; s
/*0059*/ } 4 K3 w7 M! g6 ~6 j9 w( s
/*0060*/ $ Z2 ~& q/ K8 F1 e7 n
/*0061*/ u16 MAL_GetStatus (u8 lun) 4 O1 K8 S( z# W, Z) y
/*0062*/ {
4 d( Y- V: q5 J& f; p0 P/*0063*/ if(lun == 0){ ; }1 |! A0 [+ {$ L; d, B
/*0064*/ Mass_Block_Count[0] = FLASH_SIZE/FLASH_PAGE_SIZE; 1 U( Q1 q: }1 G$ D8 \4 L% z5 ?. F
/*0065*/ Mass_Block_Size[0] = FLASH_PAGE_SIZE; ( w' @, x- n4 m
/*0066*/ Mass_Memory_Size[0] = FLASH_SIZE; ( W! a* R I6 f0 Z
/*0067*/ GPIO_SetBits(USB_LED_PORT, GPIO_Pin_7);
1 B: V9 Y; b* b! l/*0068*/ return MAL_OK;
/ e+ J3 t) W$ q1 f/*0069*/ } 6 z% J) b4 h9 R5 n
/*0070*/ GPIO_ResetBits(USB_LED_PORT, GPIO_Pin_7); 7 {% ^. D8 A! W6 U+ ~
/*0071*/ return MAL_FAIL; , R `' a4 N0 r6 L2 u2 f
/*0072*/ }
6 x; B1 I; q5 f( u6 l/ D: H- R/*0073*/
4 T3 S' U B) F5 L. o5 J5 Y# A) |9 y) f! {6 Q
改好了之后文件的存储目标就变成了STM32的内部Flash
" ]3 o/ Q: }, l实际运行中还有一个问题,那就是在memory.c中Data_Buffer定义大小为512Bytes,这里我们的Flash是1K一页,要将Data_Buffer重新定义成1KBytes的
, W$ O2 w+ G5 C5 hu32 Data_Buffer[BULK_MAX_PACKET_SIZE *4]; /* 1024 bytes*/
& B/ l. a& B# k* |5 W0 i编译好后烧到板子上,电脑会提示格式化磁盘,格式化后就可以像一般的U盘那样使用这个mini U盘了& X- V" U1 X" Z* R
虽然小了点,但是装个驱动程序、写点广告什么的还是够用了/ G6 P& g# J- L* e3 l
想要的文件放好后可以将写入Flash的代码去掉,这样可以避免用户修改内容( F9 r2 n% I6 p. H. F7 H
|