你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于STM32使用HAL库实现USB组合设备之多路CDC

[复制链接]
STMCU小助手 发布时间:2022-4-9 23:12
工程环境:
, g4 z. f" K. I  P3 HSTM32F103RC
0 c. c/ o1 e& N2 RSTM32CubeIDE 1.5.1+ R  |1 g8 X9 v0 L3 R1 k0 W
第一步:基础工程生成. _. ?( O2 W5 g8 Y
     首先先用STM32CUBEMX生成CDC工程,并测试通过没有问题后,就可以着手开始下一步的修改,如果你还不了解CDC虚拟串口,那么可以参考文章开头链接第一条说明里的博客内容。
* y* q6 l9 \; ]( O/ {) P$ a
  [% G1 ?( w: ~/ |第二步:USB设备描述符的修改; |: T0 `) q3 m$ l- T
这一步很简单的,就是修改usbd_desc.c中的设备描述符数组USBD_FS_DeviceDesc,将设备类型改为组合设备类型:
' n/ _' G  ^' i+ \1 D  J0 n1 W0 [; O
_Y05WQZKXE)EC2KO[BK]8I3.png
9 N% F3 \. @1 K- v9 s- s
7 x+ R) L% B% \6 H: y4 R第三步:修改PMA端点分布
: H0 i- k$ ~7 o
% ~5 A0 ?. Z2 F4 C }34}RD0%~S%TH9CW430~RZI.png 4 p+ n  S7 _8 N# o9 V) U
+ K: k# E( J3 a) Q- @+ [& E' P
然后进入usbd_conf.c文件中,找到USBD_LL_Init函数,修改PMA端点初始化:; ]% X! A* {: M! h* X
5 J6 j. [! X& ]* x. @4 V
}P%Q31}O8~0HCQJ(NO{27PN.png
' ?7 S8 G. [# ]7 `2 I3 S
9 ~9 ?/ B; S  H& ^3 y9 \; a说一下PMA为什么这么改,目前我们用到的端点有:
  Z4 `; s1 ?+ W# \' X: k0X80、0X00为USB所必须的端点
8 ?2 W; r+ s# _/ U0X81、0X01为CDC1的输入输出端点, ~5 C* M/ e( H' x! l
0X82、0X02为CDC2的输入输出端点
6 P' ?* m! A- T/ R1 {4 R0X83为CDC1的命令控制端点(0X03端点未使用,但是占用空间)1 z; E1 T7 u( s8 w
0X84为CDC2的命令控制端点(0X04端点未使用,但是占用空间)0 F5 L# e7 b( I* p
; f5 R- _* P$ c5 w0 B; X
所以一共10个端点,10x8=80字节,十六进制为0X50,所以端点的缓存地址就是从PMA偏移0X50地址处开始。
7 H- F" n  F$ l9 T7 \$ m  y3 C; \1 l* z2 G5 R. L0 C' ^
输入输出端点最大可配置为64字节的缓存,所以是自增0X40。
' J& S; j2 C2 v/ j8 c' E4 S# |# P2 M- m
  J) k5 z( b/ Y4 N命令端点的缓存数据大小是8字节缓存,自增16字节是因为光用到了输入端点,输出端点没用但是占用PMA空间,所以是自增0X10。0 e" l+ _4 Q& \- Q* u2 [2 V

" K2 h1 `0 f( z4 I如下图指示是8字节:
) z& P0 E' F: D; A# E* Z4 m* \! a4 p( h, T
20210427142334981.png 1 w/ S& _& c# K: }3 n

* Y  V+ ?# ^" D( n4 Q9 W接下修改端点初始化,找到USBD_CDC_Init函数,添加CDC2的端点初始化操作:4 P' q. N& W( N. Y3 \

7 K# T. |6 A; p
  1. static uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)0 M: [/ B2 c+ z3 y( z
  2. {
    0 W. \; ]& m9 Q& }9 H. Y8 z
  3.   uint8_t ret = 0U;" h; ^( G9 `; V1 S4 o( M
  4.   USBD_CDC_HandleTypeDef   *hcdc;
    0 H) R+ M4 y$ b" [0 R! f" x3 p
  5. 2 p, _7 _+ ]2 P$ f
  6.   if (pdev->dev_speed == USBD_SPEED_HIGH)! ?1 B; k+ O$ j8 J: o7 M
  7.   {6 K+ K& h5 _3 J
  8.     /* Open EP IN */
    ; z2 A' g9 l, i# S/ K6 E% i
  9.     USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,
    5 ~6 P" ]1 m0 \4 C" q
  10.                    CDC_DATA_HS_IN_PACKET_SIZE);
    ( _. v  w: j7 f( I7 F

  11. : F0 b8 Y; S& k& @) @: Z
  12.     pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;0 E; {, Z4 v6 a6 G  ^( N
  13.   s4 `  h: X& b
  14.     /* Open EP OUT */: E$ X- T5 B0 s0 o; O% Y% H. I
  15.     USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,  ?$ Y" a1 t; u; |
  16.                    CDC_DATA_HS_OUT_PACKET_SIZE);5 U1 Q  Y6 Z* p# t
  17. + t- G5 a+ g0 Q5 @6 a; i
  18.     pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;3 o9 [" T' |* _
  19. 2 h; r! b# d7 l0 x4 x! o
  20.   }9 Z. h9 {) k& r+ D" r/ m
  21.   else8 I9 X1 f) \( ]3 ~* I" v
  22.   {: G/ S& G% b5 M' z+ g
  23.     /* Open EP IN */8 h. h, ?4 @+ v2 M. p
  24.     USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,0 W8 x& X: k: p' l( H
  25.                    CDC_DATA_FS_IN_PACKET_SIZE);# `# g8 \8 ~- y7 D2 z$ ^$ m

  26. 9 k/ p4 k$ b+ s; W6 k$ x2 T
  27.     pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;, i: r6 k0 T: U6 n8 Q2 Z8 j8 L

  28. ( S" V& [8 E: h/ y' Q$ r
  29.     /* Open EP OUT */
    # c! G( C* @' t
  30.     USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,7 c" ^: G# j0 ?3 x! i7 d
  31.                    CDC_DATA_FS_OUT_PACKET_SIZE);
    ( a0 c; X) |: T* u0 F0 Q

  32. $ s" r3 W5 z, a. N3 k; Q( Q! ?/ D6 [
  33.     pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;
    & e& d0 t5 y5 z# V3 l3 Q" m" l
  34. ) E  n) w% G. S! h
  35.     / +++lakun
    . d' m. ^2 m* @4 S" c: i
  36.     /* Open EP IN */2 U* a' s5 }$ _* ?# V' |( h
  37.     USBD_LL_OpenEP(pdev, CDC2_IN_EP, USBD_EP_TYPE_BULK,
    ) ~+ w7 x+ ]# h* S$ L
  38.                    CDC_DATA_FS_IN_PACKET_SIZE);
    / H# Z5 [. M- p2 `3 d% x
  39. ' b7 G: }1 C8 r8 i
  40.     pdev->ep_in[CDC2_IN_EP & 0xFU].is_used = 1U;: [9 u4 A9 P  B$ m
  41. # Y* c0 m0 _1 L* h
  42.     /* Open EP OUT */
    2 _0 }7 E) p3 t3 C
  43.     USBD_LL_OpenEP(pdev, CDC2_OUT_EP, USBD_EP_TYPE_BULK,
    & M" p& ]+ \7 e  U/ F. F
  44.                    CDC_DATA_FS_OUT_PACKET_SIZE);( _7 |9 o- K2 N
  45. 2 Q& m7 y3 C1 M; x% j' m
  46.     pdev->ep_out[CDC2_OUT_EP & 0xFU].is_used = 1U;
    . V5 F" [1 j+ d! y  x( \
  47.   }' v" V( U' B. @2 i& c7 Q
  48.   /* Open Command IN EP */& I1 J% Q& f5 c  e
  49.   USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);) i* o7 o3 h# r  ^' G4 L9 k
  50.   pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
    & u* ?; r+ r% k# C* c$ l, A: z

  51. 0 f7 P+ x& D0 b+ D
  52.   / +++lakun - \/ L. T9 B6 L+ \" G6 s: Q8 \
  53.   /* Open Command IN EP */
    # p8 \# @, H8 g" }
  54.   USBD_LL_OpenEP(pdev, CDC2_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
    : p8 l# R3 O) V; r3 Z
  55.   pdev->ep_in[CDC2_CMD_EP & 0xFU].is_used = 1U;
    * w! L9 V) ~/ a5 S; L( R

  56. 6 M% f, a! L0 E8 t0 D. k1 Y8 W
  57.   pdev->pClassData = USBD_malloc(sizeof(USBD_CDC_HandleTypeDef));  V) a+ \1 F6 Z; P$ [
  58. $ g3 k! s! V6 N2 s1 ^
  59.   if (pdev->pClassData == NULL)
    $ ]  _$ P. r8 `- j: P2 P3 @; w# p
  60.   {* i5 w6 }/ o# ^& n4 u& h) v( V
  61.     ret = 1U;4 ^8 v4 v7 n% G6 k
  62.   }& w+ i+ V# D6 A+ C; Y, @- P
  63.   else2 e: ^  N% }# \' Y( z& m8 [- r
  64.   {
    : M( J; r9 @1 g% P, h" Y& F
  65.     hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;& v9 w  R) L* y8 |1 t) f
  66. . J. f+ K: ?* R
  67.     /* Init  physical Interface components */
    ! y: [: ~+ `2 K6 `
  68.     ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();" i! G1 A" a$ i* o; ?& r

  69. & @2 S  K2 O& m! |# [  C8 ?- F) B
  70.     /* Init Xfer states */! A5 ]9 e9 V* w' f6 l% v2 t2 A2 P3 ^$ M
  71.     hcdc->TxState = 0U;( K3 n: \3 ~  S6 K8 |6 Z1 U
  72.     hcdc->RxState = 0U;/ l; W: `4 V0 P- b* M

  73. 2 y$ q9 l/ H+ M- x' p/ ~
  74.     if (pdev->dev_speed == USBD_SPEED_HIGH)
    + }  V7 H, I. O1 W2 d0 A% r5 `
  75.     {
    * J3 M3 S" y$ L& z: I, d
  76.       /* Prepare Out endpoint to receive next packet */1 m5 }1 }" ]; d, a
  77.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,/ G, ?; j' u8 B1 ?% d9 N
  78.                              CDC_DATA_HS_OUT_PACKET_SIZE);& f. b4 d, C" \2 p
  79.     }
    . Q2 |1 i  O. o( u- d' r
  80.     else$ H; P. s. z' ~3 x
  81.     {3 o+ ?/ v2 U9 p4 y1 @$ h$ H' Y
  82.       /* Prepare Out endpoint to receive next packet */
    5 R6 O* F. j/ m2 `. a' i) I9 C
  83.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,
    : ?0 f9 h$ h# i: h
  84.                              CDC_DATA_FS_OUT_PACKET_SIZE);9 ]* E/ ^  \) f3 x+ R$ F
  85. ' w+ [! D! _) d) X/ X6 w+ A6 S
  86.       / +++lakun
    / J. S# w3 ], x' w3 G9 ?
  87.       /* Prepare Out endpoint to receive next packet */
    - A" }' Z' ]8 T' W
  88.       USBD_LL_PrepareReceive(pdev, CDC2_OUT_EP, hcdc->RxBuffer,
    : c3 u- o/ A$ r
  89.                              CDC_DATA_FS_OUT_PACKET_SIZE);* r) N; a2 P& Z# Z( v: r
  90.     }
    ( ~. a* G4 o/ R
  91.   }
    9 r6 u5 T: @$ m6 T7 y
  92.   return ret;
    ' J! r2 Y; G8 U% O
  93. }
    % A5 g5 |+ A* C2 c* L* e0 U
