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