你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

使用STM32制作U盘(device)

[复制链接]
攻城狮Melo 发布时间:2022-11-3 21:48
硬件环境+ A. |* n5 d* N
STM32(支持USB)
( C( R) r0 X- ?4 ~. f, t# V存储介质(SPI FLASH、E2P、甚至是片内FLASH均可),本实验使用外部SPI flash(W25Q64)。
, P) C1 N# M$ V3 M0 @/ H使用STM32CubeMX进行配置初始化信息- N$ s7 ]' F; v. ]
1.配置MCU的时钟,外设等信息,可以使用一路串口进行输出Log信息,串口波特率越高越好/ {9 I4 z1 g$ r% H  V
2.MCU管脚配置% o" F+ _+ m! B9 {6 e9 o) t

- P8 I4 u6 ?$ I' v 8b99d1c2df2844dd8a50e8c493cdfc2b.png
$ J- h: p- L$ G/ V" C3 C% c
/ [% G3 v7 Z# j% t& \4. 时钟配置4 S+ x" P8 ]; H
我这里的硬件中有8M的HSE,然后需要注意的是,USB时钟需要配置到48M
% L) b# }  ~: a8 s9 ~9 u% t. _% E# a8 C, j
b7acf9dc412a4a6887a078d5bca6864b.png + W1 Z: J% ?5 B3 r+ Y: b3 |: [
- N1 z0 w/ `- K( h5 @: y' p
3.USB配置,记得打开中断
% P0 [: b) p/ a& e+ O- Y$ b; g/ F' |! O% X  {1 W
0879b662144348a6803d4ca12b7f2787.png
% z- q8 R. F0 V& K+ x4 m' L, i
8 M+ M+ q+ n" M6 c9 l+ G. \4.串口
% T! e  C. r- c/ U/ Y1 e3 v6 X  Q6 d  ^' J# K; z
8a0b450eb6a645c288c8e48a3d04a56f.png - \  [" O8 K( B  E7 K8 G
" \: T5 L8 Q3 t, s2 Y2 q- t: q
5.存储介质的通信接口,如使用内部flash,则不需要配置0 |2 C( T$ A' G! q, _+ v7 {
W25Q64 是SPI FLASH,配置SPI接口,这个配置可能需要根据芯片手册进行调整
. _3 X- l; e: y' `8 q# V+ O% x7 h% A" w/ k* t
21e21095783747e4a081e27bd2ba3ae4.png
& ~" C& n7 ?/ R  Z2 C3 i9 _2 \' V
7 R/ ~/ Q$ Z" }& o9 s  r" D" y# z6.中间件 USB_DEVICE( M- O% W. N1 x" _/ K' \% ]) R
Class for FS IP选择大容量存储,其他可以默认,USB_DEBUG_LEVEL改不改都一样,做USB device时没看到打印出log来。如果配置了非0,那么需要重定向printf,并且勾选USE Micro LIB,否则可能会出现问题。
: `( ^6 \0 R: A
4 ^3 l2 q' Q& S' i# Q$ g& p6 A" t 6aebe1fa36c24165bf020f37cbd628d4.png
6 ~$ l6 \) p. [, P/ K7 H
8 p6 K6 `  @! U) g- z+ v7.将堆栈空间改大之后就可以生成代码了6 S2 a: V- z3 R  I$ P
7 ^* g2 f# r& @$ G
修改程序
- J# }- q0 @$ e8 n) q生成完程序后,直接编译烧录,然后将USB连接到电脑上,就可以看到已经多出来一个盘符,但是看不到容量和大小,也不能成功格式化磁盘,那是因为我们还没有完成数据的读取和写入2 I) X; @& Z6 L9 {  C4 r
- O+ P8 i; q( G; f; ^
修改添加存储介质的驱动代码
! x# T5 s" G' ?8 [# \/ \这个步骤很关键,如果你的驱动有问题,那么就会导致格式化失败,也就没办法使用。9 O1 B0 H. ]8 O/ t; E% J8 n0 d6 G# g
& ~. u4 K. p1 k# u4 h
W25Q64
# C& n* [/ F& O$ T+ G4 `7 ~必要的函数& N" R$ W7 q7 m" V$ J2 P9 l% S
W25Q64.h. ^7 H$ J0 e; ~- p% I
  T- h; ^7 M& q+ G; {' s  `
  1. typedef struct
    8 s3 U8 F1 m2 w5 ^1 Z
  2. {
    - u1 n/ m9 M. ~
  3.     void (*init) (void);/ C2 D, q, ^) x+ q
  4.     void (*read_sector) (uint32_t addr, uint8_t *pData, uint32_t length);, r9 i$ d5 J- u
  5.     void (*write_sector) (uint32_t addr, uint8_t *pData, uint32_t length);
    2 z* N" R- z0 ^% z* x! M
  6.     uint8_t (*get_status) (void);! M& a4 _0 m  s) }
  7. }W25Q64_Dev_T;1 K5 N. m$ I/ s3 L: ]4 D
  8. extern W25Q64_Dev_T w25q64_drv;
