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