复制代码

4 M/ R/ ^, Q' `) W注:这一步骤的修改都非常挂关键,好多人组合设备修改出错的原因就是在修改PMA这里出的问题!在本文章起始处的蓝色链接《STM32 USB知识扫盲》文中有对PAM的详细讲解,一定要仔细看一下并理解!8 e6 h/ j6 \8 p
$ c) j" x7 h3 I2 |
第四步:修改配置描述符, `: |; N9 s7 ]9 R4 u8 S7 }: t
贴一下我修改好的两路CDC配置,修改过的地方都有+++lakun样的标记:
5 @9 F- A! ]) h7 M1 Z8 C  `1 M2 A% ]! ?& e
  1. /* USB CDC device Configuration Descriptor */
    4 a$ G) B5 U- n1 h- }. b# Z* e& T
  2. __ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =9 d2 I$ B" w3 j+ f" W: P# \: g
  3. {/ Q; M2 W* Q6 x
  4.   /*Configuration Descriptor*/# S$ M1 U0 w( ~, _1 P% b& W( C0 }
  5.   0x09,   /* bLength: Configuration Descriptor size */
    2 @5 ^, r' p+ R- t% N
  6.   USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration */
    * }, F) }7 C: o% L# m( u
  7.   USB_CDC_CONFIG_DESC_SIZ,                /* wTotalLength:no of returned bytes */
    ; ~4 I0 N1 e( C9 _4 z$ f; o
  8.   0x00,: L7 f8 v7 O) D4 |. w2 q- b
  9.   0x04,   /* bNumInterfaces: 4 interface */  /* +++lakun:一个CDC用到了连个接口,两个CDC就是4个接口 */' x2 B) z3 n& J% Q7 y9 N
  10.   0x01,   /* bConfigurationValue: Configuration value */
    / e4 C! Z* b  A- Y; v
  11.   0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
    % [: {1 E9 W$ K* n
  12.   0xC0,   /* bmAttributes: self powered */
    : X' p% L1 [9 [! V! {; \
  13.   0x32,   /* MaxPower 0 mA */& [. d  s, A  [
  14. ; y) l$ S4 O9 ^% A$ a
  15.   /*---------------------------------------------------------------------------*/* H1 `- O/ B* |- w! M
  16. . T4 N. b, o5 K6 S1 u5 t8 f
  17.   //
    % W3 z* T) f% P; `' z0 e
  18.   // +++lakun: IAD(Interface Association Descriptor)
    ' I" [. E* L' Q: x& w
  19.   //
    , q) |7 _% F& u" D5 c, T/ P
  20.   0X08,  // bLength: Interface Descriptor size,固定值% s) S% @! w, ~
  21.   0X0B,  // bDescriptorType: IAD,固定值
    " j& k9 E, a7 Q: D) i6 W1 o- c
  22.   0X00,  // bFirstInterface,第一个接口的起始序号
    # f0 d( e4 f7 K9 k, l3 f
  23.   0X02,  // bInterfaceCount,本IAD下的接口数量
    ' A6 W1 }$ i9 U
  24.   0X02,  // bFunctionClass: CDC,表明该IAD是一个CDC类型的设备3 M$ T! A) z/ R9 S* T7 e
  25.   0X02,  // bFunctionSubClass:子类型,默认即可
    + J! p) k3 |$ l0 [, M% h' H. u
  26.   0X01,  // bFunctionProtocol:控制协议,默认即可0 ]. Q! _& W+ t
  27.   0X02,  // iFunction
    % d8 O3 V( c! H$ w2 T

  28. 8 \% o" y* `' N+ g
  29.   /*Interface Descriptor */4 V, s' G6 m8 R
  30.   0x09,   /* bLength: Interface Descriptor size */6 T& m$ [$ i! ~% r% g5 z
  31.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
    % W: x' o/ _" Y  w$ y: x7 q  \
  32.   /* Interface descriptor type */: _, w& X1 i' }5 Q% M$ {& C3 x2 W1 C
  33.   0x00,   /* bInterfaceNumber: Number of Interface */                   /* +++lakun:接口编号,从0开始 */  {( D/ F' r# A1 p6 ?
  34.   0x00,   /* bAlternateSetting: Alternate setting */8 Q( e& G* d" F+ a, ~/ e
  35.   0x01,   /* bNumEndpoints: One endpoints used */% ~( a  K! p! O" [4 }+ l  O
  36.   0x02,   /* bInterfaceClass: Communication Interface Class */
    + u/ M8 C% C! t4 g8 \
  37.   0x02,   /* bInterfaceSubClass: Abstract Control Model */$ w8 C4 M* ~- H* w+ J
  38.   0x01,   /* bInterfaceProtocol: Common AT commands */# f; A4 ]) q3 [* x3 N- J
  39.   0x00,   /* iInterface: */9 z0 }* i9 e7 L2 W/ U
  40. & c3 e  O; G' T% Z6 T8 \. B
  41.   /*Header Functional Descriptor*/  \. S( T- v' h% o4 }9 H6 \
  42.   0x05,   /* bLength: Endpoint Descriptor size */
    4 e# F0 g, K' U9 p
  43.   0x24,   /* bDescriptorType: CS_INTERFACE */
    % I, I  V0 B! Y  }! ~7 e
  44.   0x00,   /* bDescriptorSubtype: Header Func Desc */
    % [6 }; J3 `7 H% g: S. j: g
  45.   0x10,   /* bcdCDC: spec release number */
    7 r7 C# U8 f7 g
  46.   0x01,
    5 X, X4 n4 F. h. t( N% D

  47. ( i. A7 G, Z5 j  f9 L7 X6 x& H! M
  48.   /*Call Management Functional Descriptor*// i3 [: P1 u# R6 M2 c3 M* R
  49.   0x05,   /* bFunctionLength */  H5 o; F" L2 d7 L# |
  50.   0x24,   /* bDescriptorType: CS_INTERFACE */
    7 B) D4 u" G: q2 _
  51.   0x01,   /* bDescriptorSubtype: Call Management Func Desc */9 B- S$ k6 n# x; h- }
  52.   0x00,   /* bmCapabilities: D0+D1 */
    3 X' S. h& K8 m) I
  53.   0x01,   /* bDataInterface: 1 */
    ; N7 }2 S8 x, O
  54. ! Z( N& b. I# Q0 R' R
  55.   /*ACM Functional Descriptor*/
    ' I# m- U: N: ~! q$ _% G1 T3 u
  56.   0x04,   /* bFunctionLength */5 n: r0 Z* _6 n
  57.   0x24,   /* bDescriptorType: CS_INTERFACE */
    $ d& x" d$ C6 Z) {2 l3 ~
  58.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */% N1 y( C# {$ v7 w
  59.   0x02,   /* bmCapabilities */7 `1 F. J6 Q0 F* x) j* f/ p3 ^  S- C
  60. : p2 h$ L, m: x" X
  61.   /*Union Functional Descriptor*/
    , y5 {+ m* T4 P
  62.   0x05,   /* bFunctionLength */
    " _! Z/ U8 R6 d' p! u
  63.   0x24,   /* bDescriptorType: CS_INTERFACE */7 f# N! @4 ^. g. _
  64.   0x06,   /* bDescriptorSubtype: Union func desc */
    & M6 P2 l9 X: A
  65.   0x00,   /* bMasterInterface: Communication class interface */                 /* +++lakun:这里指示的是本CDC的通信接口编号 */
    ' w6 {4 m% c& g1 b) j9 d- l! X
  66.   0x01,   /* bSlaveInterface0: Data Class Interface */                          /* +++lakun:这里指示的是本CDC的数据接口编号 */% o* [9 h: D! F+ F/ m" E
  67. 3 J, P4 A6 @3 Q. V
  68.   /*Endpoint 2 Descriptor*/; j, ^* t1 R4 C2 g/ Q' b) d
  69.   0x07,                           /* bLength: Endpoint Descriptor size */0 x9 Z3 y8 c4 M" U( z8 N; T
  70.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */: }, @' A& Y3 c
  71.   CDC_CMD_EP,                     /* bEndpointAddress */( \$ \* ^( j. K2 u4 x4 R
  72.   0x03,                           /* bmAttributes: Interrupt */
    ; y0 k8 ]" G4 w/ s" c" k
  73.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
    6 @0 V, |0 O( s7 x6 r2 V
  74.   HIBYTE(CDC_CMD_PACKET_SIZE),' u4 J# ^* w+ @0 Y
  75.   CDC_FS_BINTERVAL,                           /* bInterval: */
    " x, t# ~! W" Y$ l2 i
  76.   /*---------------------------------------------------------------------------*/
    3 T2 N+ e) S9 Z) Q0 ^+ N2 X

  77. ) S: f' ?: V7 V; f2 j
  78.   /*Data class interface descriptor*/
    " b  a8 @1 T/ j& z2 i4 a
  79.   0x09,   /* bLength: Endpoint Descriptor size */) X) q- x) Q/ T0 ~$ q
  80.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
    * o9 c4 G2 A# z3 M* V0 C1 Z
  81.   0x01,   /* bInterfaceNumber: Number of Interface */                          /* +++lakun:CDC1的数据接口编号 */: w5 Z! }$ g. u5 j* J% B
  82.   0x00,   /* bAlternateSetting: Alternate setting *// N3 {. q: v4 u$ T1 S
  83.   0x02,   /* bNumEndpoints: Two endpoints used */( \) u4 j9 v* ~" \/ _1 k
  84.   0x0A,   /* bInterfaceClass: CDC */
    - c. h3 a& ?, G2 ?  b! @$ p& A
  85.   0x00,   /* bInterfaceSubClass: */% G) n* k% P! t. w( U
  86.   0x00,   /* bInterfaceProtocol: */
    ) L6 a& x% ?& k
  87.   0x00,   /* iInterface: */' e# ]) ~: z! a! C$ B4 z6 L, x; A

  88. # c+ H, C4 p0 `$ r3 }2 H. m2 k1 F
  89.   /*Endpoint OUT Descriptor*/
    4 k4 q+ h. c( u) n% A7 n
  90.   0x07,   /* bLength: Endpoint Descriptor size */
    9 ^  \& E( m9 z/ r4 h
  91.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */  t$ H+ q- t  T! f# T
  92.   CDC_OUT_EP,                        /* bEndpointAddress */" C- i" l  b- k1 B6 M
  93.   0x02,                              /* bmAttributes: Bulk */
    ! A& g( N! [% R8 W" {& Y5 \* k
  94.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
    2 [. B9 g2 l, {+ t
  95.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),5 X! \; Q3 m+ `) d' \7 _& ^
  96.   0x00,                              /* bInterval: ignore for Bulk transfer */: n9 x5 Z' v. s/ U' H- v$ T1 e0 g

  97. , e, q0 Q# |" W) n& G- h: M
  98.   /*Endpoint IN Descriptor*/6 c8 J  F) T- _6 J' n! V
  99.   0x07,   /* bLength: Endpoint Descriptor size */
    2 f# y: z  K7 Q- k
  100.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
    * l/ M' v. T7 a' v& f7 S9 f  w
  101.   CDC_IN_EP,                         /* bEndpointAddress */
    / D0 c" J# V0 O, C
  102.   0x02,                              /* bmAttributes: Bulk */) v8 R6 l  o& d# r- B0 f, n& p- a
  103.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
    ' |) C9 p9 j- V, B* m6 v9 d: L& P
  104.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),% I1 `+ `" x0 g
  105.   0x00,                               /* bInterval: ignore for Bulk transfer */' c: c3 e2 ~, ~6 v% {
  106. 4 Z3 m; l& v2 k$ x! ?, h
  107. 1 ^7 U) e0 z2 c8 U& c4 H
  108.   //  e8 ?' ?8 K1 ~: [8 D1 @
  109.   // +++lakun: IAD(Interface Association Descriptor)* B- X) ^) V4 @( z
  110.   //
    ; F! I; Y( w% ?% N
  111.   0X08,  // bLength: Interface Descriptor size,固定值( z$ p4 m8 m$ E4 {3 y7 S' ]. W
  112.   0X0B,  // bDescriptorType: IAD,固定值; K  g- \$ D0 y6 b' `5 k! z' B
  113.   0X02,  // bFirstInterface,第一个接口的起始序号(第0、1编号的接口用于CDC1,现在是第二个CDC了,所以从2开始)& R) s. p4 p4 F& d
  114.   0X02,  // bInterfaceCount,本IAD下的接口数量$ ^9 ^& m- @* q* d6 R" o! V1 `
  115.   0X02,  // bFunctionClass: CDC,表明该IAD是一个CDC类型的设备
    ; J/ d& G" z2 r$ c* O
  116.   0X02,  // bFunctionSubClass:子类型,默认即可
    4 z# Z, G1 e3 i; E* z* [
  117.   0X01,  // bFunctionProtocol:控制协议,默认即可% a0 k) o2 D8 q
  118.   0X02,  // iFunction
    + A! k* g4 W; z) L0 W" Y0 D6 K: I

  119. / ]* ^1 L: ^! m8 m! V' ^$ o  ]& j/ j
  120.   /*Interface Descriptor */
    " t3 s: n. d, Y% B% ?( V# u
  121.   0x09,   /* bLength: Interface Descriptor size */- X- H- s1 D" y# }& }
  122.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
    + {: A1 q$ E; d
  123.   /* Interface descriptor type */, k4 W1 D9 ^3 G1 B7 T, |
  124.   0x02,   /* bInterfaceNumber: Number of Interface */ /* +++lakun:这里就是第二个CDC了,第0、1编号的接口给CDC1使用了,所以是2开始的 */
    . @. N' }' r9 {
  125.   0x00,   /* bAlternateSetting: Alternate setting */
    & A' N! x5 I6 D. E
  126.   0x01,   /* bNumEndpoints: One endpoints used */9 v2 w5 _, I# v
  127.   0x02,   /* bInterfaceClass: Communication Interface Class */+ j9 I' b2 P; O2 c9 D) e9 H
  128.   0x02,   /* bInterfaceSubClass: Abstract Control Model */0 ~. I: w; j+ d( }6 \# b; @
  129.   0x01,   /* bInterfaceProtocol: Common AT commands */' {' j  L5 Q2 {: g8 d  T; X
  130.   0x00,   /* iInterface: */, c. j: n! P3 i# ~) M0 B8 f  p
  131. - e$ K9 y$ m, N/ {! r
  132.   /*Header Functional Descriptor*/
    ) G& y. G3 f2 @
  133.   0x05,   /* bLength: Endpoint Descriptor size */0 Q3 F! f* e+ o. r; v
  134.   0x24,   /* bDescriptorType: CS_INTERFACE */( Y& o& d! \+ a! a+ W8 N( ]
  135.   0x00,   /* bDescriptorSubtype: Header Func Desc */9 P/ _% K- y8 t9 g! E' O' W8 E9 x6 h
  136.   0x10,   /* bcdCDC: spec release number */9 F9 P6 P  t; O; S/ ?. E8 F
  137.   0x01,
    % `+ j# n3 S& T' k" b
  138. ' x+ O" x2 N. a+ l7 ~) z
  139.   /*Call Management Functional Descriptor*/
    : x9 @6 W9 z+ z. V! J  F
  140.   0x05,   /* bFunctionLength */- w/ g! r! w7 e1 k" P7 Y
  141.   0x24,   /* bDescriptorType: CS_INTERFACE */
    . F6 j1 J3 D5 S& m2 I0 u  g
  142.   0x01,   /* bDescriptorSubtype: Call Management Func Desc */: P3 ~" u' t  g$ i. Y
  143.   0x00,   /* bmCapabilities: D0+D1 */
    % O# l& S/ P( A# O  K5 a
  144.   0x01,   /* bDataInterface: 1 */
    - O/ Y" F- o. }# p8 n! L0 [! V

  145. - z- k" o* L. s
  146.   /*ACM Functional Descriptor*/, r6 @% u6 t0 p# s* @
  147.   0x04,   /* bFunctionLength */
    * S9 V# n! S3 G# _% z# E3 t
  148.   0x24,   /* bDescriptorType: CS_INTERFACE */; `( _9 I! \5 l  z4 U0 F
  149.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
    # ~, ^+ }4 x8 [* e8 _9 \
  150.   0x02,   /* bmCapabilities */9 o3 S! [( d# C

  151. 9 B4 t% q3 a/ X
  152.   /*Union Functional Descriptor*/
    & `3 k- z9 g" [; Y/ k* X+ i
  153.   0x05,   /* bFunctionLength */
    7 A6 c* g1 Z/ E4 ?4 C
  154.   0x24,   /* bDescriptorType: CS_INTERFACE */
    + O' I2 g$ O+ I1 s) r6 K: y' b
  155.   0x06,   /* bDescriptorSubtype: Union func desc */
    $ U1 X$ ^# V  b9 h' ]- F" H
  156.   0x02,   /* bMasterInterface: Communication class interface */                    /* +++lakun:这里指示的是本CDC的通信接口编号 */; r; r9 k" [  L9 ~; l1 V
  157.   0x03,   /* bSlaveInterface0: Data Class Interface */                             /* +++lakun:这里指示的是本CDC的数据接口编号 */
    2 F9 l0 Y5 M; [1 a( V$ U2 g
  158. 8 A/ X/ r4 S# Y! g5 S
  159.   /*Endpoint 2 Descriptor*/& W$ q! }/ K9 A
  160.   0x07,                           /* bLength: Endpoint Descriptor size */( x& j3 B( G; |* N" ?4 a
  161.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */) w' a7 t. Q" k. }
  162.   CDC2_CMD_EP,                     /* bEndpointAddress */
    ' w% W9 _$ G/ ]
  163.   0x03,                           /* bmAttributes: Interrupt */
    8 ]- F5 D) `/ ^# h
  164.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
    & i0 P4 N0 S) `& H/ \0 C3 L5 U
  165.   HIBYTE(CDC_CMD_PACKET_SIZE),
    5 L5 I: l  V; J
  166.   CDC_FS_BINTERVAL,                           /* bInterval: */" n; C$ k7 U6 C$ ~% z' i: c
  167.   /*---------------------------------------------------------------------------*/
    4 }, V  ~4 b  C, {: g+ e" _4 v

  168. ; f# r  t3 J3 j! w
  169.   /*Data class interface descriptor*/7 A# ]  t" G" A5 Z& P" B- N+ R
  170.   0x09,   /* bLength: Endpoint Descriptor size */; n: o: h3 w) |  d$ @
  171.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */3 F0 I3 [% ]" V) c" U. W) ]& p
  172.   0x03,   /* bInterfaceNumber: Number of Interface */ /* +++lakun:CDC2的数据接口编号 */  M1 R; I' ~8 F, U2 B
  173.   0x00,   /* bAlternateSetting: Alternate setting */; q3 W0 j, _  f8 q8 X
  174.   0x02,   /* bNumEndpoints: Two endpoints used */* n  U( I( U% {3 ]
  175.   0x0A,   /* bInterfaceClass: CDC */
    8 I' c' u8 S7 Z( `- I! q' Q
  176.   0x00,   /* bInterfaceSubClass: */
      m# b, w, }( j2 n2 e" Q5 v+ ^; ]6 [
  177.   0x00,   /* bInterfaceProtocol: */% L& x7 w  Z# ]0 b7 c% z  {2 [
  178.   0x00,   /* iInterface: */
    9 I/ Y! _) Y4 D3 ]

  179. $ Q" }$ B  z1 Q, J8 n. m8 E
  180.   /*Endpoint OUT Descriptor*/
    7 h  W0 Z& N- A* H8 o: c) ^
  181.   0x07,   /* bLength: Endpoint Descriptor size */
    : ^9 V; d, U* e+ F( D$ O
  182.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */- b1 Z4 E9 Z8 J- K/ u; j
  183.   CDC2_OUT_EP,                        /* bEndpointAddress */
    3 X6 {3 G6 ]* A9 W0 N
  184.   0x02,                              /* bmAttributes: Bulk */1 c1 L/ o; n& ?1 x; @7 `6 ?
  185.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */9 V, {- ~% F- X/ c- Y1 Y6 T
  186.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),, V- ]; l" X4 |
  187.   0x00,                              /* bInterval: ignore for Bulk transfer */3 v- V5 C9 B  r
  188. & h% a( w& K: T0 M
  189.   /*Endpoint IN Descriptor*/% X( y6 V; K& |* [& I' \' T
  190.   0x07,   /* bLength: Endpoint Descriptor size */
    7 D- o& B# @! s! x' b8 s5 k9 ~
  191.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */" B6 u5 j4 h* g  c: s# ?- C0 I, g
  192.   CDC2_IN_EP,                         /* bEndpointAddress */8 R5 R8 ]( L% B3 G
  193.   0x02,                              /* bmAttributes: Bulk */$ f7 t7 t  j. \& k. U+ l
  194.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
      W9 ?! y3 ~4 d$ l# [% Z
  195.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),( ^6 D3 B% h. Z
  196.   0x00,                               /* bInterval: ignore for Bulk transfer */# C3 _8 n; f( ]6 g9 z3 ^
  197.   Q* C# _5 d( _. y- m
  198. } ;& {" J/ x0 I& W; V; C6 a0 U4 l
复制代码
" i4 _1 C6 @- r- P4 [, F  Y( f
第五步:修改函数接口
/ U8 V: R0 S7 p) @: N0 i, K; K  X默认的HAL库函数是只针对一路CDC的情况,所以我们需要修改成多路CDC操作函数,将端口参数传递出来,一共有下面几个函数:" L: r% p  a6 p6 W' R, @+ y
USBD_CDC_DataOut:USB接收函数回调,修改提供端口参数4 j9 ^3 S) o0 z
CDC_Receive_FS(uint8_t *Buf, uint32_t *Len):USB CDC接收函数
# q6 h2 x8 N9 q; W- lCDC_Transmit_FS(uint8_t* Buf, uint16_t Len):USB CDC发送函数
6 _) X3 l) y$ l. E7 gUSBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)0 a; X% F" {7 ~7 W, e5 R
USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)! j- N4 s! h1 z2 ?! v; g
0 p5 Q# d8 f+ j; N6 `2 }
这几个函数的调用关系为:
0 @. w$ ^# [' F* i( U
3 `' H/ Q% h- q5 QCDC_Transmit_FS->
" y2 S6 F; B' H1 w# f3 z         USBD_CDC_TransmitPacket->
" W9 J  X3 t7 V8 L4 Y7 b+ I                 USBD_CDC_DataOut->- f( ], Y. `5 x3 i- p9 u) C
                         CDC_Receive_FS
" d4 \, w) D6 y0 g; b. ]2 l1 X  q) }8 W! M: z
USBD_CDC_DataOut函数有一个参数是epnum,这个是端点号,我们就可以使用该参数来区分是哪一路CDC!8 _# Y+ `$ M, d6 k) _
6 O9 c8 ~' r0 Y+ F: E* ~9 d9 A
所以USBD_CDC_DataOut函数添加上epnum参数,改为:
' [+ F7 C/ L1 Y2 j4 `2 E! p* V% Q' W7 @4 f
87FFT4J4O6N~RMKNZ8YR89U.png 7 L$ i0 y/ s& a$ q' h; a* O- h

( U1 z$ Q, q5 _" N# |; cUSBD_CDC_TransmitPacket函数改为:- B+ J8 g) N+ ~! m* s0 ^. K3 [

) ^. w. p$ F! P) H GUMS[2B0{]XJ3_K82PE(5.png
: j* V$ I/ k- U. r/ p' b3 I
3 o$ i' m) F. s8 y3 m  nUSBD_CDC_ReceivePacket函数改为:& Z: Q( z2 Y4 I5 X
6 f) ]+ S/ D) h! e9 O
`HOL3{QSVG](2{Y(QC0`WJ6.png 4 O6 ~0 W) t/ p2 Y. d
& ^3 Z9 J9 b5 F. {# g
CDC_Transmit_FS函数改为:
5 o1 t7 H% _) Y" O9 D# |- K) r$ \- c, t8 a
@69X$D8YZ_@V7T1V17)84.png
. {. G" [  Z. ]( J; M; ~6 w" d. l+ N0 X, B. ~
CDC_Receive_FS函数改为:
! o5 c) F% F( |# A" P# Y- }/ j9 [  c- B7 }) |' f2 I7 C6 e
@IXY_]7N2PN{CNTIF7PSQ.png
+ C0 z; G8 R2 K  l' i$ Y* T5 g  h. \* ~- j
到此就已经修改完毕了,将USB接入电脑后,设备管理区会多出现一个USB复合设备和两个端口,这样就是成功了:
' k  [& H0 }+ h4 |
+ q! C# s1 A. y 20210427151851625.png
2 L5 n6 }7 w: ]6 _" Y
/ d5 H/ T/ D3 b/ I下面进行测试,使用串口助手同时对两路CDC进行收发测试效果如下:
1 w% }" u) ^2 h' j6 w$ R+ L  _- i; x/ J  [) [* g! B
20210427145204370.gif 3 F. O5 ?! U; A, C9 Z3 E& P
6 B: S# h: a4 B4 l0 z
互不影响,USB两路CDC成功!2 d0 d9 g8 V+ s: G
, H8 y3 L( _6 N
注意事项及问题9 {" V) [( g: s+ S9 l
如果你移植的时候将USB接入电脑后,设备管理器里面只会出现1路串口,那么可能是因为你先用的CDC单独的工程测试的,电脑已经默认枚举为了VCP,那么此时有两种办法解决:3 W9 s4 h" s2 x% E4 T& k! r
. @4 X1 m  t: z( t3 c- z( g
1.设备管理器卸载掉出现的虚拟串口,重新拔插USB
% L  ]: ?+ e1 {. k2 q0 _2.修改程序里的USBD_VID,换个其他编号- U* ?' s( V& a. [! J* |9 Z

* ?( ~+ L& n0 l" V  O7 m  U9 M {`H`JIQ5FA@PY~5VH9YRM.png * x7 w! o4 k/ d2 Y) y' c

. U+ {, b7 K, ~, m我是用第二个办法解决的!
  }! S) C+ ]8 n- ]6 Y! A' c! v6 I9 W; u8 ]  ?
补充:3路CDC实现
5 B6 M+ O7 R$ q3 t0 r1 i5 o+ G实现3路CDC修改步骤跟实现2路一样,首先是PMA端点的配置:+ z5 S1 V3 v% u9 g
+ Q6 p& i, u* {8 l! M
J8%P41)T]b9Q%C)$T$HER.png ! ~: t! L% l& ]
5 _8 e. S- a+ p7 ?
_E5WLU7L13%Y]XC(2ZQOZIY.png
, z. [2 m. |8 T/ K# p4 F4 L$ g# W/ N" L

+ F& z7 ?, O7 h8 W! y为什么要把CDC_DATA_FS_MAX_PACKET_SIZE改成32呢?% \! o# s* ]- R, \4 ?

7 l3 m- r' Q( P. M) S2 x现在我们算一下使用到的端点:6 F; B1 u/ W+ K6 }; W6 A/ h! R
0X80、0X00用于USB必须的
% Z1 i4 |! ?  z0X81、0X01用于CDC1输入输出端点: M5 {. }8 W0 z2 n1 c; @! H9 e
0X82、0X02用于CDC2输入输出端点! B; ~1 ?" @. R1 h
0X83、0X03用于CDC3输入输出端点
& {4 d; L9 E. f: D. ~' V: L0X84用于CDC1命令控制端点、0X04未用但占用空间
% b1 P! B+ l  U. o0X85用于CDC2命令控制端点、0X05未用但占用空间! W% X! O2 V% y
0X86用于CDC3命令控制端点、0X06未用但占用空间" w0 m4 f, Y5 u: @+ ^! _( s7 A$ Z
0 x4 X$ \* Z3 r: q" Q3 O" S/ z+ X% `- V

7 O# \/ a0 j1 D) p: B可以看到我们用到的端点很多,光算输入输出端点一共8个,每个端点最大占用64,那么就是512字节,而PMA一共才512字节,所以如果将端点缓冲设置为最大64字节的话,3路CDC串口缓存空间不够用!不改成32的话你会发现第1和2路串口收发没问题,而第三路串口返回的都是0!
1 p7 ~. r+ f9 y  ^  u7 q. k; s6 a; h( `3 H9 O, Z
如下图:
! p, m# O4 {6 |% N& g, @1 ]6 o. n
; b) G& s/ j8 D$ H# ~ 2021042715193621.gif
0 x7 Q; t# k; E
+ k& D8 K. r% P- f0 Y$ W) F6 F# O改成32后,效果如下:
- I0 _8 f" T( _& W+ F' t) }' \1 Q
0 j  Z: k0 m3 o$ D) D% O; w% s
, _( n' Y7 r/ f9 A& @1 y0 l: X0 `: i, l! @5 @

6 q; u$ z- ?4 x7 G# C8 H# l1 c# J- E- L5 M5 C0 X  y

$ r( P3 _: \2 A2 [, g. v* _4 i2 J三路虚拟串口收发数据互不影响,到这里就成功了!
; G$ J  z" ~3 x3 f( I. F( a, b3 m& `% f9 b/ h" w# r9 Q& g
4 A( L$ H+ d- Y& J

0 P) V) ]' K7 U3 S. T6 |. R" L: j! M
20210427145004468.png
20210427151703661.png
赞 收藏 评论0 发布时间:2022-4-9 23:12

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版