打印

如何使STM32进行USB传输时提高传输速度?还请大家不吝赐教啊

[复制链接]
30602|30
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
alien2006|  楼主 | 2008-1-10 09:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    最近一直在学习USB,总算是稍微有点懂了。现在自己写的PC端USB驱动程序和应用程序终于可以成功实现STM32的BULK /INT传输和有数据/无数据传输控制请求等功能(STM32固件的程序我是用STM32 USB开发工具包中的UART范例进行的修改)。应用程序与STM32通讯测试基本没啥问题了,就是有关传输速度的问题一直比较困惑。
    STM32的USB接口是USB1.1的全速接口,进行BULK传输的时候,端点最大的包大小按照USB规范是64个字节,并且按照USB1.1FULLSPEED的规范,USB数据的传输是基于令牌的,也就是说假如设备打算要向主机发送数据,必须先由主机发送一个IN的令牌,设备收到令牌后,紧接着在其第二阶段送出要发送的数据,如此完成一个数据的IN操作。
    而规范上定义令牌发送的间隔是1毫秒,这样就意味着如果按照BULK传输最大64字节的规定,则最大传输速率是64字节*(1/1毫秒)=64K字节/秒。不过规范上也说到一个令牌后面可以跟多个USB传输事务,也就是个令牌(1帧)最大可以跟15个64字节的数据,1毫秒的间隔,这样可以达到64字节*15*1000 = 960K字节/秒的理论最大传输速度。
    现在假如我有一个4KB的数据要传输,现在我是分成多个64字节的请求进行传输的,在BUS HOUND5上看到传输的速度大约只有40KB/S不到,显然这个速度很不理想。我的问题是怎样才能在传输的时候在一帧内连续传输15个事务使STM32传输速度最快?在STM32的USB开发包中具体如何实现?有没有这样的程序范例能供学习下,还请大家不吝赐教,谢谢!
    
沙发
McuPlayer| | 2008-1-10 10:15 | 只看该作者

ST提供的例子速度就很快

每秒几百K字节是没有问题的

使用特权

评论回复
板凳
香水城| | 2008-1-10 10:56 | 只看该作者

要想真正提高USB的传输速度,必须在驱动中连续传输64字节的

也就是说,应用程序必须将较大的数据包交给驱动程序,由驱动程序把这个较大的数据包拆成多个64字节的数据包并发送出去;同理接收时,USB驱动程序必须先把多个64字节的数据包组合成较大的数据包,再交给应用程序处理。

关键的因素是应用程序与驱动程序的数据交换和调用转换是非常耗时的!

使用特权

评论回复
地板
ijk| | 2008-1-10 11:36 | 只看该作者

STM32进行USB传输时提高传输速度-建议

  首先,使用BULK传输来保证无差错的传输,这点应该没有疑义-已经做了。
  其次,建议把STM32的USB模拟成 Mass Storage的设备,从而自己可以不用写驱动程序,而借用M$的现成驱动。
  第三,STM32的Firmware端可以借用ST提供的参考代码-U盘的那个代码,从而可以模拟出来U盘。
  第四,PC端的应用程序可以自己编程,也可以使用ST提供的动态链接库(记得是storeacc.dll),该链接库在ST-LINK/ST-LINK2的驱动程序里面可以找到。假如PC端的应用程序自己编程也不难,可以用DeviceIOControl来做。
  目标是:速度接近USB Full speed的U盘的速度,800kB估计可以做到。

使用特权

评论回复
评论
pjzmj2012 2021-10-14 08:43 回复TA
我就是用的STM32的Mass Storage例程使用sdio接口的sd卡,但是数据传输却只有200Kb 
5
totoko163| | 2008-1-11 10:10 | 只看该作者

TO:接近USB Full speed

只考虑传输,还要考虑USB数据处理,强烈建议STM32内部RAM改为32-64K,价格不变..
    呵呵..

使用特权

评论回复
6
香水城| | 2008-1-11 10:20 | 只看该作者

增大RAM有何意义?没有地方存放数据速度快了也没用

按每秒一兆字节传输,64K字节的数据,只需63ms就可以传送完;按每秒600K字节传输也只需100ms多一点;所以增大RAM没有太大意义,必须增加大容量存储,如串行Flash或NAND Flash。

我们的8位单片机ST72F651只有5KB的RAM,做U盘管理NAND Flash,传输速度可以达到900K~1000K/s,经各种分析发现影响USB速度的瓶颈不是单片机本身,而是NAND Flash的速度不够快。

使用特权

评论回复
7
starm| | 2008-1-11 12:12 | 只看该作者

建议把STM32的USB模拟成 Mass Storage的设备

本帖最后由 STARM 于 2013-6-19 08:27 编辑

是否增加了协议开销? 不如直接使用bulk in/out来得快。

使用特权

评论回复
8
香水城| | 2008-1-11 12:18 | 只看该作者

starm:请说详细一些,为什么要把USB模拟成Mass Storage的设备

starm好久没有上来了,上哪里玩去了?哈哈~~~

