wangweixd
驱动牛犊
驱动牛犊
  • 注册日期2009-11-02
  • 最后登录2009-11-02
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望11点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2550回复:6

ARM9平台AT91RM9200 USB device开发及PC端应用程序开发心得

楼主#
更多 发布于:2009-11-02 19:54
最近一个多月一直在做这方面的事情,对USB从一点不懂到最后写出了符合老板要求的程序,也算是颇有心得吧,跟大家分享下。本文不涉及太过具体的编程,因为如果直接把几千行的源代码贴出来,没做过USB的朋友估计直接就晕了。

1.概述

     USB作为PC上应用最广泛的外设接口,对用户来说是非常方便的,一插就能用;但对开发人员来说,做起来就有点复杂了,USB相对串口来说复杂度完全不是一个层次上的。

     总体来说,USB开发分为两大块,嵌入式设备(比如ARM)端的firmware开发,和PC端驱动程序的开发。我要实现得目标也很简单,让我们自己的板子能和电脑进行通信就行了。项目开发的时候程序严格按照SDL结构化编程来走,因为实现的是某通信协议,类似IP,协议里常用SDL图来描述,这是个结构很清晰的编程方法,可以算是加强版的流程图吧,做过802.X同学应该都对这玩意熟的不能再熟了。

     做USB的必须对USB协议非常熟,不要被300多页的英文协议吓到,虽然我刚开始看的时候也是两眼一摸黑,但是其实要看的东西不多,主要是设备枚举和数据包的握手机制,明白USB设备是怎么被PC检测到(发送各种各样的描述符,比如设备描述符,接口描述符等),每次传输的过程是怎么进行的。

     USB有几个基本的概念,第一是HOST和DEVICE,如同其名,HOST是主,Device是从属,Device完全没有主动权,一切在HOST端操纵下执行。日常的PC,就是HOST,U盘MP3等等都是Device,两个设备之间是不能通信的。当一个USB设备想要发数据给host时,它不能主动发起,比如收到HOST给出的“发”命令后才能把数据发出去。

      还有一个容易让人搞晕的是端点,即EndPoint。USB是半双工的总线结构(3.0是不是我不清楚),也就是同时刻要么是HOST发向Device,要么是反过来,为了把某种功能的传输抽象,于是有了端点的操作,比如控制端点专门用来传输HOST对设备的控制信息,In端点专门用来向HOST发送数据,Out端点专门用来接收HOST发过来的信息。由于USB传输分好几种,有用于保证大批量数据传输的Bulk方式(可以保证数据完整的发过去,有检错重传机制),还有用于保证时延的等时传输(比如用在语音和视频流上,可能会丢包)还有能保证立刻性的中断传输(其实是疯狂的轮询,但人家就叫中断)。所以一个设备上可能有好多个IN和OUT端点,控制端点一般就只有一个,而且只有控制端点是双向传输的,其它端点只能单方向传输。

    为了区分不同的端点,端点有一个地址,英文用的是Address,而不是Number,所以要区分开端点地址和端点号之间的区别,端点号+传输方向=端点地址,因为有的设备允许一个端点号有两个传输方向,但是只有取定方向之后的才是实际意义上的端点。更晕的是,像ARM这样的设备,很多时候一个端点号只能有一个方向。

     由于一个HOST接口允许通过USB hub扩展127个USB设备,说实话,没见过扩超过4个的,多了还想活不?所以每个设备有一个地址,地址0用于和刚插上去的设备通信,枚举完成后就有了专有的地址,接下来就是在操作系统里注册这个设备,加载对应的驱动等等。

2.目标

   短时间内开发出速度达标(所谓达标就是越快越好),没有BUG(不可能的,越少越好)的USB通信程序,要求对PC和ARM端跑的应用程序提供透明的数据传输管道。对PC端应用层程序提供三个函数结构,GetTxReq(获取ARM发过来的信息),TxCfm(向ARM发送确认信号),RxInd(向 ARM端发送信息);对ARM端应用程序,提供TxReq(向PC发送信息),并在收到PC发过来的信息(包括确认信息和数据)后,向上层应用程序发送 Signal。

