打印
[STM32F1]

STM32F103多路虚拟串口成功

[复制链接]
20575|76
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
QuakeGod|  楼主 | 2016-12-16 09:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
虽然是电路科班出身,刚开始做过一段时间,但是已经很多年没有接触电路和单片机了,一直在做软件。
最近刚开始搞STM32,也第一次接触USB。有人送了一个二手的STM32F103Discovery,芯片是C8T6,版很简陋,只有一个LDO,一个晶振,几个LED和几个按键,连硬串口都没有,这些年手头也没有任何电路的存货了,连个电容都没有,所以就打算把虚拟串口搞出来。


沙发
QuakeGod|  楼主 | 2016-12-16 09:22 | 只看该作者
前两天把虚拟串口搞出来了。但是发现只有一个串口的话,调试通讯协议的时候还是不够,想做出至少3个串口,一个做命令行,另外两个互相通讯。昨天晚上也将按照网上的例子把双串口做完,后来索性搞了个通宵,把4串口做出来了了。
以F103的资源,8个双向EP,理论上可以虚拟出7个串口,如果要实现中断端口,则能虚拟6个串口。

使用特权

评论回复
板凳
QuakeGod|  楼主 | 2016-12-16 09:34 | 只看该作者
本帖最后由 QuakeGod 于 2016-12-16 09:38 编辑

网上找的例子,EP0作为控制口,EP1_IN和EP3_OUT作为数据,EP2_IN作为中断输入,其实完全没有必要。
STM32F103的USB有8个双向端点,或者说有16个单向端点,8IN,8OUT。但是对应的IN和OUT需要同一个EP号,而且工作模式也要一致,所以还是8个双向。
之所以网上都说,端点是单向的,是把EP1_IN和EP1_OUT当成了两个不同的端点,使用时可以分别指定而已。
实际上F103的每个EP都有IN和OUT(双缓冲除外);
实际上EP0也分EP0_IN和EP0_OUT,只不过EP0作用比较特殊,通常把IN和OUT合在一起当成EP0
再回到虚拟串口上,实际上完全可以把把数据通道设置成同一个EP。一个EP1_IN,一个EP1_OUT当成数据通道。
这样的话除了EP2作为中断口,还有EP3,EP4,EP5,EP6,EP7,再加上原来的EP1,总共可以虚拟6个串口

使用特权

评论回复
地板
Ketose| | 2016-12-16 09:55 | 只看该作者
成果呢???

使用特权

评论回复
5
QuakeGod|  楼主 | 2016-12-16 10:04 | 只看该作者
为什么只做了4个虚拟串口,没做6个呢,关键在于512个字节的包缓冲区不够用了。
实际上,这4路虚拟串口,前3路都是64字节进,64字节出的缓冲区,最后一个串口只有16字节进,16字节出的缓冲区。而且已经把EP0的最大包尺寸改成了8字节了。中断EP的缓冲区也改成8字节了。

使用特权

评论回复
6
QuakeGod|  楼主 | 2016-12-16 10:09 | 只看该作者
经测试,用直接在SOF中断直接填充数据和CTR中断直接置Valid的方法向电脑单向传输速度可以达到900kBps,算起来是7.2Mbps,已经很快了。

使用特权

评论回复
7
QuakeGod|  楼主 | 2016-12-16 10:09 | 只看该作者
要干活了,晚上回来接着写。

使用特权

评论回复
8
hameyou| | 2016-12-16 10:25 | 只看该作者
楼主挺有干劲的

使用特权

评论回复
9
icecut| | 2016-12-16 10:45 | 只看该作者

使用特权

评论回复
10
nelsonfung| | 2016-12-16 11:22 | 只看该作者
坐等楼主更新

使用特权

评论回复
11
mmuuss586| | 2016-12-16 11:58 | 只看该作者
厉害,啥时候上个图看看;

使用特权