复制代码

; ?* N0 ~' j3 g5 B; c# ~- eW25Q64.c0 u1 y% E3 ]  a% z. C* d  r
0 ^; ^; a( l( s- F. ?
  1. static void w25q64_write_enable(void);
    ! {. }) i) X( m! w9 j
  2. static void w25q64_write_disable(void);
    ' q( O: B- c/ \: j1 j/ U/ Q& C% ?
  3. static void w25q64_chip_init(void);
    & x! s) R; L. J9 q( i, F9 x
  4. static void w25q64_page_write(uint32_t addr, uint8_t *pData, uint32_t length);  //256byte max
    2 ]1 `8 c: W! i( s( l
  5. static void w25q64_sector_write(uint32_t addr, uint8_t *pData, uint32_t length);//4kbyte max
    4 r  k/ {  ~9 B0 H
  6. static void w25q64_sector_read(uint32_t addr, uint8_t *pData, uint32_t length);/ a% Q% l" K2 }6 u) @
  7. static void w25q64_erase_sector(uint32_t addr);& N. y8 w& S+ ~, s% ^2 Q$ r
  8. static uint8_t w25q64_read_satatus(void);; d+ o0 V) z; v2 B  h# e- d

  9. 4 n% D8 k8 w3 I: A) Q
  10. static uint8_t data_padding = 0xff;# |+ u+ E8 R8 _
  11. , b5 B. l! @! Q2 z3 P2 z
  12. W25Q64_Dev_T w25q64_drv = + F% q2 t- P! o4 `. q7 I7 C
  13. {
    , y7 X' w6 B4 }& a, u
  14.     w25q64_chip_init,
    ) b9 z: |3 t6 [4 U# u# ]# U. R& {: p
  15.     w25q64_sector_read,% Q- F. P9 _: w# J8 v2 u* |
  16.     w25q64_sector_write,9 h+ X$ B9 O* L7 W( L* E3 N& V+ _
  17.     w25q64_read_satatus,& d& B) c8 o2 E  l1 C" k
  18. };
复制代码

