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