不知您要把USB模拟成Mass Storage的设备做什么用?

使用特权

评论回复
9
alien2006|  楼主 | 2008-1-11 13:38 | 只看该作者

谢谢香版和大家

    PC端USB驱动程序部分我是实现了传输大数据时的拆分的,驱动的Write函数接收应用程序的WriteFile发来的IRP请求,如果发现数据长度大于设定的管道最大尺寸(64字节)则进行拆分,拆分成多个不大于PipeMaxSize的URB发送。
我用BUS HOUND对数据包的截图如下:

    
    这是我发送129个字节的情况,被拆分成2个64字节和1个1字节的数据块,并且是每个数据块发送一个URB(URB请求我理解似乎会对应发一个令牌)

使用特权

评论回复
10
alien2006|  楼主 | 2008-1-11 14:23 | 只看该作者

根据上面的情况推测

应该是令牌等所占的开销太大了,因此速度提不高大约只有33KB/S。后来把驱动程序中的PipeMaxSize改大,设定成512甚至更高,发现速度有了较大的提高,512时候最高速度是180KB/S左右,1000是240KB/S左右,甚至可以该成很大的值,设置成100K的时候速度超过500K,真是搞不懂了。这个值似乎是设置一个令牌后面的可跟最大数据域长度,按道理是不能超过1K啊。手头也没有USB协议分析器,无法知道具体怎么个传输情况,真是感到疑惑

使用特权

评论回复
11
香水城| | 2008-1-11 14:27 | 只看该作者

楼上是高级玩家

使用特权

评论回复
12
starm| | 2008-1-11 18:46 | 只看该作者

不知您要把USB模拟成Mass Storage的设备做什么用?

这个不是我的意思, 我是看到4楼的建议这样做。不过我还是认为自定协议效率高一些。目前我的一个项目用到了str710就是自定协议,用到一个bulk in ep1, 一个bulk out ep2 端点。还有一个bulk in ep3 端点用于返回str710的运行状态。通过ep0传送控制信息, 通过ep3报告状态。ep1 ep2用于传送大块数据。传输速度在 500-600KB/s. 进一步也可以再启用一个bulk out ep4来传送控制信息, 要比使用ep0效率高一些, 但是控制信息不是很多, 和使用ep0效果差不多了.

使用特权

评论回复
13
香水城| | 2008-1-11 18:53 | 只看该作者

原来如此,明白了。又来一个高级玩家!

12楼的ep3如果改成中断端点可能效率可以更高点。首先PC端在驱动里面直接发Token,不用应用程序干预,只当有数据时才通知应用程序;其次在Firmwire中不需要发状态时可以不理会PC的查询,节省时间。

使用特权

评论回复
14
alien2006|  楼主 | 2008-1-11 20:51 | 只看该作者

呵呵:)惭愧,我是菜鸟,这个坛子上好多专家,我得多多向大

简易示波器暂停了,主要是听取大家的建议,要把STM32的USB功能用起来,所以就开始学USB啦,等把USB搞明白之后再继续了。USB搞起来的难度可真不小,又是驱动程序的编写要学,又是固件编程,到现在也没搞明白。好在编程是件快乐的事情,哈哈~
    刚才又实验了下,现在驱动程序方面的速度瓶颈已经解决了。主要还是这个PipeMaxTransferSize的关系,这个值越大速度越快。晚上注意到这个值很多USB设备的驱动程序都是设的很大的,连HID设备都设成4096,我的一个U盘也是4096,KEIL的ULINK设置成65535,几乎所有USB设备驱动的端点0都是设成65535。晚上测试了下,这个值不会影响数据传输,这个最大值不管怎么设实际USB设备管道每次接收的数据该64字节还是64字节,应该是WINDOWS核心驱动层收到来自USB驱动的IRP后会自动拆包成与设备固件定义的大小(64字节)进行发送的。
    做了下速度对比
pipemaxtranfer:64---33KB/S
pipemaxtranfer:512--265KB/S
pipemaxtranfer:1024--349KB/S
pipemaxtranfer:4096--457KB/S
pipemaxtranfer:65535--506KB/S

