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

STM32 USB CDC 虚拟多串口  

[复制链接]
creep 发布时间:2017-9-28 22:30
本帖最后由 creep 于 2017-9-28 22:37 编辑 1 ?9 a. y$ o  h% h8 d$ g

$ u/ L& N+ f9 l# ]2 Y' [. }8 z$ f4 R) p& {+ J
         之前一直使用STM32的CDC虚拟串口和上位机进行数据通信,通常只枚举一个串口基本就能满足要求。但是STM32 USB提供了足够的的端点可以在需要的情况下枚举出多个串口供使用,最新跟着论坛大神飞哥  @wofei1314 玩了下多个串口的使用,然后我在STM32F769-DISCO 上测试了下多串口的移植,以便以后使用的时候可以参考。' i# i5 ~6 c, R3 f6 o: v5 F2 u2 P( y

- q- Z8 s! h# @  U. I         关于USB的使用ST的库文件里面提供很多的例子可以参考,除此之外官方也进行了不少USB的培训,没法参加的小伙伴可以看下培训的文档对USB有个基本的了解,然后找个板子把USB库中例子都跑一遍看下代码应该就会有个基本的了解。
5 z. G4 p3 ~3 y+ w- B& C9 @- e* z- e: g& S8 \# W- _
5 h. P6 A5 ~+ r, d! J
0 H- U+ X: O3 X
0、复合设备- _4 z7 M. j& I$ \6 B
  Y, S- m0 {; \, T/ u

; e# f0 ?. M2 j( I. sCDC 类设备在枚举过程中最主要的信息存储在配置描述符内:. F' t2 p, b2 k2 `+ v  H/ N  _( k
8 b0 J# S% @# f4 x' S# J6 f
6 ]* w+ e4 ~. t& _: f: ^% Z
abfdf189-a154-49fc-bd00-ab9c51382987.png
. Q& X: p3 J3 F8 A# [
5 h4 c7 X$ L- W- A$ P: u) R! e8 W6 ?# B2 M: [0 X# T1 F) R- n* Q4 j
  如上图所示, CDC 类的配置描述符一般包含两个接口 (Interface 0),一个控制接口,另外一个是数据接口 (Interface 1 ), 除此之外,还有一个虚线指向的 IAD(Interface Association Description),这个表示这个是不是可选的, 得根据实际情况来确定其是否真实存在。我们使用的CDC多串口要使用到IAD进行设置,通过IAD可以设置相应的接口枚举的设备类型
8 H5 A: [4 h! K$ Y; O- I. r; F% e9 X和使用的接口。 0 Q) v+ Z+ a% |4 M. B; q0 M  B
  一般来说把多CDC 串口 叫做复合设备,和一个CDC串口相比,USB库要把设备描述符、控制描述符进行修改 ,多串口新增的端点也要进行初始化 接收发送函数也要根据相应的端点进行处理,PC端加载的驱动也要适当修改。
9 ~$ H& r  y' g0 @  {. C9 \( w2 |) Y) m/ y0 W" R! e. m6 z
9 `7 n; _5 o/ C% F$ l- B
1、USB库修改
& M  }1 K/ E+ c. ]9 P1 `' i8 ?3 x1 Z% {2 v  B4 d

