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