3.ARM端

    需要的设备,PC一台,板子一块,USB线一根。还有最重要的,USB总线分析仪,对于熟手来说这东西不需要,但对于完全没做过USB的新手来说,没有它是不可能开发出USB设备的,USB总线上信号频率48MHz,而且还是用不归零码编码的,外加一堆乱七八糟的信令,想用逻辑分析仪或示波器看是不现实的。

    USB从某个角度上来看和I2C总线相似,比如都是两根数据线,都是主从结构,靠地址来寻找设备,等等。看过周立功的I2C程序的朋友应该记得I2C的状态码都是在中断里面处理的,USB也是,USB设备收到信令后都会引起中断,然后进行相关的处理。

    枚举。枚举就是一个usb设备插到host(比如电脑)上之后,被HOST识别并注册的过程,电脑不可能知道没插上去的设备长啥样,所以这些信息都是电脑找设备要的,就跟找工作差不多,HOST问设备,你是男的还是女的,DEVICE说我是男的;HOST再问,你是本科的还是专科的,还是研究生,然后设备再说@#%*&*;问完之后就签约了,如果ARM端固件没写好,对HOST的枚举要求不响应,那就会爆出个“无法识别的USB设备”这样的信息。

        枚举的过程是USB设备端程序最为复杂的一段,因为没碰过USB设备的人在做USB的时候,最开始遇到的就是设备无法识别,只要能枚举,ARM端得程序就算写了一半了,要想最快速度的搞定枚举,USB协议里面关于枚举的章节必须看的能背下来,这样才能分析总线分析仪截获的数据包对不对。双缓冲。由于USB 控制器对ARM来说是个外设,有个FIFO,ARM核心往里面写东西,然后USB控制器把它给发出去,很明显ARM正在写的时候不能发,不然发个一半过去算啥,所以如果只有一个缓冲的话,USB总线会有一半时间是空闲的。为了解决这个问题,用双缓冲,乒乓方式工作,乒乓方式嘛,轮着来,我写A,你发B,你发完了B,我A也写完了,所以两边都不闲着,USB控制器不停的发,ARM核不停的写。但是这里面有个需要注意的问题,刚开始的时候,程序必须是这样的:写缓冲A,就绪缓冲A,写缓冲B,开发送中断,不能都写了才就绪,否则USB控制器不知道该发哪一个。发送完成后,设备收到主机的ACK信号进入发送完成中断,终端里面就绪刚才写好的缓冲B,同时填写下一包,当剩下最后一包的时候,需要关发送中断。

4.PC端

      这个是很让人纠结的程序,最能体现出高手和菜鸟的区别,因为PC端的USB驱动本质上是WINDOWS的一部分,所以写起来很难,把PC搞得蓝屏死机是很随意的事情。高手可以用DDK写出专用的驱动,实现最高的速度,和最小的体积。

      由于对我来说,USB的驱动是谁写的不重要,重要的是实现传输数据的功能,所以驱动本身并不是研究的重点,总共才给了一个多月的时间,拿来入门DDK都不够,所以直接我就放弃了。

      USB的PC驱动都是一个萝卜一个坑,一种设备一种驱动,像U盘这东西微软早就把驱动写好了,根本不用操心,但这驱动没法拿来用。我们有周立功给 ISP1581USB接口芯片写的驱动,刚开始的时候就是把自己的设备伪装成ISP1581来通信,也确实实现了,问题就是,速度太慢,而且同样的设备只能插一个。慢点还能忍受,后面那个问题直接就把它KO了。

      接下来的选择是DriverStdio,宣传的很好,什么好用如同MFC,纯属胡扯,版本多如牛毛不说,还要写一大堆的代码,我要是会写这些代码那就直接去用DDK了,所以在这上面折腾了三四天之后放弃了,DriverStdio本身也已经被微软给招安了,一堆得Bug不用指望有人来做支持。

      在我马上就要崩溃的时候,曙光出现了,无意中记得有人提过Windriver,这名字不好,拿来google的话,搜出来的都是Wind river,大名鼎鼎的vxworks就是他们的产品,跟WinDriver一点关系都没有。拿来一试,可以直接识别设备并产生驱动,狂喜啊。 Windriver把很多种设备抽象的提供了一种驱动,相当于在操作系统和用户应用程序之间加了一层,所以安装它生成的驱动有点奇怪,要敲命令。不过这完全不能掩盖这款软件的优秀。

      我从它的公司Jungo上下载了试用版,v10.1,可以直接生成适用于从win ce到linux,从win98 到win vista得驱动,而且读写代码直接提供的是vc6,vs2003,vs2005,vs2008,borland^^^^^^^的工程,可以直接编译的那种,不得不佩服这家公司的强大与细心,要做就做到最好最方便。它的代码里其实只需要掌握两部分,一是设备插上去是怎么获得设备句柄的,而是接口函数的用法,软件附带的manual详细的不能再详细了。如果说有缺点的话,那就是这软件太贵了,正版要几千美金,所以我无耻的选择了破解版,在此表示对软件作者团队的歉意。

      下载试用版的时候,我留了真实的电话和邮箱,没想到该公司的亚洲总代直接从台湾打了电话给我,台湾MM的国语听着真好玩,“作业系统、**位元”听着还真有点奇怪,该公司的技术支持Nadav Shner也认真的回复了我那蹩脚的英文写的邮件。

      windriver的借口函数支持多个设备,而且是multi-thread safe,可以为每个设备创建一个发线程和收线程,每个设备有独立的接受和发送缓冲区以避免多线程切换的问题。而且该驱动的效率非常的高,实际试验的结果是,对于USB2.0全速的设备,可以达到8Mbit/s的速度,而理论值是9.*Mbit/s,多个设备同时工作时,几乎没有性能的下降,如果时间紧迫的话,WINdriver是很完美的选择。