5 B/ z& q- k$ X# n" b6 |7 `+ ^. S% J* I- l& E
不同的芯片型号和不同的USB库配置可能有不少的区别,但是知道了需要修改哪里应该可以根据具体的情况进行操作,下面的移植是在STM32F769-DISCO
& Z7 e  x0 W2 F# y+ V, _) y上由官方的HAL USB 库进行修改。默认是在一个CDC串口可以使用的前提下进行,关于一个CDC的移植可以参考官方代码或者使用Cubemx。
) s3 {% K7 K0 |
9 B  X+ u* L1 d2 o% f+ m1)、2个VCP串口移植是在可以枚举出来一个VCP串口的工程上修改的,主要集中在USB CDC模式下的Class中文件及相应的头文件:
% u; j; C& y' w; g. Y
* |9 }: I5 q2 e+ ^ 5ec90026-3c9b-4786-87e0-06cadbef4265.png ! D; C* M& |6 E$ [  h

% A+ {" N! c7 |6 b+ R+ L' V/ k, s/ g( i  I' j% W' i6 [4 u  K/ j
a)增加端点8 q8 [( E) P$ Z) \7 d$ j
一个VCP的时候使用3个非0端点(2个BULK,一个Interrupt),再增加3个非0端点用于枚举另一个VCP。
& _. V3 q9 R  Z6 t" q
+ `: a) F1 U' P, L  ] 5b8ef82c-10a1-4d37-946b-ae60da254152.png
# v! j" s2 X, \  ]# c- s; Z! I1 _) g% O9 N
设置增加的端点的FIFO
- c4 ~9 t4 L) t# `1 V. P7 c( Z
5 j9 @) \$ _: d7 m% {$ B; \' p( h
0ddf6de2-e026-485b-8070-04514e83e56c.png / s$ K' E2 R) u

4 s6 |6 V; R) G# e# x
2 T# `2 {9 [+ Z) l! _* y; Xb)对增加的端点进行相应的初始化操作,我测试的是STM32F769-DISCO 上面的USB 是高速接口9 u- |) H3 d/ {0 @) _1 ]
6 b$ F) ^# k- q8 g3 H6 o3 @/ E

7 o& }# w) T/ D3 t 48c4af14-a790-4617-8015-6c8f1131cdd4.png * }( ^: V9 W3 W* Q

