1. 背景- 由于项需求,在STM32F072中需实现5个CDC设备,折腾了很久分享出来,希望能帮助别人少踩一些坑.USB2.0全速,该款单片机支持8个输出和8个输入端点
- * G% k* l5 S2 Q: o
2.1 它是什么?需要使用到什么?- 它是USB设备类型的一种,如U盘插入电脑时,电脑会知道其是U盘,是一个存储设备,那么它就属于USB MCU存储设备。USB协议中对设备进行了分类.它在stm32上叫虚拟串口设备,当将其链接电脑后,可以把它当成串口使用,如使用windows的串口工具打开它,设置波特率等等,这是我的理解。
4 @6 _5 e! C! L; K' L$ _: `
+ { q* N# y8 b* T$ m
- 它需要两个接口,三个端点
! x4 U p1 h5 [) S& a2 N
7 z+ [% p* @" w! s1 ~
- InterFace 0:第一个接口,其包括一个端点,和Functional_Destriptcrs,该端点为控制接口(输入型端点(IN)),Functional_Destriptcrs则是一些描述符。先不管这个
- InterFace 1:第二接口,其包括两个端点,endpoint In 和endpoint out端点,IN为stm32数据输出端点,OUT为stm32数据输入端点,随便提下,在STM32 HAL库中,USB的IN,OUT是相对于主机而言的,如:上诉的IN是指主机的输入,主机的输入(IN),对于设备来说就是OUT,数据的输出端点,IN OUT都是相对于主机而言! s& p1 M; ` }6 O4 P3 X
- 由此可见,正常情况下,一个CDC需要三个端点,其中两个IN端点,一个OUT端点( n* x' j6 {! e7 }! y8 q5 a
4 s$ a$ z+ Y6 i3 m9 G 3.配置过程3.1 配置流程- 在STM32CubeIDE的帮助下,生成一个CDC的代码,这里没什么坑,点几下就成功了,注意的是可能需要将Heap设置大一点
- 修改设备描述符
- 分配端点和修改配置描述符
- 分配PMA端点缓存地址
- 修改HAL库关于CDC部分函数接口的参数,以适配多CDC设备的情况
- _7 P3 r# w! e- W' e& ~0 q & v7 C: l3 a. U! j) [$ H7 x
. h" a4 x3 ~7 Y; E t
3.2 使用STM32CubeIDE生成一个CDC程序的代码- 根据下面的文件操作即可,文件会介绍USBCDC的知识,在PDF的最后会说怎么使用cubeIDE配置,很简单没什么坑(注意的是可能需要将Heap设置大一点)
4 y2 A) ~8 V, X( y( a6 N9 Y
, \) V2 t* |) {; ]7 X. C0 f% {# i3 U0 ~
3.3 分配端点和修改配置描述符- 此时问题来了,CDC要求3个端点,其中2个输入1个输出,而stm32F072只支持8个输入端点,8个输出端点,2x5>8,正常情况下是不够的,这里就需要将IN端口中的控制端口省略,也就是第一幅图中的Interface 0中的endpoint IN端点,不分配有效端点给它,在本款单片机中IN端点的有效范围(0x80-0x87),OUT(0x00-0x08); T% G+ F6 T; p
. _, x1 _% [& |5 Z: S" j
& W; i4 x- V, }% v/ F5 m$ K
- #define CDC_IN_EP 0x81U /* CDC*/( y8 D. N8 S0 u+ U$ i( T
- #define CDC_OUT_EP 0x01U . ?- S J; D1 z# m
- #define CDC_CMD_EP 0x88U //无效端点
' f: F0 L- O' L! w: | - : ^7 p- y7 u$ k
- #define CDC_IN_EP1 0x82U /* CDC1*/
! ^/ \; L% p1 ~ - #define CDC_OUT_EP1 0x02U ) j* H, E( w* Q9 H% I4 J! i8 a
- #define CDC_CMD_EP1 0x89U //无效端点
& g0 ]6 t9 q0 S% W3 ]3 j- ~ - & q7 `$ g4 V, M! B1 B
- #define CDC_IN_EP2 0x83U /* CDC2*/$ L3 b( U/ Z6 G3 x2 S! j
- #define CDC_OUT_EP2 0x03U
; `! [& [7 V: f" M+ ] M - #define CDC_CMD_EP2 0x8AU //无效端点
1 `! \0 ~4 W; L* M0 G# d - # w1 v+ q2 p1 H: f9 ?+ s+ l
- #define CDC_IN_EP3 0x84U /* CDC3*/1 U5 B. ?8 y/ Y$ L8 i3 }- z/ x9 m6 L
- #define CDC_OUT_EP3 0x04U
+ } O! X* y9 F! j% _/ s1 z - #define CDC_CMD_EP3 0x8CU //无效端点' _; ~. t5 p4 q9 ~& v
- ) F( Y* `, N' w* R5 o$ G: N
- #define CDC_IN_EP4 0x85U /* CDC4*/
. H; }1 W* T! b) {" T; h6 ~ - #define CDC_OUT_EP4 0x05U
6 u. Z+ z0 b$ M - #define CDC_CMD_EP4 0x8BU //无效端点
复制代码 % I5 n- J$ `7 j: U ^
- r7 q# z+ K5 f- F( n+ g6 n
- 修改配置描述符号,这里面的内容就很多了,里面涉及到USB方方面面的属性和参数,其中USB_CDC_CONFIG_DESC_SIZ是该结构体的大小,记得修改,或者直接改为最大255。8 d% f( ~. X7 ]0 o4 J
- 配置描述符的结构如下:
% }' S- E: b0 c$ E/ K0 f- `: {1 ^, H2 ~& O% L: i$ c9 P
- 配置描述符
* \$ q! A$ S' \+ M: p - {
% g) _& o" W% u- w( Y3 @ - 配置描述符总概括(相当于预览:9字节)
, p9 t6 [) n3 H" e7 H3 L) _ - IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC1 C( {" b( t# V S2 I- B9 l
- {
. m6 D$ c" j. p/ b3 x - 接口描述符1
" V+ ?' v. r) x6 ` b. h @ - {+ Y; `" t/ f; G4 b, H J D
- 其他描述符(ACM等)9 t1 N% f& w7 d5 L8 E
- 端点描述符(控制端点)) a6 G& _& _: G2 P1 A3 V
- }! u5 K; A3 H0 @3 J7 X* B+ f
- 接口描述符2
8 |! O: `4 l6 ~) c2 l$ b - {" F; k( w3 a' S
- 端点描述符(IN)$ C) i9 }6 f; a) D9 j% K* d
- 端点描述符(OUT)1 n; B" F, e a) |" f. Y4 F) ~
- }( B$ n; |. E0 n* N! L0 H* [
- }
/ W% \ q4 K' v
* q, d8 O) v/ h% e- IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC1
, _0 ] A; d8 @ - {
, L3 k/ m5 T; B- k! a! ]/ v; N - 接口描述符1
7 Z7 P5 U# q& q1 h - {
4 U) s/ h. A9 @; | - 其他描述符(ACM等)
& o; M3 M4 y# u" Y - 端点描述符(控制端点)
f' s: X( P* A T* M8 a0 w7 g - }5 x X8 } V9 `* D4 i; l% [' w
- 接口描述符2
- b h3 {3 s) B - {' ]4 |! ]( J4 B7 @0 D5 `% H
- 端点描述符(IN) s0 I- ?" S) J
- 端点描述符(OUT)
8 f! U3 V% s/ M0 p5 u1 D - }
# e- ^$ j( ?* W& y+ P C0 o - }% H6 B7 L0 S" f) a% `' g- u
o4 H, x0 Z7 K2 o% n. q' [5 ^- IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC2
# g2 R+ S' ~/ [( Y - {" c/ L( L) [9 u! O) v6 K9 @1 P
- 接口描述符1
% u1 W( h% Z4 ^2 X" t: O - {/ C4 I5 N; A8 G% }& b: U
- 其他描述符(ACM等)
) r! j/ B8 C6 k, y* u# @. V - 端点描述符(控制端点)
) q; x) t2 Q7 X: s - }4 o, o, Y, L. I# r: o
- 接口描述符2
0 N$ Q5 a# N# m - {+ y- m3 \& Y5 Q: O7 S: t
- 端点描述符(IN)
$ e- Z* C$ o! R9 I4 M - 端点描述符(OUT) B/ f1 l# q* y2 k
- }3 r$ v; h, M0 L/ E% e
- }) R& |- I# W/ ]. s
! H; N7 k& ~7 L- IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC38 w. w6 b+ ^3 F+ B$ e3 ]5 `! E
- {( T" Z9 K% d; W1 e: T
- 接口描述符1$ Q: g* r+ D2 V* E
- {/ q5 q, n6 y& ~) o3 K3 `! Q
- 其他描述符(ACM等)4 g: U0 K$ M5 v' D4 \3 V) `
- 端点描述符(控制端点)% g' t2 V; B2 N5 l0 q n
- }# v2 l2 u a; j
- 接口描述符2
" j9 N- C3 X) a% B l - {* c6 ?) O* r y$ T5 h8 }
- 端点描述符(IN)( w6 P1 e- l) K1 ?, A' ^
- 端点描述符(OUT)
% E, S* o' [. e' J - }
: W8 c( F0 Y, u4 B) Z - }
4 w2 N- G+ R6 p) g! c+ u% X( b
& L' l' v0 t8 Q5 T7 o9 ^- IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC48 t$ ~+ p7 F1 w7 Z
- {
; d# t# W0 [7 D( S$ t* I: r! K - 接口描述符14 V2 z% N9 G0 z ]/ F
- {
0 k. \3 ^% t; b) A/ J' p - 其他描述符(ACM等)
& Z- b5 W, {) D% d" V/ U# v0 ] - 端点描述符(控制端点)+ {" B* p( w V$ \* K z; w8 l
- }$ J0 z( E1 P# N3 G% A, w# R, `
- 接口描述符2
6 X" _7 o. t4 B9 l. Z: t6 t - {" j& D3 I. ?+ j
- 端点描述符(IN)' r# d0 X s0 [# `' v f
- 端点描述符(OUT)
# M2 g" J3 q0 Y4 \ - }
( H, `' `+ B' y# w - }) x8 v* X' k9 d
- }
复制代码 & h0 z" B6 x7 Q" T' E9 M; s
- 配置描述符如下,下面有些字段需要修改的,都用casojie标记了,CTRL+F搜索casojie就可以方便显示;
* o( E3 \3 g0 v
" g: [2 I: [$ j' m0 Q0 ^' @$ P2 j$ `" j$ |6 }' }0 w0 A% @3 M
- __ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =6 @, ~, }! {3 g0 B
- {; O. U% J. ^: B2 W/ p1 Q$ I. ]
- /*Configuration Descriptor*/8 C3 _2 H' T8 K- p* D* k
- 0x09, /* bLength: Configuration Descriptor size */
5 w+ \$ q) v" m4 Z - USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */9 ?+ g# z1 B1 L/ h+ X# X
- USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */
% D; q p0 _$ [- t - 0x00,
! {( v/ t6 m! x, a7 ?3 a - 0x0A, /* bNumInterfaces: 10 interface *///总接口大小,5个CDC*2=10=0x0A casojie/ M0 {7 J: Q$ T$ X$ ?: z
- 0x01, /* bConfigurationValue: Configuration value */5 g0 f1 D- a1 G `: o
- 0x00, /* iConfiguration: Index of string descriptor describing the configuration */4 H/ v# L0 |0 Z$ }! r
- 0xC0, /* bmAttributes: self powered */
+ y* ]" a; k0 a' t4 @/ O/ p# Z - 0x32, /* MaxPower 0 mA */
* ?2 o3 G: D& D# f- s0 z q$ U - ( Z. G, {9 L$ O# R/ h
- /*------------------------CDC0--------------------------------------------------8+9+5+5+7+9+7+7-*/; F: ^. s, l3 I3 N. ^0 t% C8 ?! K( e/ _
- // // // IAD Interface Association Descriptor //IAD描述符需要添加 casojie- ^6 G* X, {/ U! @0 F" O
- // 0x08, // bLength: Interface Descriptor size //标识IAD描述符的长度,基本都是8,casojie
1 S6 D. a- h1 k/ |6 O* r8 M/ ? - // 0x0B, // bDescriptorType: IAD //不用管6 J* W* V! @% a; t# l0 c
- // 0x00, // bFirstInterface //第一个接口的序号9 ?1 Q* b# w. v9 M6 p, G
- // 0x02, // bInterfaceCount //本IDA的接口数量
0 [3 l7 k( S( l - // 0x02, // bFunctionClass: CDC //表明该IAD是一个CDC设备- r# _4 L7 ?3 h8 Q2 [& [5 F+ Z: J
- // 0x02, // bFunctionSubClass //不用管+ c- {& O3 D# Z
- // 0x01, // bFunctionProtocol //控制协议等其他我也不懂,默认就行; Z+ }; ?, A6 A. d2 g, H0 N
- // 0x02, // iFunction - a4 }" S3 x) v0 i; |7 r1 n! j9 [
- . e" m$ }# L; Q% o, M
- /*Interface Descriptor */
3 M+ r0 `5 C* h - 0x09, /* bLength: Interface Descriptor size */
- d/ D* c9 G( L7 ]; ^( x3 X/ ^ - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */( @* h# B- K: k6 l
- /* Interface descriptor type */
8 N0 `3 R$ j @) l) P - 0x00, /* bInterfaceNumber: Number of Interface */ //接口编号,从0开始 casojie0 L% s6 h( t D
- 0x00, /* bAlternateSetting: Alternate setting */; K2 X( F: Q6 r" P P! [% N* C
- 0x01, /* bNumEndpoints: One endpoints used */ //接口内有多少个端点被使用 1个 casojie( ?; u, f: a& q% f4 a9 q
- 0x02, /* bInterfaceClass: Communication Interface Class */
/ X+ C$ K8 B! ]' O# t: t0 h - 0x02, /* bInterfaceSubClass: Abstract Control Model */
, D7 T; _2 L, H4 u& D8 x - 0x01, /* bInterfaceProtocol: Common AT commands */
) I) ~5 d, d2 p - 0x00, /* iInterface: *// c" |( t6 I" L8 L' [ V4 }& {
- G* O7 s2 z+ k( h
- // /*Header Functional Descriptor*/& } B/ o1 b- i' j5 c7 O" s
- // 0x05, /* bLength: Endpoint Descriptor size */
! U7 P" C( @5 H8 L4 p - // 0x24, /* bDescriptorType: CS_INTERFACE */
( f1 z; ?, M+ h; k5 N - // 0x00, /* bDescriptorSubtype: Header Func Desc */5 T* k @4 m! {* {
- // 0x10, /* bcdCDC: spec release number */& e5 Q5 }" _) q8 I; R( f9 J% \
- // 0x01,, j; {& {6 ?) U7 k2 y) X" |
- * B6 f2 s# Z* E* Z4 F1 g
- // /*Call Management Functional Descriptor*/
; C, |9 Q; V. h- k% M9 H( [% j - // 0x05, /* bFunctionLength */5 E2 C# J, H: J+ j
- // 0x24, /* bDescriptorType: CS_INTERFACE */
5 a& `1 g+ V, H3 L' R - // 0x01, /* bDescriptorSubtype: Call Management Func Desc */! P# W0 [6 S' Z- V5 \
- // 0x00, /* bmCapabilities: D0+D1 */
- l- T* r! p+ H& k$ ~- }/ ^ - // 0x01, /* bDataInterface: 1 */
- C5 J1 I' v" w3 Q$ E9 K3 Q% _8 [ - ) a8 h5 e) T$ L; k* N9 M/ w/ m; Z! t
- /*ACM Functional Descriptor*/
1 Y7 P, v8 |! Q: y - 0x04, /* bFunctionLength */& O- G2 q3 g$ J$ T
- 0x24, /* bDescriptorType: CS_INTERFACE */2 T F8 C* m# n9 f# _
- 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
& g1 S( w; R, P4 I - 0x0F, /* bmCapabilities */
7 t# X: H% D7 \! r4 M5 {% x
6 `2 S, @$ h' u5 j- B3 I; i- /*Union Functional Descriptor*/
3 H% k! `" D) S3 v% v - 0x05, /* bFunctionLength */
/ Y, E/ S: Z9 k6 S$ K: o - 0x24, /* bDescriptorType: CS_INTERFACE */4 T$ R6 p! B% L' x
- 0x06, /* bDescriptorSubtype: Union func desc */
: e! O0 v9 b4 Y' P( F9 b1 j3 ] - 0x00, /* bMasterInterface: Communication class interface */ //联合描述符,与IAD功能类似,标识哪两个接口是属于一个设备的casojie
) l9 {# D ?8 `$ T - 0x01, /* bSlaveInterface0: Data Class Interface */ //与上面一样,上面是0,这里是1,标识0号,1号接口是属于一个CDC设备的 casojie
5 y3 g- h; h' i; q( {" ?2 u - ) E' R% ` k8 o3 Z' m1 w
- /*Endpoint 2 Descriptor*/2 f6 L% ~- S$ h& o
- 0x07, /* bLength: Endpoint Descriptor size *///控制端点描述符,虽然端点号是无效的,但是这个描述符不可省略5 s s m, x1 c; B7 j; v
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
( r0 F; [- H( V* S - CDC_CMD_EP, /* bEndpointAddress */! R6 ?' C- Z+ d6 g
- 0x03, /* bmAttributes: Interrupt */
5 {0 x2 A! \% Q5 V - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
2 G4 t! I/ m- Z8 L - HIBYTE(CDC_CMD_PACKET_SIZE),4 \( f( M; _. z; B8 L5 q8 z" g3 @
- 0x10, /* bInterval: */ , w7 j% s2 o9 G3 `9 ]
- /*---------------------------------------------------------------------------*/1 a, s8 g) G, e B9 \2 B
- 9 ^ U1 e/ X4 U" O v: \3 u
- /*Data class interface descriptor*/ //第二个接口描述符 casojie
5 f% Z9 w" r& V3 r - 0x09, /* bLength: Endpoint Descriptor size */0 T2 D* t3 q: d2 f
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */; y) _- q2 T2 d* J
- 0x01, /* bInterfaceNumber: Number of Interface */ //接口的序号,上一个接口是0,那这里就是1 casojie" G2 ^2 N: x; ]( ~, ]# X7 e
- 0x00, /* bAlternateSetting: Alternate setting */
6 i" g; f8 {; q# \* ]6 t - 0x02, /* bNumEndpoints: Two endpoints used */ //标识此接口有两个端点(IN)(OUT) casojie
7 |$ F# z! M* z$ R- R& ~' J - 0x0A, /* bInterfaceClass: CDC */
4 n, Z) b4 R. s) w# S C6 {+ Q - 0x00, /* bInterfaceSubClass: */
& j4 A8 b( }/ G f5 y - 0x00, /* bInterfaceProtocol: */
; b2 s w( {2 x/ s1 Q" z - 0x00, /* iInterface: */
' m4 c& ~% @2 H4 t
9 B0 l0 m! x+ J9 h$ @- /*Endpoint OUT Descriptor*/ //OUT端点" A# N( a& S% \* |( y3 ?; x
- 0x07, /* bLength: Endpoint Descriptor size */$ p) h- d/ [# W. I2 L4 P
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
, o5 x+ b% N N) o* ?* p% r - CDC_OUT_EP, /* bEndpointAddress */8 |+ j7 Y5 E M- e* @! y4 R
- 0x02, /* bmAttributes: Bulk */
7 G- S; p `. |: _1 h - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
3 w' m$ q9 k- ? F9 Y7 i! D - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE)," }, x6 _5 `2 ?. x' U
- 0x00, /* bInterval: ignore for Bulk transfer */& @$ O8 U3 e: Y7 H# c% X9 f. I6 q9 o
- . t! M! }9 e% _' S6 M) @! g
- /*Endpoint IN Descriptor*/ //IN端点$ c4 A9 @# v/ y0 {+ R
- 0x07, /* bLength: Endpoint Descriptor size */
2 P+ R! R$ S3 w* v" ] - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
4 Q7 R8 p9 D0 n4 a+ W* O y - CDC_IN_EP, /* bEndpointAddress */5 m$ }5 |' ^, v
- 0x02, /* bmAttributes: Bulk */
; y# e$ [: b# V' U! ^% J9 n - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */: a. ~& n* J( F6 C2 D
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),1 t6 I8 g7 m7 o E
- 0x00, /* bInterval: ignore for Bulk transfer */
) q4 l4 D# C! K' z) C; F2 r - 6 f' h* } l: B' h! p
- /*---------------------------------------------------------------------------*/
8 {* n- Q. H3 a6 G - // IAD Interface Association Descriptor //这里就是CDC1了,重复CDC0的配置过程,注意有些字段的序号 casojie$ p' m, O |; Z& y- W. {4 h" u: Z* @
- // 0x08, // bLength: Interface Descriptor size
1 J. I' \, I0 ?, K& H" Z! E- v - // 0x0B, // bDescriptorType: IAD* l( f+ Y% z) s# k" j9 p
- // 0x02, // bFirstInterface //太多了,写不下去了,意思和第一个IDA一样的
9 m: |- e7 c; p; t0 Z1 u3 d: S - // 0x02, // bInterfaceCount
' E# e G+ H9 H( i4 Y0 H - // 0x02, // bFunctionClass: CDC$ t, e3 V+ M: c3 ~: V$ k6 G
- // 0x02, // bFunctionSubClass6 v9 m% _* Y. r
- // 0x01, // bFunctionProtocol : S& D) W' D! u; |# K
- // 0x02, // iFunction+ v0 S# q- B. d) \/ k
4 @0 H; \# R2 z' r- /*Interface Descriptor */. O! p/ H r/ P/ i5 g* Z q9 U8 ]
- 0x09, /* bLength: Interface Descriptor size */
4 k k) k0 G( X4 F2 h L) c - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */' s6 r3 p* y9 M8 w" |* i
- /* Interface descriptor type */
( t% p. Y; L* | - 0x02, /* bInterfaceNumber: Number of Interface */
$ Y+ K' E; k& S5 `8 U - 0x00, /* bAlternateSetting: Alternate setting */
+ i4 A% F, L+ V8 o - 0x01, /* bNumEndpoints: One endpoints used */
; }+ Q& s: V: c- K% L) V! R - 0x02, /* bInterfaceClass: Communication Interface Class */
( n' ~; w' P6 [ - 0x02, /* bInterfaceSubClass: Abstract Control Model */
& m& u4 k, e6 n) V3 _8 X - 0x01, /* bInterfaceProtocol: Common AT commands */
0 a+ [$ `( i" R - 0x00, /* iInterface: */
- o+ ?' {' a2 G0 Z& ]6 J1 Y7 N
+ n! I D6 M/ |- // /*Header Functional Descriptor*/
; q/ L2 `4 o7 i9 j9 y# j - // 0x05, /* bLength: Endpoint Descriptor size */) Q/ a% ?7 z( f( R5 Y4 A
- // 0x24, /* bDescriptorType: CS_INTERFACE *// _( |% D6 N+ P
- // 0x00, /* bDescriptorSubtype: Header Func Desc */
8 l+ s( \8 {7 ?4 Y+ d& u, ?% r - // 0x10, /* bcdCDC: spec release number */
9 X9 I+ `( Q& T - // 0x01,
, s" y% i2 T5 j: t% H, x - 3 U0 E/ o1 g/ G0 z
- // /*Call Management Functional Descriptor*/2 ?5 o p% \+ E8 ?- b3 \
- // 0x05, /* bFunctionLength */
2 E6 U* V) d' ^/ z ^2 k7 h - // 0x24, /* bDescriptorType: CS_INTERFACE */' f8 m( e5 J7 m, \
- // 0x01, /* bDescriptorSubtype: Call Management Func Desc */
* E& I: f5 u% o. ?% W+ ?9 i, j - // 0x00, /* bmCapabilities: D0+D1 */
8 h( ^- h5 |) U0 G) v) _ - // 0x01, /* bDataInterface: 1 */
$ e& W9 E; {0 ]7 v- X' c2 W
: i$ q! S& r' v6 P# `- /*ACM Functional Descriptor*/' H! V9 W; P4 q2 g5 l7 J2 M
- 0x04, /* bFunctionLength */
# f" o* k) x, J3 [ - 0x24, /* bDescriptorType: CS_INTERFACE */
+ [3 P) {. t, [( ^% u! m7 \4 Z6 G - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
5 F! v6 m, j. G - 0x0F, /* bmCapabilities */
+ e& g# N1 L0 [, w) G# W( S1 ^
5 \- D6 n/ H- s& B4 i2 s- /*Union Functional Descriptor*/; {8 A) b* O+ U% ~ o: I3 [
- 0x05, /* bFunctionLength */" G2 J* y4 M: g+ c. E U
- 0x24, /* bDescriptorType: CS_INTERFACE */8 k0 V/ Y% a3 D/ @4 m* _: J
- 0x06, /* bDescriptorSubtype: Union func desc */
1 Q' B* A8 p1 `4 Z* }, e& {* R0 r - 0x02, /* bMasterInterface: Communication class interface */
& b# ~4 P( ?" q( J* F+ U+ ]& l - 0x03, /* bSlaveInterface0: Data Class Interface */* o6 d/ H$ ^1 j9 q, Z# h$ J2 n1 }
- : _2 J0 y; f3 n5 J F) r1 n
- // /*Endpoint 2 Descriptor*/
% f4 z, q, r. e7 p/ D8 X" c% V - 0x07, /* bLength: Endpoint Descriptor size */8 K' ?9 ^5 [" V, X% U5 j2 T
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
* R: S2 h- y8 J' T$ w4 H5 H ^ - CDC_CMD_EP1, /* bEndpointAddress */
/ k6 X* p! c k. { - 0x03, /* bmAttributes: Interrupt */' u% F# E( Z% U+ B1 W y& V
- LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
5 a, S4 o) H9 ~. [% e - HIBYTE(CDC_CMD_PACKET_SIZE),
. l& g4 P1 l& ^9 t - 0x10, /* bInterval: */
- s! G/ x3 |9 S$ j& F" K - /*---------------------------------------------------------------------------*/" X" b2 k8 D8 Z, j4 ~4 w
2 J! G3 ~: U- R* s: b: p, f- /*Data class interface descriptor*/
a4 C6 G0 x6 h5 z - 0x09, /* bLength: Endpoint Descriptor size */
6 q m" _! x W+ P/ g - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
" `0 q* A. ~# I6 B - 0x03, /* bInterfaceNumber: Number of Interface */
$ y* O5 D$ ?; |' G - 0x00, /* bAlternateSetting: Alternate setting */1 b! R1 B# X: }* z, A! U z
- 0x02, /* bNumEndpoints: Two endpoints used */
3 i1 L! H' z6 S) F - 0x0A, /* bInterfaceClass: CDC */3 i" x; U& `; h4 `) L
- 0x00, /* bInterfaceSubClass: */
+ c0 o1 k9 y, a6 @% S M - 0x00, /* bInterfaceProtocol: *// R$ }" L" n& d) y
- 0x00, /* iInterface: */3 X/ d- C8 I" e, S7 j% O3 N& _
- " m8 o$ y4 u0 o. Q7 b
- /*Endpoint OUT Descriptor*/4 N; }) v! D5 i1 y2 D
- 0x07, /* bLength: Endpoint Descriptor size */& D3 F8 G8 p+ x% [. x' } q* Z
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */; D" q ^8 a. Q8 W& |
- CDC_OUT_EP1, /* bEndpointAddress */( m0 z, ]9 m& `3 T; T$ ?, M8 p8 i
- 0x02, /* bmAttributes: Bulk */( {0 c" s: g l i
- LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */2 @, H! m( x+ k
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
7 M- ?( ?" E5 o, i8 m4 z - 0x00, /* bInterval: ignore for Bulk transfer */
3 }) h, u) q& ~: I- u - $ V4 P V! y6 y S
- /*Endpoint IN Descriptor*/
) K4 W: T1 t6 Y: \" _( D - 0x07, /* bLength: Endpoint Descriptor size */( W y# y& ]$ I5 [' K
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */1 `/ [4 N( M6 W; y6 h- t& T
- CDC_IN_EP1, /* bEndpointAddress */
+ \' U* B- w6 M; d2 F/ s: U: k3 E - 0x02, /* bmAttributes: Bulk */+ z: k5 |/ r3 u8 N, m
- LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */4 z w$ k% a& U' r
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
( q+ X& m, k! `; \ - 0x00, /* bInterval: ignore for Bulk transfer */
! H' t# H7 s4 V7 e: h7 s% M, ~ - /*---------------------------------------------------------------------------*/
: P L) R0 ^+ H% d - // IAD Interface Association Descriptor
2 @0 e- H3 p( F - // 0x08, // bLength: Interface Descriptor size( ^6 b3 o: _& i
- // 0x0B, // bDescriptorType: IAD
' d1 \. z5 ]! R2 S6 I - // 0x04, // bFirstInterface
& g! A1 C$ ~) c- n9 X) [, w - // 0x02, // bInterfaceCount8 G: O7 {; C' A3 x% f
- // 0x02, // bFunctionClass: CDC
# _/ ^2 z, ?: V' ~) t8 r - // 0x02, // bFunctionSubClass7 ^1 S7 i2 K4 u5 P- I! m
- // 0x01, // bFunctionProtocol $ o( x3 m+ H) X9 r
- // 0x02, // iFunction2 h1 N) W. ?6 a! ~1 |' N' E; q
$ @% _: _8 T& @# Q S+ j& u! r2 R- /*Interface Descriptor */+ B, ]; D) }9 A1 g2 E/ ?
- 0x09, /* bLength: Interface Descriptor size */7 ~% R W4 J8 P" {) R
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */2 }: N' L# M& z& t& \5 r
- /* Interface descriptor type */
0 B; J" W2 {2 R) E N4 ? - 0x04, /* bInterfaceNumber: Number of Interface */
# w# i) `" V; v - 0x00, /* bAlternateSetting: Alternate setting */9 e8 L- C6 h8 K5 O/ ^4 b
- 0x01, /* bNumEndpoints: One endpoints used */
1 B6 {6 T5 X, t6 f - 0x02, /* bInterfaceClass: Communication Interface Class */
) m8 N6 U2 t4 g* q- E - 0x02, /* bInterfaceSubClass: Abstract Control Model */
( f5 ~* Y: g5 s; R3 O; n7 N) y | - 0x01, /* bInterfaceProtocol: Common AT commands */1 |# m% M4 f2 J
- 0x00, /* iInterface: */ z4 ?5 K# z- I" ^
. `7 P+ i% O& H& m9 ?- // /*Header Functional Descriptor*/0 `! _; N- K8 t+ v
- // 0x05, /* bLength: Endpoint Descriptor size */ m& M b9 X% K: C! @% ~( v! k
- // 0x24, /* bDescriptorType: CS_INTERFACE */. L6 K8 G4 K, s0 {$ e9 j0 r$ N
- // 0x00, /* bDescriptorSubtype: Header Func Desc */
% `% } N6 B9 s: i; o9 b8 q - // 0x10, /* bcdCDC: spec release number */
* s3 V/ o/ e9 {( x" e - // 0x01,
7 F& s* L- n7 ~. m+ s- i& b% d - " ^' {' {* H# |: D, |) u
- // /*Call Management Functional Descriptor*/' |4 ]8 f- j s Q! D: D
- // 0x05, /* bFunctionLength */
+ l" ^0 g, c" S9 J. q7 @( u% M: q - // 0x24, /* bDescriptorType: CS_INTERFACE */
f$ Q2 [, Z$ M" y - // 0x01, /* bDescriptorSubtype: Call Management Func Desc */
( L# T' ~- ^" z( i( i3 h- L - // 0x00, /* bmCapabilities: D0+D1 */
# F8 R( `; R1 [: T u - // 0x01, /* bDataInterface: 1 */ }4 f5 g5 d: v, Q& P
$ t+ v. S' F1 @- A+ o- /*ACM Functional Descriptor*/+ B; N: x2 P1 u1 u( N" V- i
- 0x04, /* bFunctionLength */8 i/ f; k4 `/ p: { m8 Z9 ~
- 0x24, /* bDescriptorType: CS_INTERFACE */
7 X* `* b8 T$ B - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
4 I& |( G# i3 D8 ?% Z( C1 t - 0x0F, /* bmCapabilities */
7 l1 q b/ g: d; }6 G; ~ - 3 ^5 V/ W% N& U E8 B" u2 m
- /*Union Functional Descriptor*/% T) o) ]# L% E) {7 m
- 0x05, /* bFunctionLength */0 q/ c, |8 ?! t8 r7 k6 \6 G6 y0 C
- 0x24, /* bDescriptorType: CS_INTERFACE */* N( |* f. _7 \! } ]1 ]9 X8 U' H
- 0x06, /* bDescriptorSubtype: Union func desc */" r7 d* W d& {' d' e2 n
- 0x04, /* bMasterInterface: Communication class interface */
# ?2 W; i0 L' n, a4 a* \ - 0x05, /* bSlaveInterface0: Data Class Interface */
k: M5 T5 N8 d0 W& } - 5 s; I& X/ o6 L3 a9 J
- // /*Endpoint 2 Descriptor*/
o; }% d' Z/ }; b0 q - 0x07, /* bLength: Endpoint Descriptor size *// n! P. r) d# j3 |5 d
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
% i- N) r' v( T+ S: _ - CDC_CMD_EP2, /* bEndpointAddress */9 P+ y; o, {2 c/ ?* b8 p
- 0x03, /* bmAttributes: Interrupt */
) H( \* `7 t: |- V - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
, l. A! G6 c! |# ?9 y f+ f - HIBYTE(CDC_CMD_PACKET_SIZE),# A0 @# Q( b" D- H, Q
- 0x10, /* bInterval: */ 4 ~* d ]& {* q2 v3 P- ?
- /*---------------------------------------------------------------------------*/
5 R* `0 T* Q a* L; a4 N# G
O, I) d% L! D5 ^- /*Data class interface descriptor*/* k8 E" u0 f1 N' Q4 `7 }4 t0 T, }
- 0x09, /* bLength: Endpoint Descriptor size */
% n7 [, T0 `5 G% ~: ^( a - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
: v) s* m h6 v ?2 e. G8 D - 0x05, /* bInterfaceNumber: Number of Interface */6 }% E, L! `. S# {$ G1 B
- 0x00, /* bAlternateSetting: Alternate setting */
3 @# d+ _9 C7 c6 ` - 0x02, /* bNumEndpoints: Two endpoints used */
; U& N0 a+ W" U( u - 0x0A, /* bInterfaceClass: CDC */" l8 L6 ^1 |$ Y$ g( L+ b
- 0x00, /* bInterfaceSubClass: */
, U& ] o; G+ U# z6 E( M - 0x00, /* bInterfaceProtocol: */( a6 ?) Y q6 @; D! B6 b5 v
- 0x00, /* iInterface: */
" D! e! [: S2 d1 a4 A( t - / K% G$ G; N$ J
- /*Endpoint OUT Descriptor*/0 p! y" g( A( o j
- 0x07, /* bLength: Endpoint Descriptor size */* h( r4 k0 d. O5 i5 y- E. i" W
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
7 v2 {/ n1 R% H7 X - CDC_OUT_EP2, /* bEndpointAddress */3 b! B0 m a1 R" ~* \5 m* \7 s
- 0x02, /* bmAttributes: Bulk */
+ o( R) P8 u7 i& g) A: @ - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */! I: i$ l# m% y9 B) f4 F
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), U6 \" h, R; k+ b8 a
- 0x00, /* bInterval: ignore for Bulk transfer */) x9 e5 s! X; h1 |/ c' ?* S; ]
; Z8 d3 D0 @; T) y% w4 \- /*Endpoint IN Descriptor*/
7 ~) ?3 b: a6 H8 d) J - 0x07, /* bLength: Endpoint Descriptor size */
: O5 p% M# w g& Y - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
/ K! Y+ d+ z% m8 ] - CDC_IN_EP2, /* bEndpointAddress */3 p8 b, k$ z. P( O {( A0 }% k
- 0x02, /* bmAttributes: Bulk */
% `% {1 `8 s7 d$ \5 U - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */) S( l* p' X) _, S" q+ |% l
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),0 `& z* f7 V7 m$ p
- 0x00, /* bInterval: ignore for Bulk transfer */
5 u4 r& e5 K' I- ?+ `; G5 o- ~
4 {: r: S# ?) K2 E# b- /*---------------------------------------------------------------------------*/
$ m# x N9 \8 t! w - // IAD Interface Association Descriptor
' I4 [: q, Z. f9 ~. G7 Y2 e - // 0x08, // bLength: Interface Descriptor size1 }! {$ G3 e6 J. \( O$ Y( q' U- t
- // 0x0B, // bDescriptorType: IAD8 g' |7 E& J. ^
- // 0x06, // bFirstInterface/ D! q' v$ _. C7 ?3 Y
- // 0x02, // bInterfaceCount
! ^/ z$ Q" S$ t$ S$ ~( _. K: H - // 0x02, // bFunctionClass: CDC7 U9 l6 J1 [9 }- M- E2 t+ U& E
- // 0x02, // bFunctionSubClass
5 c! r: p$ t Y' z% q - // 0x01, // bFunctionProtocol ( U) g% v2 A# l: }* l1 M4 \9 d. f
- // 0x02, // iFunction# Y& c) }& W" S& e" `: g" }
- $ }/ K7 L( a9 t' d9 ^! w8 \' @
- /*Interface Descriptor */
3 L8 A9 r, U& b - 0x09, /* bLength: Interface Descriptor size */4 F8 {: v. r3 r7 G$ }7 ]3 d
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */% U: |' `; [" E# [ N) G
- /* Interface descriptor type */
" I/ _. t# }/ ^( I; w2 }' ^ - 0x06, /* bInterfaceNumber: Number of Interface */# O# R `7 V+ q; f
- 0x00, /* bAlternateSetting: Alternate setting */
) [6 U- z9 K2 C6 o6 d ~6 @ - 0x01, /* bNumEndpoints: One endpoints used */
7 i! r; ?/ \/ v4 S- L - 0x02, /* bInterfaceClass: Communication Interface Class */ H6 H0 U R# i8 B
- 0x02, /* bInterfaceSubClass: Abstract Control Model */
# m0 A% @5 j' S - 0x01, /* bInterfaceProtocol: Common AT commands */6 B7 K$ [' D, A; U- W
- 0x00, /* iInterface: */% O( f) n+ j5 L4 m2 \. [
- ; v( `2 U V) R3 D
- // /*Header Functional Descriptor*/) [5 |; R! I& l/ X, ~
- // 0x05, /* bLength: Endpoint Descriptor size */ E( w( w/ |6 w& T# P7 f( K
- // 0x24, /* bDescriptorType: CS_INTERFACE */* _' e% p5 z* o. C0 f" u
- // 0x00, /* bDescriptorSubtype: Header Func Desc */8 n8 L& ?9 j- O' |7 B/ t& V5 W. N
- // 0x10, /* bcdCDC: spec release number */# F8 j9 K+ }6 @, L7 H
- // 0x01,7 ? e6 S' E) n& |
+ p. V6 N% h0 D2 K) o- // /*Call Management Functional Descriptor*/
( h! A' G* z9 R$ O1 }! w - // 0x05, /* bFunctionLength */: [9 n* J% F) ~* X
- // 0x24, /* bDescriptorType: CS_INTERFACE */; V6 q$ h$ P' O; B& T
- // 0x01, /* bDescriptorSubtype: Call Management Func Desc */7 ?7 O0 M! i' Y t/ V) d
- // 0x00, /* bmCapabilities: D0+D1 */
4 U( y* @4 x D) }0 j) J u* F - // 0x01, /* bDataInterface: 1 */8 K3 ? P; g# r* E
- ; C/ c. ]( Y* l- } m( M% X; S
- /*ACM Functional Descriptor*/% i+ }3 P( K0 S+ ~! z
- 0x04, /* bFunctionLength */8 D2 e* F+ O5 Q. Y' T. m @
- 0x24, /* bDescriptorType: CS_INTERFACE */( q# O8 \9 v# V& v8 e7 L, L
- 0x02, /* bDescriptorSubtype: Abstract Control Management desc */
* e% }( X: a' b/ z8 F; S4 ~) K - 0x0F, /* bmCapabilities */
* o9 Y9 L& @( C* ]
' {+ p1 o) s4 |" m1 l- /*Union Functional Descriptor*/
" a$ H5 \* k5 o" F0 ?$ R - 0x05, /* bFunctionLength */ ^4 d- @+ W& u8 J" {( Y+ M2 d0 J( D3 G
- 0x24, /* bDescriptorType: CS_INTERFACE */
8 j! T. u6 J! S4 B3 j. ? - 0x06, /* bDescriptorSubtype: Union func desc */
# g( a* F2 C; E J& V7 i* D ? - 0x06, /* bMasterInterface: Communication class interface */7 g, ^9 i% i" _% q
- 0x07, /* bSlaveInterface0: Data Class Interface */0 c5 z" ]. ?6 ^1 u) Q. f7 e
- ; G7 u, L. I* x( Z1 s* `
- /*Endpoint 2 Descriptor*/# v& I2 Q+ g0 }. \8 o
- 0x07, /* bLength: Endpoint Descriptor size */8 ^* c* i( O+ \8 Q
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */& r- ]) w( v% e2 Y( P2 ]0 d
- CDC_CMD_EP3, /* bEndpointAddress */
( @ e: h- e9 [5 h - 0x03, /* bmAttributes: Interrupt */. Y! \2 J* ^1 S( e" p
- LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */, D+ H# V/ A8 P* y. T
- HIBYTE(CDC_CMD_PACKET_SIZE),: C, W# ]! W& H+ c% w! S8 V
- 0x10, /* bInterval: */
4 a$ @: { v& V2 b0 @3 r - /*---------------------------------------------------------------------------*/2 d, `9 _* Q% R- O' `, D
- t$ Y7 q( s) E, P) ^5 {
- /*Data class interface descriptor*/
- [, ]. N; ^% j3 @& i. q - 0x09, /* bLength: Endpoint Descriptor size */( }6 N2 D% g- J4 g$ w R; r% E9 M
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
& d+ x4 ~1 U0 w4 R6 Y5 ~% {) t - 0x07, /* bInterfaceNumber: Number of Interface */" f( [0 O! [$ a0 Q
- 0x00, /* bAlternateSetting: Alternate setting */
2 B7 K, F( r! v% I - 0x02, /* bNumEndpoints: Two endpoints used */; }, s0 Y" y9 }* @6 `7 T
- 0x0A, /* bInterfaceClass: CDC */7 a, V9 n# W/ e' K
- 0x00, /* bInterfaceSubClass: */
: q8 ?& l6 n+ _) Z - 0x00, /* bInterfaceProtocol: */" @" m! o! } V l5 d
- 0x00, /* iInterface: */
$ ]) i# W- Q( U1 }" @* W. }) w - 8 T4 ` I8 L" i! \% z3 ]' m
- /*Endpoint OUT Descriptor*/: o: d1 ?! i# z ~. d5 m
- 0x07, /* bLength: Endpoint Descriptor size */0 ?6 \2 H" s- j, \$ h2 J3 B
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
& O4 `/ s3 y& v1 A$ _ - CDC_OUT_EP3, /* bEndpointAddress */
- z2 M9 r# [7 F# r7 G& \- b# n - 0x02, /* bmAttributes: Bulk */
9 b2 X8 p- X1 Y" k - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */& K% a: j V' @$ R
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),+ a, ^; T' N4 J/ G
- 0x00, /* bInterval: ignore for Bulk transfer *// P" e% `: d: m7 w. z
- ; k/ M, I. {* l& E5 _ S
- /*Endpoint IN Descriptor*/
: Y5 U2 m5 Z' l- n v - 0x07, /* bLength: Endpoint Descriptor size */8 n0 Z6 i9 N4 ?. V$ j; _4 f
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
- k+ O# U1 P! x% }, J - CDC_IN_EP3, /* bEndpointAddress */
9 d$ M- H! N @ - 0x02, /* bmAttributes: Bulk */
3 Q; H3 a, G: j4 D U3 o0 a; M4 ~& M - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
! p0 \& B& H0 C: ^& R% X9 q' Q2 t - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
* W- v5 G& S( b. o! @0 e - 0x00, /* bInterval: ignore for Bulk transfer */9 f4 x$ P3 K2 L) b4 [; p
6 ^+ V8 N1 ^+ g% b7 w) ^- // /*---------------------------------------------------------------------------*/8 D6 d; G' C: u
- // // IAD Interface Association Descriptor
$ @8 H. X/ K+ T - // // 0x08, // bLength: Interface Descriptor size
' [2 W+ x% u4 g - // // 0x0B, // bDescriptorType: IAD# v# M; j4 e$ O, C( f
- // // 0x08, // bFirstInterface& P1 }' C' T6 p
- // // 0x02, // bInterfaceCount
( U+ W! l; e* `- I* \ - // // 0x02, // bFunctionClass: CDC* L; s+ D; y+ Y
- // // 0x02, // bFunctionSubClass
; l* _2 K' {3 _+ v: b$ Q' Q& L; J3 U - // // 0x01, // bFunctionProtocol
3 s# u8 @- A5 t0 x - // // 0x02, // iFunction
d) ? w( \. w( ] - 3 O7 C/ q& u+ Y: R: j
- /*Interface Descriptor */ ~) n& ]" p. r, T: Z- m! p0 }
- 0x09, /* bLength: Interface Descriptor size */
6 J2 o8 P/ B. ~ G - USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
0 ?$ o( n) T) ^! r; ~ - /* Interface descriptor type */1 E5 w6 g/ r; \* U( Y
- 0x08, /* bInterfaceNumber: Number of Interface */
0 B( g* d+ _3 {4 C* L. p - 0x00, /* bAlternateSetting: Alternate setting */
# z7 }. _* A1 S0 y6 K% D+ ^* C - 0x01, /* bNumEndpoints: One endpoints used */
2 S- F+ J% M% F5 e& A - 0x02, /* bInterfaceClass: Communication Interface Class */
2 n9 C* l4 ~+ y& V& M - 0x02, /* bInterfaceSubClass: Abstract Control Model *// P* C' V/ N6 m+ O! E
- 0x01, /* bInterfaceProtocol: Common AT commands */
% W6 N8 s7 r1 d, o; z2 U4 k - 0x00, /* iInterface: */
" [4 K" k6 z$ b
1 c# K! K& P) T7 n; w2 U- // /*Header Functional Descriptor*/
* a6 S, r( e) C( X; S( q2 O - // 0x05, /* bLength: Endpoint Descriptor size */
0 F0 N- B7 N, J& b - // 0x24, /* bDescriptorType: CS_INTERFACE */
( \& d! R1 d: g% M& h, X - // 0x00, /* bDescriptorSubtype: Header Func Desc */2 Q, M5 K4 x4 m5 O' s! I, ?! y
- // 0x10, /* bcdCDC: spec release number */
" H/ ^# {- j1 g1 { - // 0x01,
7 b! [- t/ x9 b% G; A9 }8 Y - 0 Z, b. o& e! w) o# a
- // /*Call Management Functional Descriptor*/4 r- w1 \: g- i9 h
- // 0x05, /* bFunctionLength */
6 q% z. ~; e% ~8 @" ~ z - // 0x24, /* bDescriptorType: CS_INTERFACE */4 R- o. @6 E6 P8 E# H8 D- u
- // 0x01, /* bDescriptorSubtype: Call Management Func Desc */3 G/ @. x# S- t0 k" f0 R2 d
- // 0x00, /* bmCapabilities: D0+D1 */
- T$ y" s7 N* T; ] - // 0x01, /* bDataInterface: 1 */0 N2 a0 L0 }6 A$ x/ S3 F, s* p
- 1 d1 Q$ Y/ i6 d$ H! @( K$ i k7 Q
- /*ACM Functional Descriptor*/
4 C2 r8 j9 e9 z* K - 0x04, /* bFunctionLength */
2 u- C9 ~. e- |+ A* k - 0x24, /* bDescriptorType: CS_INTERFACE */
3 g# Y2 K* r3 J2 Z; Z - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */( F3 Z3 S; z0 l2 N g; o; j6 i
- 0x0F, /* bmCapabilities */6 F7 Q8 v1 C& v: X
- ; [" g- n5 I+ p0 [
- /*Union Functional Descriptor*/, M# i6 \8 Q& j
- 0x05, /* bFunctionLength */
6 O: c8 F' a |; }2 Z( l/ Z - 0x24, /* bDescriptorType: CS_INTERFACE */
- O. P# [( l8 f - 0x06, /* bDescriptorSubtype: Union func desc */$ L& G4 f4 v6 J0 @1 p
- 0x08, /* bMasterInterface: Communication class interface */4 |5 `1 P& t A( j
- 0x09, /* bSlaveInterface0: Data Class Interface */" c7 r! l; ]# ~' w$ v5 {
- 7 ]! o5 f0 q8 v4 O0 K( d
- /*Endpoint 2 Descriptor*/0 W+ K9 a6 ?1 \7 o
- 0x07, /* bLength: Endpoint Descriptor size */
& J) c! _+ V x4 a4 ?6 Z* S4 R6 d& b( P - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
4 W( G, w' [: m% B8 ]( L - CDC_CMD_EP4, /* bEndpointAddress */
) N! t5 i' R: ]% H - 0x03, /* bmAttributes: Interrupt */
" h" u/ F4 F) P, _: a - LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
2 |, c- N, ~1 d1 |- _ - HIBYTE(CDC_CMD_PACKET_SIZE),/ D. S2 ^* O* d6 m' I
- 0x10, /* bInterval: */
* B; l) }/ C/ q6 ~4 w: ~ x - /*---------------------------------------------------------------------------*/
# j% V# S5 f1 @% i - /*
4 C- C* l" Q q1 r0 V4 n. b8 | - /*Data class interface descriptor*/
8 C1 t; A" p! ~1 I - 0x09, /* bLength: Endpoint Descriptor size */8 G4 e. x4 |( i* R
- USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
! T _$ k8 B% a) ]+ e" { - 0x09, /* bInterfaceNumber: Number of Interface */6 V% o2 n# q( l' N7 c! E
- 0x00, /* bAlternateSetting: Alternate setting */
j. |9 f. }7 K8 a' P" K - 0x02, /* bNumEndpoints: Two endpoints used */
* u0 S$ J+ [/ f1 i - 0x0A, /* bInterfaceClass: CDC */
6 Z( N8 A* X7 c: l5 E - 0x00, /* bInterfaceSubClass: */$ t; y$ ^) v0 U0 y8 |; d
- 0x00, /* bInterfaceProtocol: */" y7 x0 c# s; u* k+ M: G# b) N4 I6 f
- 0x00, /* iInterface: */7 Z+ ], v0 m' n
- . x `& n# Z- B" \
- /*Endpoint OUT Descriptor*/ Q$ u; p0 h+ ~ p3 n
- 0x07, /* bLength: Endpoint Descriptor size */
1 o7 e- g8 s% Q, F+ D( V - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
. T8 K! {: d9 H. W. S3 n; O- k - CDC_OUT_EP4, /* bEndpointAddress */
* q- L7 j" E' v' ? - 0x02, /* bmAttributes: Bulk */
$ G" ?' [3 ]/ D- P, d: e3 }! A - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */- b0 }( C0 G0 r1 C( Q: ]
- HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
# G: Q6 Q. X- Y - 0x00, /* bInterval: ignore for Bulk transfer */ D) t1 I, y3 V
. {: r: z: J, f3 L- /*Endpoint IN Descriptor*/
% \. w$ }, e- Z4 f% h - 0x07, /* bLength: Endpoint Descriptor size */
8 g/ q- U6 t B. y( c1 R - USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
' Z: r- `2 [0 E - CDC_IN_EP4, /* bEndpointAddress */
; [. x0 m3 [0 {0 o - 0x02, /* bmAttributes: Bulk */
. Y, f. o0 w+ l9 d) H- R - LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
4 O8 O- ~8 ~( v/ _( g+ O& y - HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE)," E+ M5 w4 {8 ]' [5 C2 p+ S8 J' I
- 0x00 /* bInterval: ignore for Bulk transfer */
$ t- A) B9 V6 C3 V0 E - }
复制代码 0 i. H' R& m$ D5 P; a
) c2 h s+ P+ h: n: |% k/ G
- 为什么上面有些描述符被注释掉了?
- 配置5个CDC如果描述符都写上了,这个结构体就超过了255个字节大小,超过了USB2.0最大配置描述符长度
- 在我的项目中,IAD和联合描述符(/Union Functional Descriptor/)功能一样,我这里注释IAD描述符,不会影响USB,但在windows平台下,它认的是IAD描述符,这个时候就可以注释联合描述符,打开IAD描述符,总之,省略一些非必要描述,减少长度
2 S. P8 T+ q. a s: }/ v - 这里的坑很多很多,需要很耐心,配错一个字段,千奇百怪的问题就来了
& N& D: E: A8 L; N) S9 C! Z
- D+ O! H$ t! g e& U 3.4 配置PMA---USB硬件缓存- 这里又有坑了,我把我知道的都说出
( H7 [6 w% v/ b 3.4.1 PMA是啥?- 此部分感谢一个大佬的帖子,理解来源与它
- 这个PMA的作用就是USB设备模块用来实现MCU与主机进行数据通信的一个专门的数据缓冲区,我们称之为USB硬件缓冲区。说得具体点就是USB模块把来自主机的数据接收进来后先放到PMA,然后再被拷贝到用户数据缓存区;或者MCU要发送到主机的数据,先从用户数据缓存区拷贝**MA,再通过USB模块负责发送给主机。
% y# i! x$ b* k % n U! O$ ?6 q: t# N7 K, J
6 p5 p3 P, ^9 f) |3.4.2 5个CDC的PMA怎么配置?- 啥也不说,先上代码 i$ k' h% ~1 r3 { x
# s8 D* e% O: g" s
! C. X) e. k3 U5 ^
- u_int16_t ep_addR=0x70; //起始分配地址: 这里是大坑 casojie
; }) V4 e- \4 G0 l/ i/ m P: ~+ F% F - u_int8_t ep_addr_size=64;* R o0 y: Y3 e% k$ [' B$ e0 g
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //此端点是用于USB枚举和基本的通信使用,默认就有,且不可省去# y# X' a4 N5 M @! E% s; B. I8 A
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
3 _/ ]# h; e/ z1 s1 J - /* USER CODE END EndPoint_Configuration */2 N' |4 y y, h* u! U3 `
- //CDC0 每个端点都分配了64B% Y. t% x" r% V2 @1 Y, s" i% B
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
. V8 u/ d* h1 P p$ Q. _5 f+ U - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
5 r7 [! }$ f6 P, }/ }
8 Y* q; E: A4 G- //CDC1 //+5
0 K. }9 X* C; j) \* ^: P7 J1 e - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP1, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //192 258
+ |) |) ]. H _2 g7 r8 X - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP1 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //272 2A8" X3 ^% J0 m/ L: W( g, P
- 9 S; m, W7 u" ]: E& @% t4 x+ @
- //CDC2( n+ m7 a5 Y1 R$ O' T: }4 d( F0 l
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP2 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //0x270
0 A/ |1 i4 Q( L c& v3 | l - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP2 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;//0x2C0
4 t3 O1 R7 }' `, O# B' b - " [5 ]9 Y. M; V! Q; ~
- //CDC31 _, r. P3 T4 U! v# S( g' z; J- U3 v
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP3, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //192 258 0x1E0
( i0 s3 z3 U8 ] - HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP3 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;6 X2 f: s j) B6 r) N8 `9 I; i
- / L: Q& G* }; m/ H/ u
- //CDC4 I. B; }: \4 A+ X2 c7 L
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP4, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; 3 a. t/ ~* N) M
- HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP4 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
复制代码
& D3 T) m: }; i5 D" D# C0 E0 e% J# j4 d, I
- PMA图(我理解的)
1 x# r8 R2 h" n
* |+ j4 [" B. e; V. N
- 在PMA的开头部分,是用于记录信息的,这些信息就是:端点缓存区的起始地址:说这简单点,里面写了端点0的缓存区的起始地址是X,端点1的缓冲区起始地址是Y等等
- 由此可见,当使用的端点数量比较多时,信息记录区索要的空间就比较大,反之,就小,需要动态调整
- 由大佬的帖子可知,记录一个端点的起始地址信息需要8字节,那么我们五个CDC,则5x2(IN,OUT)=10,再加上0x80 ,0x00端点,一共12个.则12*8=76字节
- 因此,端点(0x00)分配的地址需要往后偏移,默认的不行,如这次需要76字节的大小,换成16进制,0x4C,我设置了0x70>0x4C,默认的太小了,会导致部分信息记录区被端点0的数据覆盖,而导致部分端点无法使用.! E2 h% Z* W& B9 s; d
5 z. r1 F- q6 F& q3 c! v8 i0 o; R0 U
4.修改USB初始化代码,新增对新端点的初始化
0 A/ N* X' L$ a5 E" y0 N6 y& P
+ I1 O! c& j5 v4 F, @/ _: m- static uint8_t USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)# E" N. G, a# n1 {. v. F5 I: ]
- {$ M6 x, U) ~% b) F# y1 d* l/ m
- uint8_t ret = 0U;# _0 P3 M& u* C6 w
- USBD_CDC_HandleTypeDef *hcdc;
% N$ c( |' z2 f, \+ a
6 W9 M) B+ a- z9 ~0 \+ m. J" \- if (pdev->dev_speed == USBD_SPEED_HIGH)
% ?' {+ @! {9 I: k; T9 U - {" ~ |; [' m" p1 r/ d
- /* Open EP IN */
) l$ [$ l h- E6 D( _ - USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,4 H' B" E' n8 _
- CDC_DATA_HS_IN_PACKET_SIZE);
: M/ r' [& E( E8 N% s - ^$ s4 l# C0 w. ^8 V
- pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
+ ~( v }* C* u! B* O3 I, o! d6 V - 0 M! W; p+ ^( f7 R0 D
- /* Open EP OUT */
: O& N4 _: l6 M+ N, B - USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,7 j- R4 U% X- b( _* m! H/ ~
- CDC_DATA_HS_OUT_PACKET_SIZE);
4 l. z1 K/ y9 U - - K* @, P) b% _
- pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
- s8 f3 e6 K# `2 f& p( ]6 _ - ; ?% Y7 @: O* ^0 [" P! i
- }
- @. }, T, w0 f& ` - else
/ ?: o& g' y5 o: m( _+ p3 [- `' p1 q' i - {
" T5 Y; X: c3 J2 S5 j - /* Open EP IN */; }$ m9 F Z; v4 ~
- USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,
" C3 a4 @9 Q* }2 I - CDC_DATA_FS_IN_PACKET_SIZE);$ c1 P; U5 W. h* U
- 7 H1 n! a. w6 I/ @( W/ Z
- pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;
& z2 @! v* E6 l+ o3 E# Z( t - 8 D# J3 ^) U2 a
- /* Open EP OUT */
0 b, R( P9 T1 \8 A8 i' z2 a2 M! E6 C - USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,
# y' b4 I( a6 }. ]5 S& l/ D - CDC_DATA_FS_OUT_PACKET_SIZE);
. g( A$ |" e% Z - 0 R" }8 l7 A# g8 q# h. T
- pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
2 _" x2 H; n" j& [ - ) l' Z* J$ i, E0 k! J8 h1 A
- ) n$ B: {: V8 ?7 q5 e
- /* Open EP IN */
3 ~ w+ w6 y. R. s- A* t8 V0 r- z - USBD_LL_OpenEP(pdev, CDC_IN_EP1, USBD_EP_TYPE_BULK,4 j) n" o0 m5 q1 Y: t
- CDC_DATA_FS_IN_PACKET_SIZE);
1 {8 K5 ]; r" F5 A: S1 W" d
" |- [4 T: X" T4 A' ?. C- pdev->ep_in[CDC_IN_EP1 & 0xFU].is_used = 1U;
3 x, v3 S7 P; s) V
' D1 T& A5 r+ f- /* Open EP OUT */
$ X5 j. {& i, u4 j$ y - USBD_LL_OpenEP(pdev, CDC_OUT_EP1, USBD_EP_TYPE_BULK,/ z& \8 V# F8 M6 b/ o6 b. O. i
- CDC_DATA_FS_OUT_PACKET_SIZE);
: ]7 O- K1 H$ ~2 L' X7 X! H
3 R3 ~9 I5 t4 R% l7 [- pdev->ep_out[CDC_OUT_EP1 & 0xFU].is_used = 1U;
9 i: b0 f/ I- x8 l; K+ Q. A7 h! | - , z/ `& i: t2 w
- ' ]4 d+ d6 S0 w
& m# d9 y4 t( G5 V- //--------------------------------------------------------------------
* Z" I& E1 R! m, N$ P l - /* Open EP IN */
: w$ G* K! m* l& ^ - USBD_LL_OpenEP(pdev, CDC_IN_EP2, USBD_EP_TYPE_BULK,2 Z% R5 `" c/ d( p
- CDC_DATA_FS_IN_PACKET_SIZE);1 O7 z, Q& A: {& N, o* k! i
- 8 a* j# t: z$ `$ v( p! r. N* s
- pdev->ep_in[CDC_IN_EP2 & 0xFU].is_used = 1U;
! z j- `* m! N - , r$ h5 p% \# z* S, F& U2 l: K6 c
- /* Open EP OUT */2 g8 M/ F8 S4 V& x# U" n% {
- USBD_LL_OpenEP(pdev, CDC_OUT_EP2, USBD_EP_TYPE_BULK,
" A H; s5 e9 |# r+ r3 h) m$ [ - CDC_DATA_FS_OUT_PACKET_SIZE);
+ Q N3 ?$ B, ~, i9 n, j1 c/ V q - 2 N2 z4 B6 ~' z0 f6 m% {
- pdev->ep_out[CDC_OUT_EP2 & 0xFU].is_used = 1U;
0 C5 o# d8 j! x( N7 |. c - , P! ^8 R- P1 r& f; T+ ^3 y
- n& P( M. w( G2 o- //-------------------------5---------------------# ? b1 C# G# ~2 H2 p1 n* I
- /* Open EP IN */, b1 M1 w9 ]+ M, _- F
- USBD_LL_OpenEP(pdev, CDC_IN_EP3, USBD_EP_TYPE_BULK,, b) h( v. z& R# P
- CDC_DATA_FS_IN_PACKET_SIZE);! W$ E' t( H# n
8 {2 o& i# m1 T- pdev->ep_in[CDC_IN_EP3 & 0xFU].is_used = 1U;! d) b) `8 [4 e {$ z( J7 ]
- 5 U/ E6 ~3 `0 Z& E; y
- /* Open EP OUT */) L9 Y/ X j& P/ L* K) \- h, S
- USBD_LL_OpenEP(pdev, CDC_OUT_EP3, USBD_EP_TYPE_BULK,1 m& j1 C; q4 v! v$ |
- CDC_DATA_FS_OUT_PACKET_SIZE);
' O2 `) y" Y' P3 t9 N9 g - 6 A3 T% U$ c/ _6 c
- pdev->ep_out[CDC_OUT_EP3 & 0xFU].is_used = 1U;0 o$ W. q+ S$ k7 d0 ?" C" t
- ! D N# F/ m& ?4 s- \' p! Y, ]
- //-------------------------5---------------------
; ~6 u& H: Q- C7 H. I+ N' l1 Q6 E( [ - ( S, A& P0 y$ w$ B3 a
- /* Open EP IN */
7 p0 [3 U/ H a8 {& g - USBD_LL_OpenEP(pdev, CDC_IN_EP4, USBD_EP_TYPE_BULK,
5 b) \3 D" s* `* i7 I L - CDC_DATA_FS_IN_PACKET_SIZE);
# q8 _ w, P6 ^9 b - 9 B+ d% E. o+ |0 l( Z# V! ? }6 e& e3 ]
- pdev->ep_in[CDC_IN_EP4 & 0xFU].is_used = 1U;
6 W3 L' K# P! w
. B1 C2 C5 ~2 Z, {6 X; {- /* Open EP OUT */" G5 r$ h2 n$ ?. G: U/ [7 x, U$ E
- USBD_LL_OpenEP(pdev, CDC_OUT_EP4, USBD_EP_TYPE_BULK,# e/ _! _4 N7 D6 }
- CDC_DATA_FS_OUT_PACKET_SIZE);/ R- B* A2 H0 f8 s3 m% F
- * N/ y% |" v" A
- pdev->ep_out[CDC_OUT_EP4 & 0xFU].is_used = 1U;
$ [! r! G# L$ d6 A R6 d) {
: P, v8 L* G8 d- `& w5 I5 [: B, v- }+ X" y" C2 S" {7 K5 q' w6 j, ^5 S$ q
- /* Open Command IN EP *///控制端口无效,不要取消注释
4 R" N+ m. q( h; ?; S - // USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);; X: y8 f- R) i% E
- // pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U; d4 ~! M& l2 `4 M3 U
- # X( E$ p, X% s3 {
) h" E2 u+ g/ h- // USBD_LL_OpenEP(pdev, CDC_CMD_EP1, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
9 Z* k3 h! ~! N1 E. q6 q3 r; S: H - // pdev->ep_in[CDC_CMD_EP1 & 0xFU].is_used = 1U;# @: r. e6 R8 H5 X) {/ u
; t1 Z% T+ l _+ K
0 x# }9 z2 c4 K1 }9 x' N& L) Y- // USBD_LL_OpenEP(pdev, CDC_CMD_EP2, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
, d9 H. W2 u6 H8 G) Z/ | - // pdev->ep_in[CDC_CMD_EP2 & 0xFU].is_used = 1U;
! L& L6 p5 M) E - # I. V# o( W. [# y5 Y
- % _" K& ]; E( b8 p
- // USBD_LL_OpenEP(pdev, CDC_CMD_EP3, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);8 C" {3 ^" E! M( p e1 z
- // pdev->ep_in[CDC_CMD_EP3 & 0xFU].is_used = 1U;
. L3 T9 l) X4 H - 8 _: \; h" G( A" t: S: f, d) T
- pdev->pClassData = USBD_malloc(sizeof(USBD_CDC_HandleTypeDef));
+ s% R: r8 l* I; [8 C; E$ C: t' ~ - , D* l7 D6 J' C) r8 q3 H' Z" e
- if (pdev->pClassData == NULL) q. u, R3 X( Z% B) X( N- P+ S
- {
: l+ Z( H3 i5 F/ l$ p( \' Z' f - ret = 1U;5 B2 B# V# _0 v
- }$ u2 \0 X$ {5 J0 m) m4 s
- else* H3 D% ]; t; Z O7 x
- {
4 ~: l0 q% P" g' V( ] - hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;0 k9 d' r0 U" p
5 }9 l% u, [, v/ p& I- /* Init physical Interface components */
- P$ Z0 _- \- C4 S$ Y' m+ U - ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();% X+ F/ v7 P$ F4 Z- `1 U, _& C- M; c
- 3 u5 N& q! n5 ~
- /* Init Xfer states */
* \( Q. A3 i. e8 L/ H - hcdc->TxState = 0U;
/ D* ~% g& O! c' p* u; g - hcdc->RxState = 0U;: p# m6 n d3 J9 s& @0 f ^
, c& w/ c, ]5 E( d2 r3 Z/ ?- if (pdev->dev_speed == USBD_SPEED_HIGH)
7 U* W. P$ _3 o9 T - {/ k) o& ?( N" R/ y$ R1 r _2 v
- /* Prepare Out endpoint to receive next packet */
4 @* Q' ^! i* `9 G! k$ i, [1 j8 S - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,
# u" I6 [# z/ Z8 Q( }7 l. Z - CDC_DATA_HS_OUT_PACKET_SIZE);
2 X9 D" @& N0 B0 @ - }
! l3 z; C% n0 p% q5 J$ u5 u' J - else1 @& m) I8 J3 K3 }2 K- B5 Y
- {' r( F( i. B6 w1 s
- /* Prepare Out endpoint to receive next packet */
( m, L; a0 k( H" i7 S - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,) k( J! ^, d' V* _3 v+ [# Y2 w
- CDC_DATA_FS_OUT_PACKET_SIZE);
6 H0 W! H3 E. i - / ^) y$ T2 z. j) G: S
- /* Prepare Out endpoint to receive next packet */' v0 O1 p* K$ n$ e% M* A
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP1, hcdc->RxBuffer,
; W4 y! [5 A7 T' b8 b - CDC_DATA_FS_OUT_PACKET_SIZE);: N2 V( m+ `' w& r6 r% A
. d0 q: x# g9 k% j1 ^- /* Prepare Out endpoint to receive next packet */( o. J1 {5 `; G* s4 C$ o
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP2, hcdc->RxBuffer," s% n* U C# }3 A+ S, {
- CDC_DATA_FS_OUT_PACKET_SIZE);
+ d/ T( G' ~3 l/ L8 z. P& a9 J
0 I% S6 v9 s5 Z# C, j8 c- /* Prepare Out endpoint to receive next packet */, T2 {# i" t- x: j! V
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP3, hcdc->RxBuffer,) ~0 g5 G5 |' l* x6 z
- CDC_DATA_FS_OUT_PACKET_SIZE);
% J9 n1 L1 S8 v V
) l4 C9 n* |& Y. ^6 q! \! r- /* Prepare Out endpoint to receive next packet */
; D6 g: w h; X; X5 Q+ M - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP4, hcdc->RxBuffer,
! u( `0 B0 a' j! q/ R# c# y, R - CDC_DATA_FS_OUT_PACKET_SIZE);
' _ W! V4 E6 C7 }) ~' }" q! Z5 r - & U* b$ g& x+ s t
- USBD_LL_PrepareReceive(pdev, CDC_OUT_EP5, hcdc->RxBuffer,
+ V: k8 E8 ~4 q. p/ f5 ^9 h - CDC_DATA_FS_OUT_PACKET_SIZE);- m8 ]* c4 J' D0 I; N1 d. U4 M' r
- }+ c* m' V. ?8 a
- }
' K) K* G3 Z0 v' Z1 f# G - return ret;
- X( \: y8 m! q9 x) m( s% P - }
复制代码
$ d5 W5 c2 s( p2 `; {6 y3 f. B& c( I: g) S. ^0 C* I
5.修改HAL默认USB CDC相关接口函数- 现在是多CDC的状况了,但默认的HAL库的函数均只是针对一个CDC的情况,我们需要将端口的参数引出来
- USBD_CDC_DataOut:USB接收函数回调,修改提供端口参数
- CDC_Receive_FS(uint8_t *Buf, uint32_t *Len):USB CDC接收函数
- CDC_Transmit_FS(uint8_t* Buf, uint16_t Len):USB CDC发送函数
- USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
- USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
+ X9 w. @1 O/ }* I+ N- M: g f
- 先说说这几个函数的关系:CDC_Transmit_FS---调用--->USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
- USBD_CDC_DataOut(数据接收回调)---调用--->CDC_Receive_FS
6 f: h3 D) u _& V. f! X( ?
CDC_Receive_FS(uint8_t *Buf, uint32_t *Len)修改为CDC_Receive_FS(uint8_t* Buf, uint32_t *Len,uint8_t epnum): 此后所有OUT端点来的数据都将进入此函数,可通过参数epnum区分 % [- K' H; i) [* E
- static uint8_t USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)9 B* J5 ^: h5 K" z. u7 N8 M5 N
- {
4 z7 i$ \5 h/ \- Q& V% j+ I# _4 d - USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;
$ W! Z2 _4 j' f7 f3 c; U
; X9 a/ V: @9 R- /* Get the received data length */
6 q9 t' P8 ]$ V: l9 d9 j4 @ - hcdc->RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
7 \# Y4 _/ g3 N: o - /* USB data will be immediately processed, this allow next USB traffic being% U: ] o# J, `5 k# z8 d" X
- NAKed till the end of the application Xfer *// `% h8 [* |- Q: N
- // printf("USBD_CDC_DataOut.1294:Len:%d :EP:%02X\n",hcdc->RxLength,epnum);
2 k( ? j2 a1 ?4 @! C, g/ }& L5 s - if (pdev->pClassData != NULL)! g1 H" x7 c. ?
- {' ^" I1 e) z3 o
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength,epnum);//此处修改,加入端点,相关的函数声明也跟这这样改' `& N5 L. [7 V5 B! H0 Q# N
- return USBD_OK;
( w& P9 z$ p) I6 c( Z - }
& P H# S3 s3 D; N' N: M - ) S7 f3 \- p2 z0 f: O# ?( f
- else
" P& h- z" u0 p - {
2 v7 |5 E3 ^% p/ A1 S' h" T - return USBD_FAIL;# w# M& |. M/ G# B! }
- }# x E. p8 @) l, _3 o# H
- }
复制代码
& l9 y4 i2 ^( {7 q
- CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)该为CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum):只是增加一个参数,函数体不用动9 c& F! r- ~1 w4 C) y
( A! f, |4 [+ d- E3 v$ s& `8 m J' ]/ U& O" L( C9 }' Q
- uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum)
/ {/ J& o- |$ i n; X- ^( \. S - {& D1 p% V v3 k. B
- uint8_t result = USBD_OK;
" ]5 Q$ k1 l6 w9 I+ ~) Q - /* USER CODE BEGIN 7 */- a V) r$ U' x6 ~ b0 E( U
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS_CDC.pClassData;
0 A6 C1 @7 v* P8 m - if (hcdc->TxState != 0){5 R% }9 t" y: m
- return USBD_BUSY;
% n+ t2 v9 r" D8 `8 j4 E - }" {+ L# I8 V# o( x. Z
- USBD_CDC_SetTxBuffer(&hUsbDeviceFS_CDC, Buf, Len);6 [! k/ |/ E6 k# i% {/ b' j. D% X7 V
- result = USBD_CDC_TransmitPacket(&hUsbDeviceFS_CDC,epnum); //将epnum的端点传到这个函数,这个函数也需要改
9 B" A- Y9 Q' W# P6 n- w+ ]% S - /* USER CODE END 7 */
! [- ?" W* V- ]; d: n# T2 x - return result;
8 G8 f" J2 T; _" A' _ - }
复制代码 7 F; t' v3 Z5 {% z$ L5 n
! I! c \6 s; x3 u
- USBD_CDC_TransmitPacket的修改* E: [# c- p* Z, e e
- uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev,uint8_t epnum)
. {5 U+ e7 I' v2 H3 k9 e - {4 h. B, d( _. C
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;% f+ q6 G- N q7 U3 q. ?3 G" _" z
' n. P' Y1 T0 _- if (pdev->pClassData != NULL)5 |( @ x! V5 t
- {
) `8 U, d* N& D& s5 P& w$ K - if (hcdc->TxState == 0U)' l" \8 k# G' u' M S+ v
- {
1 D- ~- C: x& U - /* Tx Transfer in progress */" y8 d6 `# L _' E& _2 {
- hcdc->TxState = 1U;+ [$ E/ S7 p4 P+ ^; ]
- " A( A' {/ ~3 L1 ]9 e5 t, c
- /* Update the packet total length */
/ P4 c5 y& Q" j - pdev->ep_in[epnum & 0xFU].total_length = hcdc->TxLength;//将原本的CDC_IN_EP更改为我们传入的端点
0 d% c$ N0 J: p$ ^: T+ |) Z, Y$ a - /* Transmit next packet */
/ ~( F3 j5 h, l5 `9 i - USBD_LL_Transmit(pdev, epnum, hcdc->TxBuffer,1 E* [8 B B/ _8 e0 ^
- (uint16_t)hcdc->TxLength);//此处也是' L3 Y& d+ P5 X4 O7 n0 o$ Z5 ^0 m, Q8 i
- + f" y% p' o- c' `
- return USBD_OK;( O2 p2 w2 \# a# w( a' R. y
- }
9 c9 T6 ?0 \9 X. L/ \6 { - else
$ z9 y5 V) ~# _& W( ^ - {* J! q6 }3 T( W4 \- L8 {
- return USBD_BUSY;
7 w( p+ v! b: o" M4 C - }. d% R8 m" {" r
- }7 S! l# L* @, i" @4 ^: ~$ _- S2 m5 |
- else
5 C# l0 R+ ?1 s5 v - {: H6 q9 i# R/ q9 U l1 P }3 O" Z
- return USBD_FAIL;% Q# s6 P- b" Q$ ~) {: m
- }
! Y8 a( W3 A0 A" h5 \9 c - }
复制代码
, I* m1 Y8 Z) k" J; j: i$ |6 L6 x5 J D4 r: \( V3 x7 t
该函数的作用:当端口接收一包数据后,需要执行此函数来接收下一包数据,简单的说:告诉主机我可以接收下一包数据了
% N- f8 G3 ]. a$ {1 @' U
- uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev,uint8_t epnum)
: N' F; L3 n. j5 |. h1 L( r; o - {$ V6 `/ T3 ^: ^' P0 X
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;- u2 f3 S+ s* T% f8 q9 i# Y- i
1 f; n- l+ y1 E- P1 i9 `- @- X- /* Suspend or Resume USB Out process */
' t! m' y d( {" `" ~& Y# e, y6 O0 O2 @ - if (pdev->pClassData != NULL)+ Z! f- ]6 h# I% R h, g! m3 Y
- {6 ]" X+ E: U& y1 W( Y1 d
- if (pdev->dev_speed == USBD_SPEED_HIGH)# O' Z$ E" Y' O& V0 k' Y, j
- {
! ^) W7 j+ t+ b* P5 y) m2 E - /* Prepare Out endpoint to receive next packet */
% G U7 K2 i) D+ Q) f8 X$ l$ ] - USBD_LL_PrepareReceive(pdev,4 V$ A8 A* l: z h
- CDC_OUT_EP,. H+ q/ O- {, O2 _6 f
- hcdc->RxBuffer,& j4 E# K; r) Z0 h- I* M
- CDC_DATA_HS_OUT_PACKET_SIZE);! Z7 O, G# Y4 x G9 p6 Y
- }
6 b$ e9 A: N0 p# A( N* c2 v; F6 p' { - else' J) j- R5 r. P z& `% p! c2 T& L& F
- {
4 ~4 N5 ]# E6 F4 G" ~0 J+ @ - /* Prepare Out endpoint to receive next packet */
+ w) C+ J6 H. |1 v- _; z* o% _ - USBD_LL_PrepareReceive(pdev,
) }& s+ t0 X; Z+ u5 f - epnum,
/ q( L% a$ [: x: c( \4 O - hcdc->RxBuffer," D! D) S7 m0 T% V! Q, O9 [2 X* f& a. z
- CDC_DATA_FS_OUT_PACKET_SIZE);
3 b; @$ D6 K5 o' c: v3 n: ^ - }
0 m+ C8 q9 y8 d% {. S7 J" c - return USBD_OK;9 k2 z4 C* H& R1 k
- }, n- v* o: \2 k- R! D
- else& J' O( |+ h, c4 m) c7 t' w
- {
& S1 }0 l# T5 ~1 v: a, D - return USBD_FAIL;' k! T* ^( m* B5 ~
- }
. @9 J' _7 ~+ L6 S6 w+ d+ C - }
复制代码
: y' H+ d9 O( O对以后而言,我们就使用CDC_Receive_FS(uint8_t* Buf, uint32_t *Len,uint8_t epnum)和CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum) 向CDCx发送数据,就填写CDCx的IN端口 * 接收CDCx数据时,CDC_Receive_FS函数会传入该数据来源(OUT)端口,就可知道哪个CDCx了 ! f& V4 f. ]% a5 p# W. g, a* F
6.后续- 此时就完成了,不过不排除有些深层的问题。
- 如:当五个CDC同时在Read时,其中一个close,有可能会导致其他四个都无法再Read出数据,需要重新Open,但在电脑的深度depin系统上并没有这个问题,在项目中的板子上就有,希望大佬们提供下线索。感激不尽 e5 J5 j0 `* u ^0 h. @* x1 ]
+ x# X6 t' U* x8 x3 Z( n. w/ W
+ y; K2 }3 C9 W* m' T/ R" h+ @) A转载自:casojie
! Z$ v! F y P4 }. P |