USB转串口(CDC协议)实现原理

发布: 2009-9-15 03:14 | 作者: simonqian | 来源: StmFans思蜕盟 OPELC 自由电子联盟

[i=s] 本帖最后由 simonqian 于 2009-9-15 03:40 编辑

今天看了一下ST的USB转串口固件,怎一个垃圾了得。。。。。。还好当初做这个的时候没有看ST的代码。

我也提出我自己的实现方式 -------- 全中断实现方式。

1. 数据流
USB转串口存在2个数据流(除控制端点以外),一个是USB_OUT(PC发送数据) -->> USART_OUT(串口发送数据),另一个就是USART_IN(串口接收数据) -->> USB_IN(PC接收数据)。涉及到USB和USART接口,其中USB的速度是可以控制的(通过发送NAK,可以让主机发送数据的速度减慢)。
USB_OUT(PC发送数据) -->> USART_OUT(串口发送数据)中,USB_OUT的速度是可控制的,USART_OUT的速度也是可以控制的(肯定是一个字节发送完成后再发送下一个)。这样,就不会存在问题。
USART_IN(串口接收数据) -->> USB_IN(PC接收数据)中,USB_IN的速度同样是可控制的,但是USART_IN的速度并不是STM32(主控芯片)可以控制的(不用偶解释为虾米了吧),那么系统性能瓶颈就在USART_IN上。其他部分是不会丢数据的。
在921600的baudrate下,USART_IN的触发周期在11us左右(实测12us以上)。如果是STM32支持的最快4.5M的速度的话,那么触发周期在2.2us。这时,所有其他处理都要为接收串口数据让步,否则会丢失数据。

2. 中断处理
我使用这种方式:USART的中断可以打入USB的中断,USART的中断处理其实很短,接收数据的话,一般在1us以内,不会影响USB功能。
数据发送中断(USB_IN、USART_OUT):简单判断相应的发送缓存中是否有数据,有的话,发送下一个。
数据接收中断(USB_OUT、USART_IN):把数据放入缓存,如果相应的发送正在进行的话,返回;否则启动数据的发送。

3. 缓冲方式
可想而知,这里使用的是圆形缓存,接收到数据,放入缓存,并修改head指针和有效数据长度,发送完数据,修改tail指针和有效数据长度。
需要注意的是要严格控制临界点,以防访问冲突。

4. 简单的测试
我这里最快只测试过921600的速度,我这里没有其他设备能够使用更高的速度了。
用上位机下载MTK手机平台的固件(12+MB)的时候,最终速度为42KB/s左右(没有进行太多的优化),而是用FT2303时,速度大概在45-47KB/s左右,这个性能还是很满意的,以后又时间再优化。
我这里使用的硬件是http://www.SimonQian.com/en/Versaloon中的硬件。

5. 额外功能
Windows下,USB转串口(CDC)是需要个inf驱动文件的,那么可以在STM32上再通过IAD的方式实现一个U盘,用于存放驱动,这样就可以做成一个无驱型USB转串口了。这个同样也是完全基于中断处理的。当然,由于STM32芯片Flash的限制,模拟出来的U盘容易只有几十K字节而已,放一个驱动是足足有余了。
binglin (2009-9-15 08:26:15)
好文章,ST的USB转串口固件,似乎在USB_OUT(PC发送数据)也就是STM的USB_IN环节有问题,当然其它地方问题也不少。

正如楼主所说,可能自已来实现效果会更好一些。
catwill (2009-9-15 16:55:10)
楼主高手~~~~
simonqian (2009-9-16 00:28:29)
实现原理应该是没有问题,但是,我目前的方案也确实还有一些问题。
系统会以一个很小的概率出问题,有时可以恢复,有时不可以恢复。
当然,不排除是固件库的问题,毕竟自己使用的是最早发布的1.0版本的USB固件库。

最近有空的时候,想把固件库(包括USB固件库)升级到最新版本再试试。
simonqian (2009-9-16 04:39:49)
对于环型堆栈的一些改进,去掉length部分,因为读取和写入都会修改这部分,会增加系统的临界点。
binglin (2009-9-16 08:13:42)
在PC机这上面的程序,对于缓冲区这块,我比较喜欢用指针来做循环队列来作缓冲区,如果单片机用指针来做循环队列,不知道这样做出来后应用的壮键性有没有受到影响。
simonqian (2009-9-16 12:43:47)
循环队列适用于这个情况,数据的写入和读出的速度差别会比较大。
另外,循环队列不存在健壮性的问题,robust要在代码的各个细节里都考虑的。
simonqian (2009-9-17 06:33:54)
[i=s] 本帖最后由 simonqian 于 2009-9-17 06:42 编辑

发现了原来出问题的原因,循环堆栈没有问题,临界点也没有问题。。。。。。
好像是USB驱动部分的问题:

说明:
第一根是USB中断,高电平表示正在运行中断。
第二根是USB中断的接收数据部分。
第三根是USB中断的发送数据部分。

正常波形:


normal.jpg



出错波形:


abnormal.jpg



当一个USB发送中断和接收中断靠太近的时候,会使得后面的中断得不到相应,正在看驱动代码,找问题。
simonqian (2009-9-17 21:21:30)
问题似乎解决了,ST的库或者芯片确实可能有问题。