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

STM32 USB CDC 虚拟多串口  

[复制链接]
creep 发布时间:2017-9-28 22:30
本帖最后由 creep 于 2017-9-28 22:37 编辑
6 |* F2 X  N( H; @2 u; I7 T3 F
4 _7 H7 ?  B/ C9 Y" _4 Z. f5 Y, J+ _
         之前一直使用STM32的CDC虚拟串口和上位机进行数据通信,通常只枚举一个串口基本就能满足要求。但是STM32 USB提供了足够的的端点可以在需要的情况下枚举出多个串口供使用,最新跟着论坛大神飞哥  @wofei1314 玩了下多个串口的使用,然后我在STM32F769-DISCO 上测试了下多串口的移植,以便以后使用的时候可以参考。
  B/ E( c' U$ \# R; ]0 w  }! [
" t4 B( L/ F) l# A* g         关于USB的使用ST的库文件里面提供很多的例子可以参考,除此之外官方也进行了不少USB的培训,没法参加的小伙伴可以看下培训的文档对USB有个基本的了解,然后找个板子把USB库中例子都跑一遍看下代码应该就会有个基本的了解。
4 s: `" g6 w$ l! g# E* e7 k! j! _2 r$ G' ]2 R
+ `0 |6 p& n% {9 v
, @. ?/ p6 _" j% Q( W5 U
0、复合设备
) Q- @( V( C  n! j
3 W0 W0 L4 o% E( ^" z3 z) F1 F$ N4 j" e$ y
CDC 类设备在枚举过程中最主要的信息存储在配置描述符内:
9 i, Y9 s. C  _0 H1 c
4 i+ ^/ R8 R! s3 V: P4 ^- u' [- I
! |; z% E) y. |/ O6 |# c; L abfdf189-a154-49fc-bd00-ab9c51382987.png
9 r* A6 C7 D! _# D/ p" v+ I3 |6 o1 t0 e. F: {& k
: G2 Q/ ^) T# j: ]4 i' B
  如上图所示, CDC 类的配置描述符一般包含两个接口 (Interface 0),一个控制接口,另外一个是数据接口 (Interface 1 ), 除此之外,还有一个虚线指向的 IAD(Interface Association Description),这个表示这个是不是可选的, 得根据实际情况来确定其是否真实存在。我们使用的CDC多串口要使用到IAD进行设置,通过IAD可以设置相应的接口枚举的设备类型2 _9 z% T2 u! G; b/ b/ y  `0 d
和使用的接口。 ( w# x/ I5 M/ }/ \
  一般来说把多CDC 串口 叫做复合设备,和一个CDC串口相比,USB库要把设备描述符、控制描述符进行修改 ,多串口新增的端点也要进行初始化 接收发送函数也要根据相应的端点进行处理,PC端加载的驱动也要适当修改。
, ^. {8 i, C5 c$ T$ {7 x% y: |8 a, _* c. m' s9 E  |, s
* @) w, Z, V, L
1、USB库修改
, h' l2 k: k+ X; M" X' Y
" ~0 H7 L! p8 r( t" \+ v7 t1 G* J* [( h7 W! h2 M# _

! m! N5 G5 n7 P- n4 a不同的芯片型号和不同的USB库配置可能有不少的区别,但是知道了需要修改哪里应该可以根据具体的情况进行操作,下面的移植是在STM32F769-DISCO
$ T( h: }$ U2 b  r3 L上由官方的HAL USB 库进行修改。默认是在一个CDC串口可以使用的前提下进行,关于一个CDC的移植可以参考官方代码或者使用Cubemx。, J  ]% h, K: C; M

3 c4 R& _3 U$ O6 B1 ]1)、2个VCP串口移植是在可以枚举出来一个VCP串口的工程上修改的,主要集中在USB CDC模式下的Class中文件及相应的头文件:
6 Q. o" H7 R9 M3 S, H, |: Q) _. H/ g
. K3 Q2 j5 N( T4 X0 M' j( I 5ec90026-3c9b-4786-87e0-06cadbef4265.png 5 e! W3 U1 t/ M" E; @) C

( C1 P+ @: v9 V( s0 r4 {! H6 c! y% m! p: o7 c* c& `! t
a)增加端点) y3 X6 R) C$ @7 V3 w
一个VCP的时候使用3个非0端点(2个BULK,一个Interrupt),再增加3个非0端点用于枚举另一个VCP。
, p; K& V3 [$ f* I
9 m5 [* U3 G/ U, |8 `! D 5b8ef82c-10a1-4d37-946b-ae60da254152.png * \5 I' @( B/ p% B$ X. S0 [. m! h! |3 P; j

/ N7 |/ l8 _" p) c设置增加的端点的FIFO
! H  _8 e5 n' J) O1 h6 s' Y9 S! g/ Y" r3 }
, ^( w% P5 |. b7 H1 [
0ddf6de2-e026-485b-8070-04514e83e56c.png . \2 p0 h) s# ~' X

( }- W7 \- ]$ l4 ]$ k. i6 H% l" F7 `
b)对增加的端点进行相应的初始化操作,我测试的是STM32F769-DISCO 上面的USB 是高速接口: `' D5 ^+ A; w4 l( [: s
; Q5 S2 e$ J2 x0 i6 _! h5 @; P! r

7 n, D3 u+ u: q+ K* h/ Z 48c4af14-a790-4617-8015-6c8f1131cdd4.png
* {0 `8 T7 J1 }3 J; ^3 n) ^0 e5 t1 Q) u
3 C9 K7 b# ~% @- Z! a; J
c)将设备描述符修改为复合设备模式+ M( [) c' _& X( g2 S

5 Z; k  y  l# D$ ?3 X' E2 u; r  }, g: ]' e( Z# J
98db37ba-b3dc-45be-b228-1590afb41c85.png
3 B) v* w0 N2 j/ i# Z# H! }  q" g' k3 ~
/ s2 u9 ~! _) f8 m
d)配置描述符,注意我使用的高速 USB模式,如果是全速或者其他速度模式选择相应的数组1 N1 @$ Y: ?9 T& B# j