又试着在STM32的固件上做了个改动 EP3_OUT的回调函数把缓冲拷贝的部分先注释掉,如下:
/*******************************************************************************
* Function Name  : EP3_IN_Callback
* Description    :
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
void EP3_OUT_Callback(void)
{
  //count_out = GetEPRxCount(ENDP3);
  //PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);
  SetEPRxValid(ENDP3);
}这2句先注释掉,使得STM32的EP3收到数据后不拷贝,直接发送接收有效,以测试最大速度,测试驱动程序pipemaxtranfer设置4096情况下USB最大写速度上升到822KB/S,在65535情况下998KB/S!。这样看起来应该驱动程序应该没啥问题了。
    接下来还得再研究STM32的USB固件,估计做下优化可能可以提高速度,比方说拷贝采用DMA方式,采用其他更加优化的端点缓冲方式等。因为我用的是STM32 USB开发包中那个USART-USB的例子进行的修改,应该是先天不足还有不少可以优化的地方吧。另外大家所说的Mass Storage那个例子应该速度在端点设置缓冲机制等等方面有值得借鉴的地方吧,打算晚上好好看看。另外在固件优化方面还请大家继续多出出主意啊:)


使用特权

评论回复
15
香水城| | 2008-1-11 20:58 | 只看该作者

楼上太谦虚了,您要是菜鸟,我只能是只不会飞的笨鸟

alien2006 加油! 

你现在所做的已经超出我的知识范围,除了喊加油我是帮不上忙了。但如果在Firmware方面有需要的话,小弟愿意效劳。

使用特权

评论回复
16
computer00| | 2008-1-11 22:55 | 只看该作者

哈哈,如果必须每一ms才能发一个令牌,那USB就白白浪费了...

一个帧里面可以有多个事务以及数据包...

使用特权

评论回复
17
McuPlayer| | 2008-1-12 09:41 | 只看该作者

USB要提速

1、使用自定义的Bulk传输
2、增加驱动的Buffer

使用特权

评论回复
18
hotpower| | 2008-1-12 09:49 | 只看该作者

哈哈~~~看来俺要尽快地加入USB扫盲班

学习~~~敬礼~~~

使用特权

评论回复
19
alien2006|  楼主 | 2008-1-12 10:46 | 只看该作者

应该是香版太谦虚才是啊,呵呵,您是大家公认的专家和技

又热心帮助大家,我也是从中学习了不少知识,实在是感激:)
    昨天晚上大致看了下Mass Storage的例子以及STM32的技术参考手册,晚上睡觉的时候仔细想了下(呵呵,发现好像睡觉的时候能安静思考)。
    主机向STM32发送数据的时候,传输的速度是457KB/S,而当我把STM32 用于接收的EP3_OUT回调函数中PMAToUserBufferCopy这2句话去掉的话速度就上升到了822KB/S,想来还是USB固件的处理速度限制了USB传输的提升,毕竟主机是每发送64字节就等待USB设备回应,当USB设备没有完成相应的操作时状态始终是NAK,于是主机就一直重发,一直到设备完成相应的操作将端口置VALID后主机才能接着发下一个64字节。从457KB/S到822KB/S(当然这个速度是纯粹的传输速度实际上接收后是还要处理的)速度差别还是很大的,应该还有办法提升的。
    上面几位说到改用MASS STORAGE的例子,大致看了下其实也是一样的,在BULK传输时候,都是采用一样的EP 单向BULK操作,64字节的管道尺寸,我现在的固件也是这样用的,没什么不同。问题不在于用哪个例程哪个设备类型,而应该在于怎么去提高BULK传输的处理速度上吧。
    昨天在看STM32技术参考手册的时候18.5.3提到了双缓冲端点,实现所谓PING-PONG机制,可以应用在同步和批量传输,我想把现有的EP传输方式改成双缓冲机制,应该能提高BULK的传输速度吧。刚刚找了下资料
   普通单缓冲机制的OUT过程:
1、主机发出OUT
2、设备接收该OUT包,检测缓冲区,当缓冲区由MPU占据时一直置NAK,主机不断重发数据包
3、当MPU放弃缓冲区占有(完成了相应的操作)后,置ACK,可接收下一个OUT包
4、主机发送下一个OUT包


    

使用特权

评论回复
20
alien2006|  楼主 | 2008-1-12 11:18 | 只看该作者

单缓冲模式就根单线程一样,

一个一个排队依次顺序执行,因此速度受缓冲区占用情况的严重影响,尤其当单片机处理速度慢时更严重。
    
    双缓冲端点机制:双缓冲机制有两块缓冲区在一个时间点上可分别由USB端点和MCU来占有
1、主机发送OUT1包
2、设备接收OUT1包并写入空闲的Buffer1,并置ACK,可以接收下一个OUT1包,同时buffer1的控制权可以交给MCU完成处理。
3、主机发送下一个OUT2包,设备将OUT2放入空闲的buffer2包,并置ACK,通知主机可以发送下一个OUT3包。
同时MCU继续完成上上一个OUT1包的处理后,释放BUFFER1的控制权,可以接下来占有buffer2进行处理
4、主机发送OUT3包,此时由于buffer1已经由MCU完成处理释放了控制器,设备接收OUT3包并放入BUFFER1中,置ACK,再通知主机可以发送下一个OUT4包
...
    由此可见双缓冲机制,依次交换2个缓冲区的所有权,看起来就类似与双线程一样,USB端点接收和MCU数据包处理是同时在进行的,减少了传输时候等待MCU完成接收包处理的等候,大大地提高了传输的效率。
    现在打算把BULK改成双缓冲试试,看看对速度能有多大改善。遗憾的是在MASS_STORAGE没有采用双缓冲机制。原理是了解了,不过还不清楚固件该怎么具体怎么编程,哪里有BULK双缓冲传输的例子可以学习一下?

    

使用特权

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

本版积分规则

16

主题

136

帖子

6

粉丝