: o! t; i& s8 p. h2 ]  I数据读写函数添加到USB驱动中
6 {. d9 e* p1 }5 k: ]! M
我们要修改的文件是 usbd_storage_if.c, g+ {, k* K- D2 ?( G0 C

2 D3 I9 y# j7 C  K; _) D9 B
  1. #define STORAGE_LUN_NBR                  16 a+ U( `# {9 J; h, @
  2. #define STORAGE_BLK_NBR                  W25Q64_SECTOR_NBR//改为flash介质的sector 数量
    . `* f/ Q: s' M1 a% l; ^# N
  3. #define STORAGE_BLK_SIZ                  W25Q64_SECTOR_SIZE//改为flash介质的sector 大小
复制代码
1 R7 }+ Y3 C. u: i
int8_t STORAGE_Init_FS(uint8_t lun)
. U8 T' w0 U0 d/ v# h
, f% X, F, U- }" c/ e$ R2 A7 _2 @我们可以添加我们刚刚写的存储介质初始化,如果正常,则返回 USBD_OK
9 ^* q; ]" p) L6 t! ^* d$ U" K% J$ M7 D3 \4 X- d
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)5 E; F4 w2 B/ m9 Q" h  c; u
3 z; O/ p! O8 ~! f
获取存储介质的大小,函数已经填充好,我们可以不动; @* I- W. z" c8 ^# t$ l

/ a5 g6 ~3 N' a" v0 {int8_t STORAGE_IsReady_FS(uint8_t lun)
7 F! I3 S1 m7 N' ?, l
3 k: X$ ^) m- u3 ?' m获取介质状态,我们要对存储介质的状态进行判断,这里我们要判断两点,一个是是否正在读写状态中,另外一个就是存储介质是否是不可工作状态  L+ X- G4 b& u2 m/ \. K
( L% {. L* J: _7 ?+ [
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
$ b! ?4 B* W; j9 q5 t; k
" t: A) f7 K; V  \+ t9 y判断是否是写保护,我们可以直接返回USBD_OK, M1 _* [2 U  C0 b
& ~! v7 T, s% w: R: v+ @# B
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
0 ?& i$ E& M$ R1 u" J) P  |3 Z( X* Y' }
读取一个扇区,我们将准备好的读取一个扇区的代码填充进来就好
7 }* K8 r% C% r/ ]& S$ A# j1 M# o* J& G" ]
例上述W25Q64的驱动代码:2 W% w+ ?- W' F5 _" Q

+ ]* F/ t$ k2 g; L& v
  1. /**0 U; h4 b0 n' x  Y  n
  2.   * @brief  .* D- r& |4 f  N' C
  3.   * @param  lun: .* A0 {4 u4 d+ L7 `4 v' |
  4.   * @retval USBD_OK if all operations are OK else USBD_FAIL6 G/ b) i) H# H6 W0 S1 ]
  5.   */
    + R. i/ b: g% a3 ?; u; c
  6. int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    4 @) W$ U: f2 e7 Q2 K  d
  7. {  K- j& F1 s4 w; O" J3 Z
  8.   /* USER CODE BEGIN 6 */& P8 J1 h8 g3 V- }( \- f9 A
  9.   while(STORAGE_IsReady_FS(1) != 0);; V4 H1 K! q( \3 K7 O
  10.   storage_status = 1;
    * f6 l! K# z* H0 J4 t; [' A9 @
  11.   w25q64_drv.read_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);
    0 A4 Q! M# ]6 ]7 }1 ?! d- A
  12.   storage_status = 0;
    ! M; W5 I3 K# o+ y$ p3 a
  13.   return (USBD_OK);1 }0 T" \. l- i
  14.   /* USER CODE END 6 */+ o/ `' F5 b' L' J. h
  15. }
复制代码
) y" f7 R3 o- g# v9 s( c8 v7 |
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
3 G6 \* N4 c7 [9 c& k
; Q: L7 L* k3 z. T) A2 Q写入一个扇区,我们将准备好的读取一个扇区的代码填充进来就好; f* S1 y0 O: E
+ Y4 P) i/ h9 P5 `- v
例上述W25Q64的驱动代码:- ~7 @( b; o( r5 ~
6 K- Y) m3 Y; Z6 |8 t8 Z
  1. /**- u- D7 n% p3 n1 @! k
  2.   * @brief  .
    # U9 q$ t% a( b  ~4 G+ H8 r( c% t
  3.   * @param  lun: .% d, k7 N- e! G( l- @6 I
  4.   * @retval USBD_OK if all operations are OK else USBD_FAIL
    ) ?7 `* G- j4 g8 s" y
  5.   */
    & g3 z" g5 b: z" T; q
  6. int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    " G0 f. i) o. y6 o5 D% Y& l2 |
  7. {
    6 ?- D5 X& d. j0 o) s
  8.   /* USER CODE BEGIN 7 */
    8 x" N2 g. ~. T; }& B/ Z
  9.   while(STORAGE_IsReady_FS(1) != 0);- }* S: c5 {% l. O/ @, F
  10.   storage_status = 1;
    - j: E& ?3 f$ t0 v" Y
  11.   w25q64_drv.write_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);# k) B0 H( h# i
  12.   storage_status = 0;
    & N7 _2 @5 Q' ^; w& }! I3 i! m
  13. ' U" N/ n: x* [6 N4 F; r
  14.   return (USBD_OK);
    % Z8 Z% f9 x+ _. T8 u( w
  15.   /* USER CODE END 7 */  V' L% w+ Q; t" \$ o, @
  16. }
复制代码

