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