5.后记

     这一个多月下来收获还是蛮大的,首先做工程的时候,不能有尽善尽美的想法,必须分成一块块的做,否则N久见不到成果,会有严重的挫败感。其次,黎明前的黑暗这话绝对不假,凡是到了让人快崩溃的时候,曙光基本就差不多了

最新喜欢:

ilyb11ilyb11
fishly_0
驱动小牛
驱动小牛
  • 注册日期2005-09-10
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分51分
  • 威望466点
  • 贡献值0点
  • 好评度86点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2009-11-05 15:30
顶,我非常赞同你的后记的观点!
usbwolf
驱动牛犊
驱动牛犊
  • 注册日期2009-10-27
  • 最后登录2010-01-18
  • 粉丝0
  • 关注0
  • 积分25分
  • 威望231点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2009-11-05 16:18
请问楼主,10.1的序列号到哪里整啊
cfqxd
驱动牛犊
驱动牛犊
  • 注册日期2009-09-02
  • 最后登录2009-12-25
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望61点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2009-11-26 21:22
回 2楼(usbwolf) 的帖子
我没有10.1的序列号,但是有10.0的,你要的话我可以给你一份,我的邮箱cfqxd@163.com
yejin1999
驱动牛犊
驱动牛犊
  • 注册日期2009-11-24
  • 最后登录2010-05-14
  • 粉丝0
  • 关注0
  • 积分37分
  • 威望321点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2009-12-11 21:54
楼主你好,最近我在做arm端linux usb device驱动程序开发,需要同时开发windows主机上的usb驱动,利用了vs+ddk+driverstudio生成了驱动的框架,在加载的时候出现了问题,请您帮帮我,小弟跪谢!问题如下:
(1)我在arm准备好驱动的模块后,windows 主机上显示找到新硬件,然后我一步步安装利用 driver studio生成的驱动,安装不成功,提示错误:“无法打开设备”,然后在硬件设备列表里此设备上有一个黄颜色的感叹号,请问这是代表驱动不对还是主机没有获得完整的设备信息?
(2)我在arm端加载device驱动模块的时候,一个函数setup(struct gadget *,struct ctrl*)被反复调用,我看源码发现这个函数是根据其参数struct ctrl* 来执行各种不同的操作,我想请见你这个参数是哪里来的呢?另外这个setup()函数是被谁调用的呢?
(3)当windows 主机上出现无法打开设备的错误提示时,arm端的一个函数suspend()被调用,这是因为驱动安装失败导致的吗?
(4)有没有什么手段可以检测usb总线上的传输信息?

另外,楼主,我想给你发短消息一直操作失败,所以你能不能把你的邮箱或QQ给我,我想以后继续请教请教你,感激不尽!请帮帮我

         谢谢帮我解答一下,感激不尽!
cfqxd
驱动牛犊
驱动牛犊
  • 注册日期2009-09-02
  • 最后登录2009-12-25
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望61点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2009-12-25 16:25
回 4楼(yejin1999) 的帖子
1.获得设备信息后,如果你用VISTA,设备管理器里可以看到设备的PID,VID
2.这个参数是控制端点接收到的,也就是建立过程HOST发给设备的
3.不清楚,但你的驱动肯定有问题。
4.USB总线分析仪。我的QQ 549508985
ly8
ly8
驱动牛犊
驱动牛犊
  • 注册日期2006-07-29
  • 最后登录2009-12-31
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望51点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2009-12-31 13:03
好贴,顶一下。
游客

返回顶部