' A4 j; @  a8 g# P8 N0 q: a9 j4 @( [2 f( a& R8 K
c)将设备描述符修改为复合设备模式) d, q! i8 ~/ j( N1 k7 p
& |; A( r$ ?) N7 w& f' [  i% O

4 ^% c5 t. e8 b7 {0 O9 } 98db37ba-b3dc-45be-b228-1590afb41c85.png
7 W/ n2 G* x4 u+ e: u- R2 P( ?
$ s. x) q1 d: N+ \2 K) j& B, U. |( ~, g
d)配置描述符,注意我使用的高速 USB模式,如果是全速或者其他速度模式选择相应的数组8 c6 V1 J* K' g! G! D" N3 b
- k( p3 V9 j* l! G6 W7 ?
TIM图片20170928215619.png % j* ?( J) }" }+ p- i: ]
此外还需要修改最大的接口数(好像2个VCP设置大于2即可)( m0 g- r3 u1 J$ U: @3 |
因为USB库中使用了maclloc申请内存,要适当调整栈空间。
" L1 f' R/ I% O5 e  L
1 Y. b& ]: Y/ U4 ~  K0 h0 L 2a0963ce-d11f-4a48-aff2-f502028d0e1f.png
3 `+ d0 x, K% V. Q& t$ |" b* n5 P7 ]* T4 B( O% |( I) }
下面是枚举的过程和安装好驱动之后的设备管理器显示:6 |1 X  \+ n3 g; _, x+ P
1 v, ^/ v+ z8 W( \$ M# z
! l- U/ W9 P! f6 e& M
b1c85265-21c9-4197-9d29-b539741de625.jpg * G" |& ]# ?" K2 C) |0 U$ O
5294a9d3-f04b-4c63-a85f-e3edd6e56495.jpg 9 m* ~$ Y7 A( B# f7 y* g5 O

3 O. |; p* R! g+ @- \# F+ x. \: |4 i3 I7 x5 G$ J1 |
ed917e76-1d1c-4323-8bbc-dccf431f929a.png
& A1 V: S9 c" R* M( C/ z* b# W  a+ }; ?2 ~; G8 J
" {- U; D4 J: P" o
测试代码如下:
7 g- o  B  T- G, p( a8 d0 D5 [2 X
  1.   while (1)
    6 P, m5 T1 E0 L$ V. A0 c
  2.                 {
    7 ]* R2 j0 {1 V5 I
  3.             memcpy(TestBuff,"This message from VCP0\n",23);* S+ E7 @* s8 i' k  o. j' g
  4.                         USB2PC(TestBuff,23,CDC_IN_EP1);3 \# \) i+ v, P
  5.             HAL_Delay(1000);
    4 U* c& O4 K0 d* z3 V7 ?
  6.             memcpy(TestBuff,"This message from VCP1\n",23);- t1 u- \# ]& f. J. `5 }) f
  7.                         USB2PC(TestBuff,23,CDC_IN_EP3);+ w! a, `. S8 s
  8.             HAL_Delay(1000);      & c& w3 _4 g5 L5 C1 S7 i1 v# _/ d
  9.                 }
复制代码
USB收发测试效果如下
(点开查看大图)' S+ A2 c+ B/ L# M% \
test1.gif
# t* o+ ?% N" y) {' C2 m$ k, ?8 ~- |" j7 }; U& ?2 A
" {. g+ ^! Q5 e9 f
具体发送方向为:
! ~/ R; [1 K1 ^5 b7 n8 @% x# M
# G* v  l- Q$ V1 d2 T# ?. X
4 w+ \. G; i4 w3 ^/ H a5af1022-17e9-4a9d-9f0f-d7efb9f29422.png
4 P2 X6 n! c, p# r. q1 h6 N9 {$ @6 D+ Y% I

1 E0 r  x/ [/ _9 Y" r% `2)、3个VCP串口,
' F8 V6 l  `) r, l5 @% L- h6 T& A6 ^3 m
在上面的代码基础上简单修改之后可以很容易的枚举出来3个串口% ?; I+ P. T- }4 Y9 p! P, b
4 I" t' E6 E) y" ~' H
d79eea4b-4d3d-42d4-b2ed-3c461a007d97.png 5 `4 Z. z. L9 N- {  n
测试代码如下:, h1 x# S; y( r: H
  1. while (1)
    ' V) N' W  w6 {
  2.                 {0 V0 W1 e# Z) `; w8 U6 V. ^
  3.             memcpy(TestBuff,"This message from VCP0\n",23);' H7 E5 F* t8 }) z! r0 F
  4.                         USB2PC(TestBuff,23,CDC_IN_EP1);
    / J- d$ T& q  T( H$ a) N
  5.             HAL_Delay(1000);
    + h$ s4 a4 p6 X; v  O
  6.             memcpy(TestBuff,"This message from VCP1\n",23);9 E( R1 l3 H" N( J4 j# }
  7.                         USB2PC(TestBuff,23,CDC_IN_EP3);* s! x1 P0 S# k' d$ n
  8.             HAL_Delay(1000);     
    1 q  }* I0 \8 h
  9.             memcpy(TestBuff,"This message from VCP2\n",23);
    % m. H, j% w' }4 p5 m
  10.                         USB2PC(TestBuff,23,CDC_IN_EP5);. ~: I* p" V( e, ^+ P
  11.             HAL_Delay(1000);       % C9 Z8 x' Y& C9 @/ U/ r" |
  12.                 }
复制代码