评论回复
12
QuakeGod|  楼主 | 2016-12-16 18:40 | 只看该作者
终于回来了,干了一天活,累死了,中午饭都没顾上吃,这才回来吃完了晚饭。
我发现,一晚上通宵干活不睡觉,有个严重的后遗症,那就是晚上忘记给手机充电了,结果没到中午手机就没电了,严重影响身心健康。

使用特权

评论回复
13
QuakeGod|  楼主 | 2016-12-16 19:42 | 只看该作者
言归正传,接着说说STM32的虚拟串口,
首先,说说EP通道的方向,这个IN和OUT,是从主机的角度说的,往PC发数据的,就叫 IN,PC发出来的叫 OUT.
而在STM32库里,通过 EP_IN 向PC 发数据,是叫 Tx,
从OUT通道收PC发来的数据叫Rx. 这个Tx和Rx是从STM32自己的角度说的了。

上集说到了6路数据通道,还没说EP0和中断EP2_IN,
首先任何一个USB设备都要有EP0,用来接收主机发过来的命令和向主机返回配置。
还有,跟驱动程序也有关系。作为CDC设备,驱动程序也会通过EP0发过来设置命令和查询命令。比如 Set_Line_Coding, Get_Line_Coding, 也就是虚拟串口的波特率,数据位,停止位,有无校验以及方式等,形如 115200 8,N,1的意思。
这个功能网上的很多例子和库都实现了。 这个波特率是一个32位数值,说以说理论上虚拟串口波特率是没有任何限制的,可以取任何数值,不一定在标准里选。比如也可以设成 1234567。当然了,这个波特率对于USB来说没有任何意义,除非你是做转串口的应用。不过这个Set_Line_Coding的功能是要实现的,因为驱动设置完Set_Line_Coding后,还有 Get_Line_Coding, 如果返回信息有问题,就会报错。
另外一个通过EP0传送的是命令是SET_CONTROL_LINE_STATE,即设置串口的线路状态,即DTR,和RTS信号。PC端的串口软件设置线路状态后,驱动会发这个命令过来,并且带着要设置的新的线路状态为参数。
查到网上一个大虾,说微软的虚拟串口驱动 usbser.sys只支持DTR,但是实际测试的时候,发现RTS也支持。
不过不是实时发送的,只有DTR发生变化的时候,才发命令,同时会把RTS的状态也发过来,还有一个状态位也发过来了,不过这个位在CDC规范上没查到意义。
另外提一下,EP0发来的命令里都有一个参数,Index, 是指的接口序号,这样就能区分每个命令到底是给哪个虚拟串口发的了。
当然,EP0还能发很多命令,看你定义在设备描述符里面能支持的属性。其他的大同小异,我们也可以先不考虑。

再说这个EP2_IN 中断传输端点是干什么用的,原来偶也不知道,两天前看完CDC规范才看明白,网上下载的英文版,也不知道有没有中文的,看了3个小时才看完。
这个中断端点是用来向驱动发送Notification通知的,比如线路变化,电话打入振铃(用过Modem的人才有可能见过),网线插上拔出,速度变化等。
用在我们虚拟串口这里的可以有一个SERIAL_STATE,这个通知表示串口线路的变化。即CTS DSR RLSD 等的状态。不是主机去读的,而是需要虚拟串口这边主动报告。
通知的格式是8个字节的一个结构体,后面接不定长度的数据,通过中断端口发给主机。起始这个端口号也是在枚举的时候的描述符里面指定的。
比如SERIAL_STATE这个通知的格式为

其中 SERIAL_STATE 为 0x20
这个通知结构体为8个字节,其中wIndex,指示的是接口ID,也就是从那个虚拟串口发出的通知。加上后面16位Data,一共10个字节,由于EP2_INT包长为8字节,所以需要分两次传送。
其他通知见下表。




使用特权