1 S9 R7 D/ Q% T" `& ~int8_t STORAGE_GetMaxLun_FS(void)" g/ m( O1 t% h9 M: q% P

6 q) D! ^- ?4 O1 T0 B! m8 D: @4 S读取磁盘介质的个数,一般我们只虚拟出一个来,不用管就行
. g- s! C  v6 i& o, F& P
, q% _1 p# G- I0 L4 k" A1 Z我们使用的spi flash的sector大小为4k,也就是4096,USB这边是520,所以我们需要将其修改一致
# ~( k# h8 {9 ~, W6 M# y
! m% F3 e' d* m% ]- `! u修改usbd_msc.h6 ~, u5 r7 X' V: N

2 E' o5 J" E( O! b$ X/ S4 N
  1. /** @defgroup USBD_BOT_Exported_Defines3 f" y) G& g" I8 r) M! h0 [
  2.   * @{: J# u% t2 q- q" U" D3 B& G
  3.   */5 B# ^+ N9 {! r/ A7 K
  4. /* MSC Class Config */
    $ p! a$ H% E5 R
  5. #ifndef MSC_MEDIA_PACKET- ^8 l/ `! p6 K3 s
  6. #define MSC_MEDIA_PACKET             4096U //512U! O+ B. w* ?9 \# E
  7. #endif /* MSC_MEDIA_PACKET */# i: K5 U/ k& q2 x/ P1 I& o
  8. - a& g. I; }3 B- w/ i4 z
  9. #define MSC_MAX_FS_PACKET            0x40U  //0x40
    2 I% _3 |  C; _0 Z) v
  10. #define MSC_MAX_HS_PACKET            0x1000U //0x2000 S: T: Q2 P5 C' l$ V

  11. . i( j) N. c* L
  12. #define BOT_GET_MAX_LUN              0xFE
    1 G5 W2 U% y3 d8 }3 x
  13. #define BOT_RESET                    0xFF
    - m9 N4 Y% I+ h: U* q. q( a: W7 p
  14. #define USB_MSC_CONFIG_DESC_SIZ      32. l* U9 ~, D+ z5 r0 T, O
  15. - Y% ?- J. x; [/ c
  16. #define MSC_EPIN_ADDR                0x81U1 Y/ ?( Q/ N7 d5 p/ U
  17. #define MSC_EPOUT_ADDR               0x01U
复制代码

, w8 c) ]( ~; }! X# L- m3 B5 ]修改usbd_conf.h5 m& s! V. P% \! @$ C2 S6 h( a0 x
! s, _# O. v' {
  1. /** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
    9 L, G: Y- L7 Q. Q) x* u
  2.   * @brief Defines for configuration of the Usb device.. X6 \/ }5 k3 Q) }+ Q5 q
  3.   * @{
    $ M0 m& `$ w6 |' x
  4.   */
    ) V, |$ {. A' V. Q- O

  5. ; d7 k7 x  [" `" Z2 A/ f/ Y* {0 x
  6. /*---------- -----------*/5 a# L5 x. e) s8 Z
  7. #define USBD_MAX_NUM_INTERFACES     1
    - V+ q, d0 E( J  S- w
  8. /*---------- -----------*/
    / o1 {$ n$ Q- t( |$ Y/ `
  9. #define USBD_MAX_NUM_CONFIGURATION     12 z$ f) f0 V8 ^) O. J% z
  10. /*---------- -----------*/
    ( E  M  `& w. M, K
  11. #define USBD_MAX_STR_DESC_SIZ     4096 //512
    1 y. F! K' V- f4 K, H
  12. /*---------- -----------*/
    3 Y% @8 j& x& z
  13. #define USBD_DEBUG_LEVEL     3
    : ]/ L! \3 R- r2 x6 W
  14. /*---------- -----------*/+ n# {* U& l: d* ^
  15. #define USBD_SELF_POWERED     1* w% X# h* w2 |3 u* p7 L4 z
  16. /*---------- -----------*/
    - w" V, B5 }( G* K+ j
  17. #define MSC_MEDIA_PACKET     4096 //512
复制代码

- J5 r7 s* m! Z: c/ H2 z至此,我们的U盘就做好了
+ h( I5 ]' Z% C3 i* c. V3 |. p————————————————
; W7 @- K8 Q2 D$ A版权声明:Logan Li7 S! ]; `4 [% P8 l; d% A
9 G* H0 i( T5 n

7 W0 [' Q( Q1 X  [% D+ H
收藏 评论0 发布时间:2022-11-3 21:48

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版