- s3 o: J* ^3 @" _3 L2 U, R8 t" E; l' c- K& _+ c* z, D& V
USB收发数据测试如下
(点开查看大图)8 ?! R3 ~7 |  I0 i$ I2 i
test6.gif
1 E  a3 ^, z( \' Z5 h
! i" g1 Z6 p! a' V& @- d 373b1865-5fcd-493b-9972-f02d2b90dd98.png - c% n  n% J4 y( G
1 c9 M2 J  C8 N% }% ], E- Q0 m5 o# N
2 、驱动INF文件
7 h" j: ^$ r5 f; \: L6 S& ^" a% d, E9 f: ?8 k& a* D9 T
复合设备需要修改inf文件并手动加载驱动,此时要注意库文件中VID/PID和驱动里面的值一致。修改过的驱动可能会因为没有数字签名证书在某些系统上无法加载。如果是WIN10系统可以加载兼容驱动也可以正常通信。1 h9 N+ R. _2 ^. p! s
$ k& M( |2 x' E7 ^% `* c
测试代码:6 g2 K1 n, [# ~: u6 Y2 h3 @
. w& t. M# m/ B6 i
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
你好,你写的教程基本都能理解,就是我想问一下,我研究的源码里,它没有分别对某一个端点进行初始化的函数,而是统一用一个函数来初始化:
$ q( v7 m- C4 g9 {endpoint_control_address = (UX_DCD_OTG_FS_DIEPCTL0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));* A+ Q2 T+ }; Z% b: K0 W: q
endpoint_size_address = (UX_DCD_OTG_FS_DIEPTSIZ0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));& m& q# y9 z' R; \3 l! O
endpoint_dma_address = (UX_DCD_OTG_FS_DIEPDMA0 + (ed -> ux_dcd_otg_ed_index * UX_DCD_OTG_ENDPOINT_SPACE_SIZE));
/ _( V! E2 ^' W' r: n: i. i就像这样,在一个函数里就设置了端点0和非0端点的所有端点的IN设置,可根据ed -> ux_dcd_otg_ed_index来判断是哪一个端点,所以,相对来说,如果我添加了端点,就是不是不需要再添加我加的端点的初始化函数呢
深圳老刘 回答时间:2019-9-4 01:01:07
还是不行,感觉大神的代码有错
/ D+ z' K4 E- k/ i6 J$ b      /* Prepare Out endpoint to receive next packet */
& U0 z5 d! J6 c      USBD_LL_PrepareReceive(pdev,
% H  U4 K& S2 p0 _- o' y% ^5 S' G                             CDC_OUT_EP1,. q& S* |% g7 B& Y
                             hcdc->RxBuffer,8 c& X* |7 [0 J+ x$ o
                             CDC_DATA_HS_OUT_PACKET_SIZE);
3 H) i: M& @! Y1 u# Q9 K2 q; f! ?' [& s5 U+ b) p
这里怎么处理
creep 回答时间:2018-1-11 16:06:23
MaggiGunner 发表于 2018-1-11 15:35
$ n$ {# Z/ R" E" K0 Y* }' l现在用CUBEMX生成单VCP发送没有问题。我看网上说VID和PID也很重要,我在您例程里看用的是0x03EB/0x6133, ...

0 [( p0 ?- b" `& h2 {8 {2 a  S+ t1、 要保证STM32程序里面的用PID VID和驱动文件INF的PID VID保持一致,这里使用和官方的PID VID不一样是为了加载自己写的那个驱动,这样可以修改枚举出来的串口名称。
6 P2 Q. x9 t0 G; H- v7 E2、没有数字证书的问题我也搞不定,这个目前没有办法,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+ u5 y9 V) u# N! \
版主,能不能直观的给我讲下,为何可以虚拟成多个串口,我一直理解成只能虚拟成一个 ...
% E0 {6 g5 E! |4 L; I
可以先了解下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:525 X3 `& B6 a8 a# {. k
可以先了解下USB复合设备。

: g& O0 j2 Q! i+ \. ^好的
gujiamao 回答时间:2017-9-29 11:13:41
creep 发表于 2017-9-29 09:52
. b4 l6 v# t5 S- i( y! v2 _可以先了解下USB复合设备。
; R+ o8 ?- \" C* f
好的 !!!
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
膜拜~+ g, e1 y1 r, h' }- U# K( l
+ O2 |5 i; {: }6 a& w
谢谢大神分享!!
creep 回答时间:2017-10-11 08:50:29
wofei1314 发表于 2017-10-10 22:55# y5 p6 Q" Q- H
膜拜~2 Y+ y0 Q- ^2 }: N" l3 d# E) K
2 m  ]' `, A1 F* L7 A
谢谢大神分享!!
5 P" }% f5 s# U* D- ~# {
感谢飞哥带路!
wofei1314 回答时间:2017-10-13 09:36:15
又看了一遍,好详细!!!
唯有奋斗 回答时间:2017-12-30 08:58:42
您好,请问一下STM32F4能虚拟出几个VCP呢?
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版