评论回复
14
QuakeGod|  楼主 | 2016-12-16 19:56 | 只看该作者
继续,其实楼主本人也是最近几天才刚刚开始搞STM32和USB,很多东西都不懂,也遇到了各种问题。不过楼主还是有股劲头的,不会遇到困难就退缩,还有就是肯吃苦,能耐下性子,不急躁。
遇到问题就网上找资料,看完了电脑圈圈的USB启蒙书,先表示一下感谢。还下载了STM32F103的资料,论坛查资料。看了CDC 规范。百度文库 和 道客88 上花钱充了会员。
当然也遇到几个问题,没弄明白。
首先,通过EP2_INT发出的通知,BusHound并没有捕捉到。但是MCU表示发送成功了,而且串口助手上相应的状态也变化了。说明是发出了的。但是并不是每次发送都能收到,收到的可能性只有1/10一下。
另外,关于发送64个整字节之后,要发0长度包的问题也没有处理,貌似STM32会自动发送NAK,也不会引起中断,所以无从判断,不过看起来似乎对性能没有什么影响。
本来今天晚上还想继续攻克,不过考虑到这个身子骨,看情况了,今天不要干太晚,睡早点。
一会要试一下把EP2改成BULK模式,看看能不能发出通知。

使用特权

评论回复
15
QuakeGod|  楼主 | 2016-12-16 20:01 | 只看该作者
对了,先上图。
STM32F103Discovery开发板,芯片是C8T6,上面自带了一个ST-LINK V1

所有的工作都是在这个上面完成的。

使用特权

评论回复
16
QuakeGod|  楼主 | 2016-12-16 21:13 | 只看该作者
设备管理器,虚拟串口列表


BusHound中USB设备列表


BusHound中各端点列表


驱动程序是从STM32的驱动上改的,关键是这一段,黄色部分是要后加的。
;------------------------------------------------------------------------------
;            VID/PID Settings
;------------------------------------------------------------------------------
[DeviceList.NT]
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_02
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_03
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_04
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_05

%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_06


