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