* |5 o  a8 y1 J TIM图片20170928215619.png 6 \9 t1 l7 |. a# f  M; n& I
此外还需要修改最大的接口数(好像2个VCP设置大于2即可)' d1 G* w" z* R: H- C- s2 G! H
因为USB库中使用了maclloc申请内存,要适当调整栈空间。3 Z+ c, S: t3 @( v

% v& g) T( [' d- g, w4 n( o 2a0963ce-d11f-4a48-aff2-f502028d0e1f.png / ?/ C5 h0 U! T; U9 u+ L- M

% h2 i% m8 @" [- A下面是枚举的过程和安装好驱动之后的设备管理器显示:( a/ V5 D- t8 D2 J; P& `) v

8 ~0 Q* Z8 \# s6 y  ~/ @6 S9 w2 K
b1c85265-21c9-4197-9d29-b539741de625.jpg 3 L1 E' j& M) B+ E/ f$ |: S
5294a9d3-f04b-4c63-a85f-e3edd6e56495.jpg
' r" c  H, E: o$ I- {9 n; O
. A5 G# i/ g' H) K* p7 H& i* p. O: u0 N3 y6 y: K. v& u- f/ R
ed917e76-1d1c-4323-8bbc-dccf431f929a.png 9 e$ E3 U& Z- {5 c" f$ g3 u

. a7 f  c% c* W! H* l% f* {2 a- v" k; W5 k( j; n+ p8 K% z. b
测试代码如下:2 A- y. N  [3 Q9 b5 v( r5 ?
  1.   while (1)4 O) G! U% B6 g9 h* J3 `: R+ t2 K, q) m
  2.                 {
    7 ^! o$ M; ]( d: T' K
  3.             memcpy(TestBuff,"This message from VCP0\n",23);
    2 Z/ G2 n: e, W' F
  4.                         USB2PC(TestBuff,23,CDC_IN_EP1);
    & D, D- m9 I9 k3 r
  5.             HAL_Delay(1000);& Z* y7 Q1 }7 G9 n/ ?
  6.             memcpy(TestBuff,"This message from VCP1\n",23);1 n5 C2 c: e% a- Q# R
  7.                         USB2PC(TestBuff,23,CDC_IN_EP3);
    7 ]* F/ B3 |% u, D/ z
  8.             HAL_Delay(1000);      5 Z5 o3 m% u: y% Y* k# {1 K# n
  9.                 }
复制代码
USB收发测试效果如下
(点开查看大图)
) j+ f3 L/ O7 X1 [ test1.gif
: o9 b4 I: q3 r4 K9 c+ I3 r; C% |' H7 \! P

( G7 o$ b) q+ @2 S( O) E: r具体发送方向为:
6 P8 Q6 ?( H' f% a3 j* M
# f4 g* E  C2 w# @2 I+ A# d1 Q: g0 P0 c5 j8 [: E& i8 L6 E" v
a5af1022-17e9-4a9d-9f0f-d7efb9f29422.png
; w+ t3 }0 o) c. i5 b2 D5 p0 [5 Q+ s$ {+ h
4 s4 h; `6 C+ ^! @: D
2)、3个VCP串口,
$ {0 f' N$ j* X( H3 m" l1 B( x" r. S
在上面的代码基础上简单修改之后可以很容易的枚举出来3个串口9 V. e7 n; {- X

2 R: a6 n$ _+ L/ f d79eea4b-4d3d-42d4-b2ed-3c461a007d97.png
5 ]- M9 A, a: H4 @: P' }7 W测试代码如下:
9 s- {; }7 L* c1 ~& t! C0 r
  1. while (1)- i' |' n- ]  F9 B! F5 y
  2.                 {8 U0 [0 h* i3 p6 r+ O  `1 S
  3.             memcpy(TestBuff,"This message from VCP0\n",23);
    + [& {- E, ?& F: I4 X; `5 M/ `
  4.                         USB2PC(TestBuff,23,CDC_IN_EP1);2 S; y& X8 i9 W* E. ?; j
  5.             HAL_Delay(1000);- E( b' a1 g0 @0 k4 [4 f+ }
  6.             memcpy(TestBuff,"This message from VCP1\n",23);
    # r4 g1 u  c$ N  }: X
  7.                         USB2PC(TestBuff,23,CDC_IN_EP3);
    * S0 E7 o/ ~4 Z
  8.             HAL_Delay(1000);     
    # q0 L/ ~6 K4 Q% X
  9.             memcpy(TestBuff,"This message from VCP2\n",23);
    5 W, ?4 j4 [/ {; ^
  10.                         USB2PC(TestBuff,23,CDC_IN_EP5);
    ; M  u" g$ C4 w. G
  11.             HAL_Delay(1000);       & E/ ]0 n. |. X4 i5 j
  12.                 }
复制代码
3 F0 C; C; t, f7 Z4 P3 M# ~

& S6 P( M+ z/ [* q: I$ CUSB收发数据测试如下
(点开查看大图)7 {' x9 `/ J7 I  u+ u8 D
test6.gif - P9 I5 F% F" S) m* t: }: f
% G4 p0 s; B  J( r# t0 T. S+ g
373b1865-5fcd-493b-9972-f02d2b90dd98.png " ~( z5 c& X& i6 I( S: T6 P/ r

: \4 Y8 f2 {( \( k2 、驱动INF文件" {& u( u) m' X" U# ?
$ D: f, z. V- }- t/ ?5 n% W
复合设备需要修改inf文件并手动加载驱动,此时要注意库文件中VID/PID和驱动里面的值一致。修改过的驱动可能会因为没有数字签名证书在某些系统上无法加载。如果是WIN10系统可以加载兼容驱动也可以正常通信。
$ f- p4 ?& D3 y3 }( h: X8 M$ d. s3 b- h+ u
测试代码:0 }8 A3 J* m% G8 C1 W
2 Q6 w' I+ x4 H4 V/ z/ t, {0 P- n
Two-VCP-HS.rar (1.19 MB, 下载次数: 1802)

点评

厉害,研究得比较深入  发表于 2018-1-11 14:31

评分

参与人数 5 ST金币 +73 收起 理由
零壹 + 1 赞一个!
kylongmu + 20 很给力!
g921002 + 10 很给力!
wofei1314 + 22 神马都是浮云
zero99 + 20

查看全部评分

4 收藏 51 评论133 发布时间:2017-9-28 22:30

举报

133个回答
wylew 回答时间:2018-2-6 09:25:22
你好,你写的教程基本都能理解,就是我想问一下,我研究的源码里,它没有分别对某一个端点进行初始化的函数,而是统一用一个函数来初始化:
. h' a. g) v7 y9 R: ^6 k& S0 E8 Xendpoint_control_address = (UX_DCD_OTG_FS_DIEPCTL0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));2 g# P0 e" i0 H1 d: N
endpoint_size_address = (UX_DCD_OTG_FS_DIEPTSIZ0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));
+ x" L- J8 o/ `9 c$ ?endpoint_dma_address = (UX_DCD_OTG_FS_DIEPDMA0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));; ?5 A: l! j% t/ r, i/ u1 t, [
就像这样,在一个函数里就设置了端点0和非0端点的所有端点的IN设置,可根据ed -> ux_dcd_otg_ed_index来判断是哪一个端点,所以,相对来说,如果我添加了端点,就是不是不需要再添加我加的端点的初始化函数呢
深圳老刘 回答时间:2019-9-4 01:01:07
还是不行,感觉大神的代码有错
  B3 z. u- y9 Y8 z      /* Prepare Out endpoint to receive next packet */" W) B% I+ s8 D  P. l, @
      USBD_LL_PrepareReceive(pdev,
* q  i! e( I* I! D$ o                             CDC_OUT_EP1,2 t1 S: V9 B4 J! d  C
                             hcdc->RxBuffer,
$ ]! \3 w) l. T9 q) w; K. Y                             CDC_DATA_HS_OUT_PACKET_SIZE);- P- t& d3 t  p4 }! {

0 q0 M* z$ T( c' {这里怎么处理
creep 回答时间:2018-1-11 16:06:23
MaggiGunner 发表于 2018-1-11 15:35
* m+ a8 h( ]7 u1 A3 d$ p' F, W现在用CUBEMX生成单VCP发送没有问题。我看网上说VID和PID也很重要,我在您例程里看用的是0x03EB/0x6133, ...

# \. h6 d) e0 N$ w1 W: A. V1、 要保证STM32程序里面的用PID VID和驱动文件INF的PID VID保持一致,这里使用和官方的PID VID不一样是为了加载自己写的那个驱动,这样可以修改枚举出来的串口名称。
' l+ o1 J) K+ v! j4 G2、没有数字证书的问题我也搞不定,这个目前没有办法,WIN7 32位可以强制安装驱动,但是64位或者win10好像只能禁用签名验证才能安装驱动。win10也可以使用系统自动加载的兼容驱动好像也能正常通信。
anny 回答时间:2017-9-29 08:55:31
多谢分享!!!
gujiamao 回答时间:2017-9-29 09:09:50
版主,能不能直观的给我讲下,为何可以虚拟成多个串口,我一直理解成只能虚拟成一个
creep 回答时间:2017-9-29 09:52:37
gujiamao 发表于 2017-9-29 09:09& o% c3 U) S8 Z7 r$ @
版主,能不能直观的给我讲下,为何可以虚拟成多个串口,我一直理解成只能虚拟成一个 ...
# K) y$ f/ c9 y3 X, e. V5 G' r
可以先了解下USB复合设备。
七哥 回答时间:2017-9-29 10:12:38
这个比较有用,以前没搞明白端点怎么加,枚举描述等跟我之前理解一致。
zero99 回答时间:2017-9-29 10:30:09
膜拜一下大佬  
gujiamao 回答时间:2017-9-29 11:12:51
creep 发表于 2017-9-29 09:527 H! I1 O" W3 T3 m& Y
可以先了解下USB复合设备。
$ ^& F! D3 _9 `9 V
好的
gujiamao 回答时间:2017-9-29 11:13:41
creep 发表于 2017-9-29 09:52
( f* @3 c$ q& j7 Q( l8 u8 \" Q  m可以先了解下USB复合设备。
6 P' P* d) D& x9 x* h% y
好的 !!!
adlu 回答时间:2017-9-29 11:24:17
厉害!
斜阳 回答时间:2017-9-29 11:45:05
大神之作。mark备用
党国特派员 回答时间:2017-9-29 13:07:29
这个绝对要收藏...
wofei1314 回答时间:2017-10-10 22:55:38
膜拜~
" x( n! v& p9 b: b# G# H9 l
8 A4 x) [9 }1 Y. ~; R谢谢大神分享!!
creep 回答时间:2017-10-11 08:50:29
wofei1314 发表于 2017-10-10 22:55
8 ~/ G/ E5 u4 G  Y" i膜拜~$ D4 P1 \4 M/ t7 b
( o7 y, L# n9 C. ?9 d' a' u8 n
谢谢大神分享!!
9 D" n: z# K1 _" k
感谢飞哥带路!
wofei1314 回答时间:2017-10-13 09:36:15
又看了一遍,好详细!!!
唯有奋斗 回答时间:2017-12-30 08:58:42
您好,请问一下STM32F4能虚拟出几个VCP呢?
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版