工程试验环境
. H. {' _, S! S( Q) M2 MSTM32F103RC" R' d0 ]; j2 C4 w6 X# A( G e$ O
STM32CUBEIDE1.5.1% B3 u" `# Q) o+ ~% o/ q
1、本教程默认你已经会使用STM32CUBEMX生成CDC代码和MSC代码,这两个工程的生成很简单,网络上的教程一搜遍地是。
+ H4 T7 R8 [& \7 j$ ^; ]
- a3 T2 o8 H- B, S" Z- P2、USB组合设备的移植修改需要具备一定的USB知识储备,如果没有强烈建议看一下我的另一篇博客:STM32 USB相关知识扫盲2 S- ^( Q$ g7 `3 I: Q
! N; a/ I9 g# F7 t1 h s
首先说一下STM32的USB库的初始化操作,MX_USB_DEVICE_Init函数中使用USBD_RegisterClass函数注册绑定了实际的端口初始化控制等操作,如果是CDC那么注册的就是USBD_CDC这个结构,如果是MSC那么就是注册的USB_MSC这个结构,所以我们的组合设备思路就是用哪个的时候,就将这个结构切换成对应的操作结构。) z2 y* r2 u* u- K( d% W* J
, }' n/ B! x6 _8 s) W+ c
第一步:基础工程生成. V/ O. G. p% r. k$ m& d8 n3 @( f
首先先用STM32CUBEMX生成CDC的工程和MSC的工程,并测试通过没有问题后,我这里使用CDC工程为基础工程进行修改成USB组合设备。- @8 a% M4 e# G
/ v# r5 c3 S' p N- @' m1 P
基本步骤如下:, ~ K4 L; D, ?' d+ T m, ^' Z" r
b% G4 ~% t YUSB设备描述符修改成组合设备类型3 ?6 j9 R0 S: g$ D6 O8 F8 U
修改PMA端点分布
# q& r9 g' X2 a* k修改USB配置描述符并添加MSC的配置描述9 ^! V' K4 I; p8 t( q9 H, c
修改初始化函数接口,改写成我们自己的组合设备初始化操作函数
3 ?. M" H" \- L6 ^- ~- Z/ [修改MX_USB_DEVICE_Init函数,注册成我们自己的组合设备9 }4 I0 E& R3 Z0 d- h+ X
8 E4 n7 G! S) ~8 d/ V: j
& o/ o/ ~( T& U% V5 s5 j9 c下面进行分布修改。
) i2 t' ~% ^% ~4 _ Z6 E' \
0 Y7 [ |5 M9 |8 m5 c$ j第二步:USB设备描述符的修改
+ D3 t$ z7 E! Y这一步很简单的,就是修改usbd_desc.c中的设备描述符数组USBD_FS_DeviceDesc,将设备类型改为组合设备类型:
6 @( r) K* Q& O3 r) A! K% |
/ y: |, j6 z" |5 q3 w
. P8 q4 t* z& C" [1 A7 Q
& t; @# q2 V3 s2 c6 c3 G$ ?* v) E第三步:修改PMA端点分布
8 c# b' d2 j9 x( K, ?0 V! g' r首先修改一下CDC所用到的端点地址,CDC的输入输出端点不动,将命令端点成0X83:
# I; ?2 c+ Z; ]) ?4 O. ^- x! R: ?. Z6 | x- W) F4 @
" a5 Y+ r w3 H$ k% }3 C N
! G' s% @% Y4 s% x8 ^( v
4 g9 P5 I! w! B! I) F- t, G然后进入usbd_conf.c文件中,找到USBD_LL_Init函数,修改PMA端点初始化:
) ~+ s7 u% }* O b/ k% `+ F5 l$ P( _3 v# _# m; l) U, G" b% W
) I2 B: E$ y2 E3 ~3 U% |4 ?$ {/ O
& L! z& E2 d3 ?; j5 a* ?5 \这里的修改非常关键,为什么addr要从0X38开始呢?
( T+ I' e9 C) X& e5 N& f% j
6 u7 z5 b' U7 B' m( l( J& n因为我们目前用到了:1 a8 P3 O5 ]% Y g0 L; i' ~
' a* g6 C) X! W8 V6 x
默认的两个端点(0X80、0X00)
- G, O- r3 m: Y! Z* ~CDC的三个端点(0X81、0X01、0X83)" i3 l5 j4 e# h% A; T7 @
MSC的两个端点(0X82、0X02)# n# U' r: A1 o2 ~$ ^
- i: B2 K9 S5 \+ \
2 k& |# d1 g- z$ ~: L
共7个端点,每个端点占用8字节,总共56字节,十六进制就是0X38!
% `/ ] }: p* _; A5 Q8 t
- o' p& Y$ k4 k- R好多人修改自己的USB应用时,就是卡在了这里!如果起始地址修改不对,那么USB端点缓冲就会覆盖PMA头部的端点描述!
3 n# v$ f/ j- y/ {# C
3 W1 P4 @7 C: |有关PMA的详细描述及使用,请看文档头部的《STM32 USB相关知识扫盲》链接文章!
+ B$ |" m# v& U5 M5 W" u
9 M/ I0 j: I- g: y* w第四步:编写我们自己的组合设备配置1 L( t9 H, Y+ N0 g0 |5 c# }, I& r
这里我为了方便修改,新建了一个usbd_composite.c文件,用于编写组合设备驱动,文件内容如下:
; T @, F% ^3 a1 [8 Z- J! I* o
5 _- Q9 H. @( U% x- #include "usbd_def.h"* y5 o8 r8 c1 j
- #include "usbd_msc.h"
( {' O) B" q- k; l0 ? - #include "usbd_cdc.h"6 |- x& I: c5 D' z) ?( }8 s* [
- #include "usbd_storage_if.h"
3 Q, P3 I- [( @* Z$ A" m - #include "usbd_cdc_if.h") d+ y4 p9 P3 R& B, D( t, k0 G
1 j/ i( U" l( P/ _' a6 E2 ?% ?/ g$ z$ @
; Q7 T, b- O" }+ ]- #define USB_MC_CONFIG_DESC_SIZ 106
$ V$ V5 p% E& N0 S" t
& U8 K; H& t0 y2 `) A3 U) ?
7 L' H. J. B' s9 D- extern USBD_HandleTypeDef hUsbDeviceFS;
. i2 X* c' g1 r
* h; ?0 T% r5 _5 k$ @4 ]3 Q- 4 q8 G: i4 r; u" s6 M- w
- extern uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
' R" p0 K& R1 F5 `* X' r2 v7 Z - extern uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
1 W/ d1 U4 Q9 E( C- o) N2 E" F - extern uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);& c9 K. q0 {' I
- extern uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
* E7 Z: [; b3 r, |( ?. h - extern uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
# R6 l% k0 M1 A - ! F. v9 G: N3 K: ^$ x# ^/ o7 {
- 4 @, ~1 h* i3 u: C7 |: H0 Q6 g
- extern uint8_t USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
' Q+ f6 S7 k; o& F - extern uint8_t USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
2 O# n7 W0 n+ j8 W; ~2 b: R - extern uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);$ V* B; X1 Z) v" m7 L x2 ]
- extern uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
; }4 p' M+ m0 D* m% l9 f - extern uint8_t USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);* X4 U% m" d, @9 }1 ]
- extern uint8_t USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev);# X0 o8 }4 P& W/ u! s
- 5 J8 A; V; b( @
# S2 _. [. ~6 P1 @! F3 v- static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);+ M" E3 f, [* U
- static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
. h- E* z; Y8 j. ?& K! d - static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);0 w' ^6 x% Q3 F( A9 x4 Z& o% ?
- static uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
, q) D8 G: F8 t. a% R+ h' l - static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
( ]% _& |) F" D* `$ c) u - static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length);
8 K1 w0 R f' R0 [* d( X - static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length);
% F5 K" A3 V: i2 X! E - static uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length);
8 z' x4 ~! l: D! M0 B% G - static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
$ A4 d: T e a) C; l - static uint8_t USBD_Composite_RxReady (USBD_HandleTypeDef *pdev);
+ V3 C$ P7 R& M' L2 z2 q8 i - static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev);( L1 D$ t" z. _0 z3 T1 z/ Z/ F
- static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev);
- P/ H% r# \. l! x - 2 ?# I7 ]. l4 `9 L. |
3 {- b+ d& |: [* p6 S3 N8 W- USBD_ClassTypeDef USBD_Composite_CDC_MSC =
1 z" b: M6 d, I - {7 V5 `: L/ C( a0 C. e u
- USBD_Composite_Init,
& U- D, @4 \( ^* u p! ~ - USBD_Composite_DeInit,9 h v1 h. m+ \
- USBD_Composite_Setup,
% h( f3 @, P. M$ H% ], q - NULL, /*EP0_TxSent*/ s& w8 [! m+ C5 c- s
- USBD_Composite_RxReady, /*EP0_RxReady*/4 g& \) |# E, {7 J* g$ n
- USBD_Composite_DataIn,
* _5 S/ `. d5 ?5 Y$ H1 f - USBD_Composite_DataOut,) M T \ o* J6 X
- NULL, /*SOF */
* |' i+ L8 Z7 j3 Q+ d9 W7 d# _: I# J - NULL,( O- @- `4 Y1 u2 s0 v6 K) d3 K
- NULL,2 T, P) r. Q2 _* o" D- J
- USBD_Composite_GetHSCfgDesc,6 _- V9 x, L7 J
- USBD_Composite_GetFSCfgDesc,
9 z) v; m! {" J# P0 C: V - USBD_Composite_GetOtherSpeedCfgDesc,& b7 T h* s: W
- USBD_Composite_GetDeviceQualifierDescriptor,
T! C# D& t6 t" a - };* G, e( l/ l ]
* R' b! N( r/ K& q* d' ~) V( n- * \3 P! H5 C4 E
- /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
8 c2 h% q$ W* A& L" ~ - __ALIGN_BEGIN uint8_t USBD_Composite_CfgDesc[USB_MC_CONFIG_DESC_SIZ] __ALIGN_END =
1 C& b" j5 J# \ - {
# k# \4 P! y+ E) w6 j1 s! o - /*Configuration Descriptor*/
u; D8 M# O" q5 C/ n8 h - 0x09, /* bLength: Configuration Descriptor size */
& I, z I! K! C% g - USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
& g y4 T6 ^2 H5 r# U8 | - USB_MC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
9 J l2 L) c' U5 a+ O - 0x00, M- ^3 _ b5 {& D) _, |
- 0x03, /* bNumInterfaces: 3 interface */ /* +++lakun:CDC用了两个接口,MSC用了一个接口,所以是3 */5 E+ R+ x8 I2 j
- 0x01, /* bConfigurationValue: Configuration value */
1 G. t. _2 ]0 e5 Q+ P2 ], K - 0x00, /* iConfiguration: Index of string descriptor describing the configuration */+ [1 R! m4 w5 B2 ^. U3 S; m. L
- 0xC0, /* bmAttributes: self powered */
J V5 b# N4 ?; a - 0x32, /* MaxPower 0 mA */' K6 y: I1 K6 X( T
; K0 }$ K2 p7 M/ b! Y2 _5 E: U- /*---------------------------------------------------------------------------*/3 s- S) [4 |+ M& O" H ?
- % C# X3 [6 n1 [2 K G# G3 H% D G8 `
- //1 n% g: r% z% Y* W4 y3 Z
- // +++lakun: IAD(Interface Association Descriptor),用于指示CDC
2 g5 G9 Y/ n, p% p4 F - //2 @ u8 O" m- w2 |; e# s% y
- 0X08, // bLength: Interface Descriptor size,固定值$ T; t4 D, B P( R" w
- 0X0B, // bDescriptorType: IAD,固定值0 P2 {1 Q0 d2 T7 P. j3 y. d
- 0X00, // bFirstInterface,第一个接口的起始序号,从0开始5 N. M" x+ a" {; Y- n
- 0X02, // bInterfaceCount,本IAD下的接口数量
1 Z: m" v7 q r/ w: l - 0X02, // bFunctionClass: CDC,表明该IAD是一个CDC类型的设备+ p$ S3 |9 a% f' C( u& g1 Q
- 0X02, // bFunctionSubClass:子类型,默认即可2 r8 S' x3 }4 q
- 0X01, // bFunctionProtocol:控制协议,默认即可& ?% a9 x# |& U7 b. |% L/ x
- 0X00, // iFunction
2 J- _" }2 d$ n+ T7 ?/ c
; S7 h4 `* R" e' n- /*Interface Descriptor */
7 A3 p- a4 M0 N8 i& e% D: l - 0x09, /* bLength: Interface Descriptor size */1 y9 K) V- {7 Q" e8 ?, f
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
" Z. ^' t2 E& l. \) e. ^# d+ {- { - /* Interface descriptor type */
" Q+ P! \. w0 }3 U* M6 K$ M) \7 L - 0x00, /* bInterfaceNumber: Number of Interface */ /* +++lakun:接口编号 */
- r1 d+ x/ \9 Q - 0x00, /* bAlternateSetting: Alternate setting */0 }! g3 p4 ^% Z. e0 {0 r
- 0x01, /* bNumEndpoints: One endpoints used */
) `, g( h# K9 J - 0x02, /* bInterfaceClass: Communication Interface Class */ /* +++lakun:表明这是一个通信接口 */
% A5 \2 \% A5 {! ~) D- Z - 0x02, /* bInterfaceSubClass: Abstract Control Model */
/ X. b) i! Q: w) ~0 K G, c - 0x01, /* bInterfaceProtocol: Common AT commands */
# R8 g1 X4 x0 d, M" R. F0 y - 0x00, /* iInterface: */
, g# w3 b- c s2 P - 0 ^3 b4 z) u0 m3 D4 w1 M5 ?
- /*Header Functional Descriptor*/* x A; N* q4 @
- 0x05, /* bLength: Endpoint Descriptor size */) C# ` D! _( S4 r
- 0x24, /* bDescriptorType: CS_INTERFACE */
' P& Z( b1 M# d7 q) n - 0x00, /* bDescriptorSubtype: Header Func Desc */1 \/ C6 j3 Z. R5 k4 k& d3 _
- 0x10, /* bcdCDC: spec release number */6 t/ T/ o' X7 A1 y$ c
- 0x01,' d* X" Q" u; w! F* r; A/ [
3 ^1 Z) m g U, y: ]- /*Call Management Functional Descriptor*/
+ W/ I5 ^, r# l$ p e - 0x05, /* bFunctionLength */! h/ h0 u9 e0 g7 _- ~0 o+ S
- 0x24, /* bDescriptorType: CS_INTERFACE */
* b% W+ _4 e3 l- F3 y6 ~ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */
, l3 C& B5 u' F' m; v2 R1 l - 0x00, /* bmCapabilities: D0+D1 */
: B$ h5 a% ?) ^9 R0 r - 0x01, /* bDataInterface: 1 */4 l+ w9 x/ Z. b/ F/ I2 [1 Z
- 0 z$ i8 ~: B: P5 O P' n3 p7 h
- /*ACM Functional Descriptor*/
) \- Z3 S- j$ u; @& `5 R( B `$ C - 0x04, /* bFunctionLength */
1 q N8 w* b( o7 Q( A, u- a; t+ F - 0x24, /* bDescriptorType: CS_INTERFACE */
4 m: Q {2 G) B3 C8 i- s+ @ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ {' F) m$ r, [
- 0x02, /* bmCapabilities */& [! k% F' ?3 h' O9 \; g
- ) S) ?/ g; l' i3 z
- /*Union Functional Descriptor*/) r: i T5 k/ M t
- 0x05, /* bFunctionLength */
$ @* C; i4 c( ~% o; D - 0x24, /* bDescriptorType: CS_INTERFACE */
6 `1 T2 a% a+ |1 U3 c; {$ j - 0x06, /* bDescriptorSubtype: Union func desc */
4 e* p6 f( s8 Y e8 j: Y7 @& a - 0x00, /* bMasterInterface: Communication class interface */ /* +++lakun:这里是用来指示CDC通信接口的编号的 */
* G0 u: X! m0 w3 K* c$ } - 0x01, /* bSlaveInterface0: Data Class Interface */ /* +++lakun:这里是用来指示CDC数据接口的编号的 */
2 s& e% ?( Q+ P: X - * H/ D h" r- m+ f- D0 p+ S
- /*Endpoint 2 Descriptor*/
' w- x( J% X3 z0 @1 _( D j. `6 a - 0x07, /* bLength: Endpoint Descriptor size */" u' D) I& z8 o
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
1 g0 D2 ?+ c# Y8 H( X' y5 A - CDC_CMD_EP, /* bEndpointAddress */5 k( E% i' N; ]+ _' w+ u! ^
- 0x03, /* bmAttributes: Interrupt */
1 L* P3 k r+ t3 n - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */! l2 i" x! w8 R" g' x; ?
- HIBYTE(CDC_CMD_PACKET_SIZE),
# U* L* n `* H* l" U - CDC_FS_BINTERVAL, /* bInterval: */
* H s' [4 \9 e6 ^) G - /*---------------------------------------------------------------------------*/0 ^$ g0 j# f7 g* c
- 2 i# }7 W1 J _/ Y- x( m% i
- /*Data class interface descriptor*/8 ^: { |. |- A6 [
- 0x09, /* bLength: Endpoint Descriptor size */2 n9 k5 d6 g6 M$ L2 [, o) }& b
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
# P" L' U% k& N9 ]6 H% P. q% h$ R+ f - 0x01, /* bInterfaceNumber: Number of Interface */ /* +++lakun:CDC数据接口的编号为1 */
+ d R2 I( _2 n' n( a" F2 F# D - 0x00, /* bAlternateSetting: Alternate setting */% r: W: w/ L- O0 m7 ]4 B
- 0x02, /* bNumEndpoints: Two endpoints used */9 {3 s% G- d/ q" ?
- 0x0A, /* bInterfaceClass: CDC */) W) x+ C* f/ @
- 0x00, /* bInterfaceSubClass: */ Y1 w* O+ s/ j F
- 0x00, /* bInterfaceProtocol: */
) ~; A; k/ K" j4 l4 Y3 k - 0x00, /* iInterface: */
& | h/ F) c+ P8 ~- E
4 s9 _: C6 ?3 s9 ]3 U- /*Endpoint OUT Descriptor*/( l# I4 Y: K" Q! Y) V2 w3 k2 S- D7 }
- 0x07, /* bLength: Endpoint Descriptor size */
; Y% ~2 r0 y. E2 H; F% T1 D% N - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
: B c; S) t8 O - CDC_OUT_EP, /* bEndpointAddress */8 F, Q& C9 O( J( D5 x
- 0x02, /* bmAttributes: Bulk */
; F: j* c" u4 u - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */8 v2 T1 ^9 r$ n1 o
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
% h$ p+ x6 h* c: g - 0x00, /* bInterval: ignore for Bulk transfer */
5 A$ ]. Y* z4 K - # P) r) x# R( ^0 k& i, K6 n
- /*Endpoint IN Descriptor*/; N6 H0 Y# E* `/ ?! j
- 0x07, /* bLength: Endpoint Descriptor size */
1 P; c: O/ k( H1 ^1 n5 x# P; T - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */+ @6 O, N8 N1 B4 Q4 h
- CDC_IN_EP, /* bEndpointAddress */( P8 B/ Y3 @6 A8 a6 Q% O! }5 R
- 0x02, /* bmAttributes: Bulk */
; U* p B2 k. b" @2 W% {% K - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */% }/ ^) E, A- w3 ]) g* i8 h* Z
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),% T+ q6 |5 ^' @; {- P, n
- 0x00, /* bInterval: ignore for Bulk transfer */
. u# ^+ `2 w9 M! b: o2 n. d
# j# N. U5 L& g5 ^/ V5 P F$ Z- //
! C# }# q5 J( o6 F6 h" p1 F - // +++lakun: IAD(Interface Association Descriptor)
+ P: c/ p" t' o6 ]# G, P. \ - //4 k. y' B1 n: K" J. `! `+ X
- 0X08, // bLength: Interface Descriptor size,固定值) ]4 |8 A6 _% t; }
- 0X0B, // bDescriptorType: IAD,固定值' c9 {( D( \ ^3 i9 ]
- 0X02, // bFirstInterface,接口的起始序号(第0、1编号的接口用于CDC1,所以从2开始)
! k/ A9 M5 X' U0 }0 {% T+ W - 0X01, // bInterfaceCount,本IAD下的接口数量$ l& C3 C3 J+ v: c- }; y8 `8 @
- 0X08, // bFunctionClass: MSC,表明该IAD是一个MSC类型的设备
5 u5 O3 h4 B; ?, p0 Z - 0X06, // bFunctionSubClass:子类型,默认即可9 n, k2 ?& Q) C4 Z+ R) R/ n9 ~
- 0X50, // bFunctionProtocol:控制协议,默认即可5 v6 E) G2 Y* C& n% V0 k
- 0X05, // iFunction9 N$ T3 M: k% `( F
- O2 j d& O8 U4 G" E; w. D! B1 M3 a: g
- /******************** Mass Storage interface ********************/
. y- D2 C! F& n2 h- X$ A9 z - 0x09, /* bLength: Interface Descriptor size */
7 X" R2 r: ~$ J* C3 y8 o6 R - 0x04, /* bDescriptorType: */
9 e) f0 M: M: `/ [6 S& b - 0x02, /* bInterfaceNumber: Number of Interface */ /* +++lakun:第0和1编号的用给了CDC,所以MSC接口的编号从2开始 */' e x5 M; w1 H7 H% D
- 0x00, /* bAlternateSetting: Alternate setting */
& w; l) S6 G' Q* O& |4 h - 0x02, /* bNumEndpoints*/7 H* `. [) g2 d" P
- 0x08, /* bInterfaceClass: MSC Class */: A3 |" w' |( ~2 r
- 0x06, /* bInterfaceSubClass : SCSI transparent*/
; d. N! h& f, M9 L H1 d - 0x50, /* nInterfaceProtocol *// ~3 i+ N: r v# p) Z, d
- 0x05, /* iInterface: */3 ^7 G% S7 B F9 A& @
- /******************** Mass Storage Endpoints ********************/
' u6 v! q' [& S% O# ?7 T/ F9 X! Y - 0x07, /*Endpoint descriptor length = 7*/* c# l) s+ K3 \5 J: Y
- 0x05, /*Endpoint descriptor type */ ^0 L" J6 E' f% E) N
- MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */6 A4 | F Z$ o0 i" P7 `# r+ B0 t
- 0x02, /*Bulk endpoint type */+ p. ^/ q- n6 e" X
- LOBYTE(MSC_MAX_FS_PACKET),
( B6 }- O4 `7 k" q; } - HIBYTE(MSC_MAX_FS_PACKET),2 j" W9 d* ~) j
- 0x00, /*Polling interval in milliseconds */6 N: L% F' K( x* d1 y3 q! J8 ~
1 X+ B1 {6 `) v8 t4 W% A- 0x07, /*Endpoint descriptor length = 7 */$ J. c% o8 I& |& _
- 0x05, /*Endpoint descriptor type */+ ?$ A* E% t% Y5 [
- MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
* q V$ q9 w8 E( J - 0x02, /*Bulk endpoint type */; c: q2 p* C( V: ?8 c
- LOBYTE(MSC_MAX_FS_PACKET),) n* G9 p; @% Y# u: i- q
- HIBYTE(MSC_MAX_FS_PACKET),/ f9 v) Q, |" R" k* R: \) F4 ^
- 0x00 /*Polling interval in milliseconds*/& d* g6 c" V6 }8 E# ~6 i
- } ;
* r- n; l7 q4 M7 k% t/ S5 f* x - / \/ V5 n" ~( T, n! d7 T6 c# N( A( }
- 6 q0 g( O( B% I! \
- /* USB Standard Device Descriptor */) H' W/ k9 Q2 {$ y
- uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] =
/ V. @7 \! Q& D( r& T& m- W8 x - {, T5 d& @6 t8 N- r: R
- USB_LEN_DEV_QUALIFIER_DESC,; F: {( y, H, ~+ N
- USB_DESC_TYPE_DEVICE_QUALIFIER,. J% x, Q: z1 u c f+ f8 N4 U
- 0x00,
6 o: G- M1 `: m( a - 0x02,
, a- Z2 z4 @! x. j$ s - 0x00,9 Y; X" E+ v, {' L% D
- 0x00," a% r, o" L: r; D# D9 W
- 0x00,; M: T. {+ S; z# R3 f
- 0X40,
( O p) H2 e8 L# | - 0x01,
# e. b- W, D+ @ - 0x00,5 t9 x' p) d6 z5 W
- };
& a! _) }5 ^* O. p
, f0 d6 I5 @; \! C+ Q7 x4 {7 _- ! F( P3 }, U0 Z" ]+ }, L
- // 这个函数是修改的USBD_MSC_Init
2 Z3 q9 T1 K8 n0 n - static void USBD_Composite_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
3 B1 \, F3 b! R0 X - {9 e* H- g! ]6 V+ @& o* b, [1 I
- USBD_Composite_Switch_MSC(pdev);
5 f& X1 o& o* a* `" b1 T; V. ` - . {/ P" h# x& B
- /* Open EP OUT */' O' _0 P, Q0 C, S. q! Q
- USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
+ H/ K; s; c7 v! M+ f/ X2 k. r - pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 1U;% I7 v0 ?# O2 {/ a2 }# j
- , P3 D0 C" L0 T# X/ \
- /* Open EP IN */1 H. h) \, A- R* d
- USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);# _# H# N/ Z! l/ n. R# h2 x
- pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 1U;. ]' u: n5 f3 S s: B
- W8 u: T$ E9 W- L; P' ]
- /* Init the BOT layer */' J3 j# @) K% V8 ]* ^' f
- MSC_BOT_Init(pdev);2 e$ E: L1 A% k7 c
- }) K+ J) g- j; ^3 I1 A/ s T/ `
. o& N9 U. U! U' ]2 Y: \7 r' |) l- // 这个函数是修改的USBD_CDC_Init4 Y) Y7 W7 k+ I" [) y* [& ~
- static void USBD_Composite_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
* Z3 G" m% G9 o, O% j4 ^# a$ ~: A2 @* g - {8 t6 W2 ^9 u# L$ P: i0 Y
- USBD_CDC_HandleTypeDef *hcdc = NULL;! q1 J5 k$ J$ T( D3 }; B; \' q s
- W: f) p- \. {# I' U. G- |- USBD_Composite_Switch_CDC(pdev);
* `" N; t; J2 l9 P0 [! z7 w9 _6 k
2 z9 L! o* e z: s! e1 q- /* Open EP IN */' O- C9 E) H. ~7 v/ n8 H1 D
- USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK, CDC_DATA_FS_IN_PACKET_SIZE);
, z9 ~9 L' R6 W M - pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
& o& c; y \1 _3 d1 C2 ?5 d - 0 B7 Y7 o- r( V4 b# w
- /* Open EP OUT */9 F" Y9 e# l9 W H3 {
- USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,CDC_DATA_FS_OUT_PACKET_SIZE);+ g) T# ^6 S5 b5 k; I2 W
- pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
0 @. d( g5 e# f! r4 b9 e4 x9 r
. E4 g3 P7 u8 ^2 m3 s- O3 D- /* Open Command IN EP */
# Q# r' B& f+ Q8 c1 P9 i: ] - USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
: i& O/ v9 b9 x+ P& l - pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
( x4 J( |. S9 u8 H
h2 ^9 d9 l, P; a2 |- hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;: O/ t) u3 H) _8 Z2 o7 I @0 H0 t9 o
( H% q1 z0 D7 H# U+ B- /* Init physical Interface components */! e+ u3 @$ s9 \4 U! q: Z8 Q" V& Z
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();6 q5 T# ?2 C6 V3 P+ _+ U N2 @' z! r( J
- 7 T$ L% |" e2 n- o( V
- /* Init Xfer states */! @3 @* j* H+ R
- hcdc->TxState = 0U;
# u& C" L: q$ i3 W" Z+ _+ ] - hcdc->RxState = 0U;
5 P- `- v: C) D6 I! G) } - . `8 M9 }5 u! u9 ^
- /* Prepare Out endpoint to receive next packet */3 ~3 q/ t! ?7 Y9 L: i6 f
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer, CDC_DATA_FS_OUT_PACKET_SIZE); ?# u+ d- Y+ L' ^0 [; i
- }8 ] j6 M T9 u
v& o& |2 m1 x/ C6 m2 s# {3 |- uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx). X) i( t+ h9 B
- {4 {9 D" g: N, Q' \: a8 z; e
- USBD_Composite_MSC_Init(pdev, cfgidx); // 初始化MSC
2 z0 B; q7 v. Z6 k1 f* _% x. K - USBD_Composite_CDC_Init(pdev, cfgidx); // 初始化CDC7 D: L' f f3 w, o; j1 D
- return USBD_OK;
- H2 f h6 R8 a: [) V - }) m- h8 R1 A J$ r; q7 c9 x
" r/ M8 |5 U: A, V2 n& m$ ?+ q/ y- uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
4 ^+ F. C5 N# _% J8 w8 o - {' r2 T% y) f4 ~1 `
- return USBD_OK;8 K" Z* P9 U( E" z
- }* B" i2 [1 z/ |% j
- ! q; q8 z6 V2 g4 w! M$ p7 A# f
- uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
" F: g% z' M- B3 N - {
2 w) b) V2 O6 ?5 m% J- m9 O - switch(req->wIndex) // wIndex是接口编号,在配置描述符里面我们第一个IAD是CDC使用的是编号0和1两个接口,第二个IAD是MSC使用的是编号2的接口' M9 E" e% q8 j3 X5 o
- {4 k- X, O) I4 @' l; U6 m& A
$ R% e H7 m* Q3 R: N- //
# I0 d% C5 t( c" p- { - // 第一个IAD& q" k1 }& n# R; c1 ]" R- Z
- /// d# R2 [1 Y% F* |% c, ^
- case 0: // CDC的命令接口编号为0
* n2 _2 G6 [ ?1 x* I - case 1: // CDC的数据接口编号为1$ V! P, C! v& J s7 Z9 A4 ?( L' C( E
- USBD_Composite_Switch_CDC(pdev);
* Y" D) E/ R* ? - USBD_CDC_Setup(pdev, req);
8 r! P: q, m, k1 i& x - break;
1 p5 D& L5 Q( `! ^- L
. n) V Y5 X; p- Y4 k- //2 T9 q" g1 R F6 P, T6 B
- // 第二个IAD
1 u; k& V( |6 w3 n& u - //5 t' Q$ e0 B" ]" o8 y
- case 2: // MSC只有一个接口,编号为2
; P5 E: ]4 }% J7 o - USBD_Composite_Switch_MSC(pdev);
Z! f6 f/ K" ?4 k - USBD_MSC_Setup(pdev, req);9 [5 a" y5 ^7 C V( S1 U7 [
- break;) _; d4 ]' e* R1 ]" O. l0 Y. q8 K
" l* n* v4 @4 S2 f8 U- //
& o$ i* _3 _8 ~& l' B2 i2 y - // 第三个IAD(如果有,在这里初始化)
! B; t1 e& J% l1 l" x* o* }" Y - //
7 V- f& k0 {' y - case 3:
y3 g$ k" y( K% W3 l - break;
6 n) ]; @- P9 |* X - default:break;
. t7 X/ u! u4 ]+ j( d9 M - }" k4 M9 K& E$ ?! |
- return USBD_OK;
% c4 l1 E! p& d7 g* ]- U. n/ g - }
6 M! Y0 A' S& u, N/ u - / u3 g2 ]$ _5 E: g5 V
- uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
; a! K6 S m6 R% Q- ~ - {" p2 ~7 Y: o+ {2 n
- switch(epnum | 0X80)
+ p: l1 Y3 _! Q' q% X5 C! n5 \- g - {
. p2 q) A) i# v: | S7 X/ x - case MSC_EPIN_ADDR:5 ]% K6 g, ~) e z
- USBD_Composite_Switch_MSC(pdev);9 g: u4 m( s) ]9 h. y) c
- USBD_MSC_DataIn(pdev, epnum);
7 J6 d$ d& N$ h f - break;
/ K6 l, l5 ^3 @- `6 Y3 [ - case CDC_IN_EP:( a9 p8 U7 C$ Q& Z+ p
- USBD_Composite_Switch_CDC(pdev);7 ^7 V. l. T, M$ N
- USBD_CDC_DataIn(pdev, epnum);
+ X# N9 F p9 S# { ?3 B, B/ { - break;4 f. ]1 C! A; U" p) W p
- default:break;
4 I; o/ j( ^% S# t9 V h% H - }
+ Q5 L2 I. S# P; R, Q5 k+ J - - H" T9 Y! o: [* Z; w3 e
- return USBD_OK;6 ?$ W! o3 T( R
- }% n5 k6 J1 Z# s
- " F4 F! v* O6 d3 l" F/ B) H% a
- uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
! |) v6 |/ k1 H2 L - {& a. |& Q6 h: ], Y
- switch(epnum)6 T" p* l/ I! D: U3 ]- u
- {3 e3 H& b. q- b" Z2 s) r
- case MSC_EPOUT_ADDR:% e, \5 G7 ?% W: z! S* ~6 {4 ~- w' s
- USBD_Composite_Switch_MSC(pdev);
5 e8 f' x5 Q4 j2 p' \3 c5 y - USBD_MSC_DataOut(pdev, epnum);3 [& l. _9 G0 k3 w& u2 r) B
- break;; l+ u! S$ B9 W* {) c6 r
- case CDC_OUT_EP:4 Z* k2 s8 C; @ n, s
- USBD_Composite_Switch_CDC(pdev);" b5 d l0 ? v2 T9 _! z; S( F7 B
- USBD_CDC_DataOut(pdev, epnum);/ l" t7 N" }+ _# b
- break;
5 N" D1 S; s' e0 X+ t/ v - default:break;" r! U7 d5 Z% j) `! y/ |+ ~: e* W
- }6 l: `+ k/ l6 y9 Y Y% R! s
- return USBD_OK;
6 x b+ Q! z% P" j4 L - }/ t* b% F/ t% j" G: m
- ) I$ V# }% J5 f+ C! Y
- uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length)
( R# L2 h. T* x: n - {2 j6 Q) f6 w6 [) {0 x
- *length = sizeof (USBD_Composite_CfgDesc);
* }$ O8 k) G* O - return USBD_Composite_CfgDesc;
; @, n$ G: R4 l) y' O! y e' Y - }
5 l& k: s) D; ^. O- z: f
+ ~3 d, M6 T1 q3 O- A- uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length)
; O- T: T2 a1 ]. H6 S8 N% n% G - {
. I5 M. `) d! E# Z - *length = sizeof (USBD_Composite_CfgDesc);
. R2 J# \! n5 A$ Z* a5 p - return USBD_Composite_CfgDesc;
; \" n% P8 I, X# W1 H- N; n$ A6 v - }
& F9 X" T. F8 l - . P0 g( u! V' c7 x# c+ o. c
- uint8_t *USBD_Composite_GetOtherSpeedCfgDesc (uint16_t *length)
6 o' g8 ~, ?3 I0 T - {
3 O# X- M: Q. Y/ }& p" p2 P( z( Z - *length = sizeof (USBD_Composite_CfgDesc);
% _ m0 V3 B3 { - return USBD_Composite_CfgDesc;
+ F" C w- R. n$ ^! O5 b5 D+ R - }
/ t' f' m) Y/ Q! X7 E( a
$ V# d8 a# ]0 B- uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length)
' v) m0 Q9 I) x6 B# K+ L - {+ U& [5 A0 P4 ]5 X
- *length = sizeof (USBD_Composite_DeviceQualifierDesc);" i/ e8 I9 O/ }& `8 P: G r
- return USBD_Composite_DeviceQualifierDesc;
; v0 M2 s# Z3 U# R - }! B& C% u- @' r3 z
3 U! U8 K+ Z- E3 I. L- static uint8_t USBD_Composite_RxReady (USBD_HandleTypeDef *pdev)
3 Q4 G0 l- m* u( J - {
. a5 m! U# H5 O! e7 s - uint8_t ret = 0;
4 B( o* }# k1 J; W1 q8 y9 a - switch(pdev->request.wIndex) // wIndex是接口编号,这里我们通过接口编号确定CDC还是其他设备的EP0接收
3 e4 L0 h9 V$ e; ]9 |2 { - {
+ _% C! m' d1 z2 G: y9 Y) @ t7 @ - case 0: // CDC的命令接口编号是0
, G" P1 P9 X, g1 _6 L - case 1: // CDC的数据接口编号是1
& P5 J* J: y3 d# j% y' V - USBD_Composite_Switch_CDC(pdev);5 M' u5 \' q3 i4 J4 T
- ret = USBD_CDC_EP0_RxReady(pdev);6 ?+ P* y) U0 W6 G8 m
- break;+ a+ o4 H2 H3 ~ e" N
- // 如果有其他设备还用到了EP0接收,在这里加入
9 Z/ e4 g- h4 ?4 M+ @' D - case 2:$ A; x8 H3 N1 m
- break;
/ B# a3 y6 f+ \8 }+ e J. w - default:break;
2 ?( c4 Z/ C# M9 a$ X/ } - }
( E( {# ^ t: ` - return ret;7 m/ t& \* ~- Y6 _4 ?/ \; \0 h# v. W
- }
; g1 m. u4 n/ u; L& L1 q) f" T
# q( u. |& m% P/ P2 ?- static void USBD_Composite_Switch_MSC(USBD_HandleTypeDef *pdev): S5 D$ O1 \7 R! f6 V9 x
- {
" f3 U7 e. j/ [4 p - static USBD_MSC_BOT_HandleTypeDef USBD_MSC_Handle;
2 N0 p) {/ _' Y; ^8 i) [9 J) g6 O - USBD_MSC_RegisterStorage(pdev, &USBD_Storage_Interface_fops_FS);
! m" K$ V. n* L - pdev->pClassData = (void *)&USBD_MSC_Handle;% Z Q$ z6 m. p. O5 r
- }
9 { Z) P1 |/ q
1 Y- A0 J6 V0 s3 |3 p! S+ H! I- static void USBD_Composite_Switch_CDC(USBD_HandleTypeDef *pdev)
' P9 C) p' |0 J$ ?5 l/ a( N - {) B/ E2 t8 m; c
- static USBD_CDC_HandleTypeDef USBD_CDC_Handle;
- ? X4 z) f/ R5 a7 t6 ]0 F5 q - USBD_CDC_RegisterInterface(pdev, &USBD_Interface_fops_FS);
- R! t% D" o; E/ q: a5 X; L l. d - pdev->pClassData = (void *)&USBD_CDC_Handle;5 `6 B2 i, \+ r% C
- }
7 i2 s. _" Q; _" f* s
复制代码 5 V, m* Q" f' Q5 \
其中有关设备描述符的修改,我都用+++lakun进行了标注,并写上注释,方便查看。1 u% Y% O! F: C5 ^# W3 w( g
( x1 v) P6 c! h: J第五步:MX_DEVICE_USB_Init修改
7 W3 W( n2 Q! i( a7 v5 _. H# [上面我们已经完成了统一接口的编写,现在就可以修改MX_DEVICE_USB_Init函数了,屏蔽掉接口注册函数USBD_CDC_RegisterInterface,然后将类注册换成我们自己的组合设备,如下图:
% T1 c. a$ T3 A- ~: C- t
5 f" H" {4 a& e$ e1 |( k. g, W& m
5 U' o+ s- L, r O3 P" g/ B) S) @; p1 G; Q/ ]* m
到这里就已经改完了,运行程序之后设备管理器会出现:一个组合设备、一个虚拟的串口、一个USB大容量存储设备,如下图:7 B* F: A7 n8 C
+ V5 J9 ?% e3 R. m s
0 y2 x& J* b% Y) |. c* t
% r. x9 ?: r {
这样就是成功了!
7 e6 p: M- M: M9 P! k( O
9 `4 k+ T J! K1 r5 N!!如果修改过后发现设备管理器的MSC或者CDC显示感叹号,那么在回头检查PMA的配置以及组合设备描述符!!
% w7 h% o/ p) L
) Y6 {$ F# Z7 D遇到的问题5 O- T* `2 d8 [ k: w
我修改完毕之后,将板子接入电脑,虚拟出来的串口没问题,但是就是死活认不出U盘,后来找到问题的原因是因为我先使用的CDC串口这个单独的工程,我的win10已经默认枚举成了CDC,所以认不出U盘。% m- p6 X7 q* t z* _
9 `, Y0 W1 P$ N1 G3 J- I解决办法:2 f" p1 m- k+ U, x& v6 T# i3 ?7 p
1.卸载识别出来的串口,重新拔插) i8 y' U% F7 |* h3 `% b; B+ _* x' ^
2.在程序里修改一下PID
7 [! m, U0 M/ w( u0 H# Z% y/ L
+ ^# a) N0 {/ U- e. u, G. D! [; ]5 |* ^% T& |! \ W, H
- ], a) Z# M6 \! V8 O
/ d5 D5 S6 N' J. j \4 c我是用的第二种办法解决的!6 q6 \* P( a& C5 A2 X2 b
0 H5 p/ I- U; B g5 K3 x- ~. M4 j2 |
: n: x: x7 A8 p9 E, C
. X: \& b! g( T) W4 A" ]" F8 A |
不需要composite.h吗?编译出错,有几个没定义的。能给个源代码吗?不胜感谢
是拼写错误导致的,程序可以运行。谢谢