[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_02
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_03
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_04
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_05
%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740&MI_06

实际上,我的4串口只用到了MI_00,MI_02,MI_04,MI_06,
驱动改成那样,是为了以后能同时驱动起6串口,到那时我的硬件ID可能会改成MI_00,MI_01,MI_02,MI_03,MI_04,MI_05

四个串口同时打开的图

其中串口1做成了1个支持ANSI的TTY,
串口2做成了一个显示输出。
串口3和串口4只做了简单的LOOPBACK回显。
每个串口的输入输出都加了一个512字节环形FIFO。这回用printf输出一个相当长的字符串也可以做到0等待了。

使用特权

评论回复
17
QuakeGod|  楼主 | 2016-12-16 21:34 | 只看该作者
本帖最后由 QuakeGod 于 2016-12-16 21:50 编辑

枚举时数据抓包

  Device - Device ID (followed by the endpoint for USB devices)
            (29) USB Composite Device
            (30) STM USB Port 20161211 (COM4)
            (31) STM USB Port 20161211 (COM5)
            (32) STM USB Port 20161211 (COM6)
            (33) STM USB Port 20161211 (COM7)
  Length - Total transfer length
  Phase  - Phase Type
            CTL   USB control transfer      
            IN    Data in transfer           
  Data   - Hex dump of the data transferred
  Descr  - Description of the phase
  Delta  - Elapsed time from the previous phase to the current phase
  Cmd... - Position in the captured data


Device  Length    Phase  Data                                                Description       Delta  Cmd.Phase.Ofs(rep)
------  --------  -----  --------------------------------------------------  ----------------  -----  ------------------
  29.0            CTL    80 06 00 01  00 00 12 00                            GET DESCRIPTOR    2.0sc         1.1.0        //获取设备描述符
  29.0        18  IN     12 01 00 02  ef 02 01 08  83 04 40 57  00 02 01 02  ..........@W....  330us         1.2.0        //返回设备描述符
                         03 01                                               ..                              1.2.16      
  29.0            CTL    80 06 00 02  00 00 09 00                            GET DESCRIPTOR     17us         2.1.0        //获取配置描述符前几个字节,以便知道长度
  29.0         9  IN     09 02 11 01  08 01 00 c0  65                        ........e         213us         2.2.0        
  29.0            CTL    80 06 00 02  00 00 11 01                            GET DESCRIPTOR     15us         3.1.0        //获取整个配置描述符
  29.0       273  IN     09 02 11 01  08 01 00 c0  65 08 0b 00  02 02 02 01  ........e.......  1.3ms         3.2.0        //返回整个配置描述符,其实是一次一次每次8个字节传过来的,不过中途没有间歇。
                         02 09 04 00  00 01 02 02  01 00 05 24  00 10 01 05  ...........$....                3.2.16      
                         24 01 00 01  04 24 02 02  05 24 06 00  01 07 05 82  $....$...$......                3.2.32      
                         03 08 00 02  09 04 01 00  02 0a 00 00  00 07 05 01  ................                3.2.48      
                         02 40 00 00  07 05 81 02  40 00 00 08  0b 02 02 02  .@......@.......                3.2.64      
                         02 01 02 09  04 02 00 01  02 02 01 00  05 24 00 10  .............$..                3.2.80      
                         01 05 24 01  00 01 04 24  02 02 05 24  06 00 01 07  ..$....$...$....                3.2.96      
                         05 82 03 08  00 02 09 04  03 00 02 0a  00 00 00 07  ................                3.2.112      
                         05 03 02 40  00 00 07 05  83 02 40 00  00 08 0b 04  ...@......@.....                3.2.128      
                         02 02 02 01  02 09 04 04  00 01 02 02  01 00 05 24  ...............$                3.2.144      
                         00 10 01 05  24 01 00 01  04 24 02 02  05 24 06 00  ....$....$...$..                3.2.160      
                         01 07 05 82  03 08 00 02  09 04 05 00  02 0a 00 00  ................                3.2.176      
                         00 07 05 04  02 40 00 00  07 05 84 02  40 00 00 08  .....@......@...                3.2.192      
                         0b 06 02 02  02 01 02 09  04 06 00 01  02 02 01 00  ................                3.2.208      
                         05 24 00 10  01 05 24 01  00 01 04 24  02 02 05 24  .$....$....$...$                3.2.224      
                         06 00 01 07  05 82 03 08  00 02 09 04  07 00 02 0a  ................                3.2.240      
                         00 00 00 07  05 05 02 10  00 00 07 05  85 02 10 00  ................                3.2.256      
                         00                                                  .                               3.2.272      
  29.0            CTL    00 09 01 00  00 00 00 00                            SET CONFIG        152us         4.1.0        //配置设备,好像是选择第一套配置的意思吧
  29.0            CTL    80 06 02 03  09 04 04 00                            GET DESCRIPTOR    2.6ms         5.1.0        //获取复合设备中第一个功能设备的字符串?
  29.0         4  IN     26 03 56 00                                         &.V.              166us         5.2.0        
  29.0            CTL    80 06 02 03  09 04 26 00                            GET DESCRIPTOR     28us         6.1.0        
  29.0        38  IN     26 03 56 00  69 00 72 00  74 00 75 00  61 00 6c 00  &.V.i.r.t.u.a.l.  347us         6.2.0        //返回字符串 UNICODE
                         20 00 43 00  4f 00 4d 00  20 00 50 00  6f 00 72 00   .C.O.M. .P.o.r.                6.2.16      
                         74 00 20 00  20 00                                  t. . .                          6.2.32      
  29.0            CTL    80 06 02 03  09 04 04 00                            GET DESCRIPTOR    1.9ms         7.1.0        
  29.0         4  IN     26 03 56 00                                         &.V.              239us         7.2.0        
  29.0            CTL    80 06 02 03  09 04 26 00                            GET DESCRIPTOR     15us         8.1.0        
  29.0        38  IN     26 03 56 00  69 00 72 00  74 00 75 00  61 00 6c 00  &.V.i.r.t.u.a.l.  353us         8.2.0        
                         20 00 43 00  4f 00 4d 00  20 00 50 00  6f 00 72 00   .C.O.M. .P.o.r.                8.2.16      
                         74 00 20 00  20 00                                  t. . .                          8.2.32      
  29.0            CTL    80 06 02 03  09 04 04 00                            GET DESCRIPTOR    1.8ms         9.1.0        
  29.0         4  IN     26 03 56 00                                         &.V.              280us         9.2.0        
  29.0            CTL    80 06 02 03  09 04 26 00                            GET DESCRIPTOR     27us        10.1.0        
  29.0        38  IN     26 03 56 00  69 00 72 00  74 00 75 00  61 00 6c 00  &.V.i.r.t.u.a.l.  343us        10.2.0        
                         20 00 43 00  4f 00 4d 00  20 00 50 00  6f 00 72 00   .C.O.M. .P.o.r.               10.2.16      
                         74 00 20 00  20 00                                  t. . .                         10.2.32      
  29.0            CTL    80 06 02 03  09 04 04 00                            GET DESCRIPTOR    1.5ms        11.1.0        
  29.0         4  IN     26 03 56 00                                         &.V.              235us        11.2.0        
  29.0            CTL    80 06 02 03  09 04 26 00                            GET DESCRIPTOR     25us        12.1.0        
  29.0        38  IN     26 03 56 00  69 00 72 00  74 00 75 00  61 00 6c 00  &.V.i.r.t.u.a.l.  358us        12.2.0        
                         20 00 43 00  4f 00 4d 00  20 00 50 00  6f 00 72 00   .C.O.M. .P.o.r.               12.2.16      
                         74 00 20 00  20 00                                  t. . .                         12.2.32      
  29.0            CTL    a1 21 00 00  00 00 07 00                            GET LINE CODING   2.0ms        13.1.0        //驱动程序开始接管,通过EP0控制设备。
  29.0         7  IN     00 c2 01 00  00 00 08                               .......           240us        13.2.0        
  29.0            CTL    21 22 00 00  00 00 00 00                            SET CTRL LINE ST  120us        14.1.0        
  29.0            CTL    a1 21 00 00  02 00 07 00                            GET LINE CODING   475us        15.1.0        //驱动程序控制第二个设备,这行与上一个不同的就是那个02,是wIndex
  29.0         7  IN     00 c2 01 00  00 00 08                               .......           142us        15.2.0        
  29.0            CTL    21 22 00 00  02 00 00 00                            SET CTRL LINE ST  108us        16.1.0        
  29.0            CTL    a1 21 00 00  04 00 07 00                            GET LINE CODING   596us        17.1.0        //第三个设备,wIndex 04
  29.0         7  IN     00 c2 01 00  00 00 08                               .......           176us        17.2.0        
  29.0            CTL    21 22 00 00  04 00 00 00                            SET CTRL LINE ST  157us        18.1.0        
  29.0            CTL    a1 21 00 00  06 00 07 00                            GET LINE CODING   599us        19.1.0        //第四个设备 wIndex 06
  29.0         7  IN     00 c2 01 00  00 00 08                               .......           148us        19.2.0        
  29.0            CTL    21 22 00 00  06 00 00 00                            SET CTRL LINE ST   91us        20.1.0        


看看整个配置描述符有273个字节之多。
其实只要把这些数据复制到你们设备描述符和配置里面去,插上USB,照样能认出4个虚拟串口,不过能不能实现功能就是另一回事了。

使用特权

评论回复
18
QuakeGod|  楼主 | 2016-12-16 22:27 | 只看该作者

将EP2_IN模式从INT改成BULK模式失败,枚举的时候,收到 8000600 bad pipe handle 错误

使用特权

评论回复
19
zhanzr21| | 2016-12-16 23:15 | 只看该作者
Good Job!

使用特权

评论回复
20
bowei181| | 2016-12-17 08:41 | 只看该作者
好强大呀,顶你,抽时间试试。太厉害了!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

1882

帖子

18

粉丝