windowsxp下usb驱动编写
⼀,概述
现在很多的主控上都带有USB的功能,但是对于初学者来说,这⽅⾯应⽤还是⽐较棘⼿,因为usb的不但固件程序需要编写,PC端的驱动也要编写,⽽且驱动写好了还要写个上位机才能看出效果。这样调试起来⼗分困难,建议从USB的键盘,⿏标开始做,了解清楚了,再做⾃⼰的协议就⽐较简单了。
USB的概念历史啥的这⾥就不说了。我们先不管具体的数据包格式,这⼀节先从整个包的层⾯上简单的说,过程是这样的,
---------------------------------------设备插⼊-------------------------------------------------------------
1) 主机会轮回查询各个USB端⼝,主机检测到D+与D-之间有电压差,就认为有新的设置接⼊。主机等待100ms后发出复位请求。设备接到复位请求后将产⽣⼀个外部中断信号。
---------------------------------------枚举过程------------------------------------------------------------
2) 主机这时候只是知道有新的设备插⼊了,但是不知道插进来个什么东西,所以就开始询问它是什么设备,怎么⽤,负荷能⼒怎么样。这个时侯就进⼊了枚举过程。因为刚刚插⼊的设备没有分配地址,就
⽤默认地址0,⾸先发送⼀个Get_deor(获取设备描述符)指令包,设备接到包后就开始解析包(其实就是你在固件程序⾥判断处理),然后按固定格式返回⾃⼰设备的设备描述符,这⼀步主要是主机知道你的USB设备的基础属性,⽐如⽀持的传输数据长度,电流负荷多少,⽀持那个USB版本,以及以后⽅便电脑驱动的PID,VID。
3) 这时候主机知道你(你做的设备,简称你吧)的数据长度还有电流⼤⼩后,下⼀步就是给你分配⼀个属于你的地址。
4) 给你⼀个地址后就开始询问你的具体配置。⾸先发送⼀个试探性的设备配置请求Get_configuration(要求固定返回9个设备配置字),你接到后就开始发送9字节的设备配置字,其中包括你的配置字的总长度,这样主机就知道你的配置到底有多长,然后再发⼀次设备配置请求,这时你就开始上传所有的配置字。这个时侯主机就已经很明⽩你的⼯作⽅式就各种特性,然后就可以正常⼯作了
5) 如果你在前⾯的某些配置(以后章节详细说明)要求要说明⾃⼰的名字什么的,这⾥还要上传字符串描述符。
6) 如果是⿏标或者键盘还要上传报告描述符
---------------------------------------正常数据阶段------------------------------------------------------
7) 这个时侯你已经被主机正式接受并且注册了,你可以通过⾃⼰写测驱动或通⽤驱动与电脑进⾏通讯了。
以上是简单的描述,详细的后⾯章节再做介绍,学习⼀个东西关键是⾸先要知道这个东西是什么,简单的⼯作原理。对于USB的⼯作我这⾥做个⽐⽅,
主机好⽐⼀个公司,你就是USB设备,要进⼊公司⾸先要⾯试(枚举),你到了⾯试现场(第⼀次插⼊设备),⾯试官⾸先了解到你的外表,性别已经你要应聘的岗位(设备描述符),然后给你⼀个号,以后就开始按号叫⼈,当你被叫到就开始问你的专业知识,性格等(配置描述符),如果你⽐较合适(通过了枚举)你就会录取了,并且注册⼀个你的信息到公司(驱动安装,并且写⼊注册表)。等你下次来公司,只要把⼯号(PID,VID)报上,就知道是你来了xp提交更改
USB初学2——数据包格式
对于USB传输⼤体有个概念,下⼀步就来看看到底USB上传的什么东西,以什么格式传数据,先不涉及端点的概念。
各种总线的数据传输都是以固定的层次协议进⾏的,USB当然也不例外。所谓的层次也只是个抽象的概念罢了,就是表达⼀种依附关系,上层要依赖与底层,上层以底层为基础,上层只需要关⼼⾃⼰的
东西就⾏了,如果你还不明⽩,那就继续看,学习⼀个东西不可能⼀两句话说的明⽩⼀个点,需要全⾯了解后才能清楚各个点。
要实现两个机器(机器的范围⽐较⼴,可以是电脑,交换机,单⽚机)的通信总是要有⼀个载体才可以,对于机器当然是电平⾼低为载体,具体的说机器甲要告诉机器⼄⼀件事情(⽐如说⼀条指令),那么机器甲可以通过⼀根线(串⾏数据总线)连到机器⼄的⼀个IO⼝上,甲发送⼀个个的⾼低电平,⼄固定时间检测⾃⼰的这个 IO⼝,然后逐个记录下放到⾃⼰的缓冲⾥,这样⼄就收到甲送的数据了。上述就是⼀个简单的数据链路层(计算机⽹络⾥这么叫)的描述,这⼀层要保证的就是甲发的每⼀位数据,⼄都可以正确及时的接受,并且对在传输过程中出错的数据做出反应。其实⽐数据连路更底层的还有物理层,这就是真正的物理介质,对于机器就是电线了,数据就是电线上传输的电压,USB是⽤的四线,两个电源,两个数据线。
这⾥也打个⽐⽅,⽐如⼈与⼈进⾏交流,我们当然是通过说话了,物理层就是空⽓和传输的声波,数据链路层就是我们说的每⼀个字,物理层就是空⽓,负责把我们说的话转换成声波传给对⽅,数据链路层负责让对⽅能正确的听到每个字,如果听的不清可以告诉对⽅重新说⼀遍。
经过上述的两个底层,就可以保证每⼀位数据可以正确的传到对⽅那⾥去。下⼀步的⼯作当然是解析数据代表了什么,⼀般来说,数据都是以⼀串数为单位,⼀般称为⼀个包,机器间传输都是以⼀个包
为单位传出,就像⼈们说话都是以⼀句话为单位输出⼀样。每⼀个包包含有许多位数据,这些数据⼜分段表⽰不同的意义,如图⼀,这是⼀个USB令牌阶段的包,Sync是同步数据(相当于说话时先打个招呼,告诉对⽅要跟他说话了),PID是包标⽰(告诉对⽅这个包是⼲什么⽤的),ADDR是对⽅的地址(叫对⽅的名字),ENDP是⽤端点⼏通讯(先不介绍这个),CRC5是校验位(判断这个包是否在传输中出错),EOP是包结束。
|--------------------------------------------------------|
| Sync | PID | ADDR | ENDP | CRC5 | EOP |
|________________________________________________________|
图⼀
USB 的数据包⼜分为三种,⼀个是令牌包,⼀个是数据包,另⼀个是握⼿包。每⼀次的USB通讯事务处理都是以令牌包开头,告诉对⽅要跟谁说话,这句话是⽤来⼲嘛的。如果要求有数据传输,则下⼀步就是数据包,另外如果要求对⽅要有反馈,则会发出握⼿包。令牌包⼜简单的包括OUT,IN,STEP三种类型,OUT是⽤于主机告诉设备主机要向USB设备发送数据,IN是⽤于主机告诉设备要上传数据,⽽STEUP是⽤于主机向USB设备发送配置信息,在枚举过程中会⽤到。另外数据包和握⼿包的具体格式什么的,可以参照详细的协议。
可以看到在所以的通讯过程中,主机都是发起者,不管是主机发送数据到USB设备还是USB设备发送数据到主机,都必须收主机控制。图⼆为⼀次事务的过程
令牌阶段 ——》 数据阶段 ——》 握⼿阶段
图⼆
这个过程可以这样描述,甲和⼄对话,甲是⽼板,⼄是职员。第⼀节已经讲过了,⼄⾯试就是枚举,在这个过程中,甲多段的发送STEP令牌包给⼄,⼄收到后如果要反馈数据,就发数据包给甲,甲正确接收后,跟甲握握⼿,表⽰这次对话成功。
⼄被正式录取后,甲会分派任务(OUT),这时甲对⼄说有任务给你(令牌阶段),然后⼄就开始听,甲说你的任务就是记录数据并且上报(这段话就是数据包),⼄说好的(握⼿包)。
⼄开始正式⼯作,并且记录数据。过了⼀段时间,甲开始要求提交数据(IN),⼄把数据报告给甲(数据阶段),甲说好(握⼿成功)。这⾥⼄不能主动的去向⽼板汇报,只能被动的⼲活。
上⾯已经讲USB主机和设备间数据传输的过程,都是我个⼈理解,有不正确和不到位的⼤家提出,⽅便初学者理解,谢谢··
USB初学3——USB通讯设备快速开发
⼀,设定规划
凡事预则⽴,不预则费,所以开发⼀个⼩⼩的USB也要稍微规划⼀下,⽐如想象要实现什么功能,传输的数据协议什么的。
⼆,固件编程,
固件编程说⽩了就是写单⽚机程序,要实现USB⼀般可以使⽤带USB功能的单⽚机,再个就是加⼀个专⽤的USB芯⽚。这⾥以内部集成USB功能单⽚机为例
固件的USB开发⼀般就是先使能USB,使能USB时钟,使能各个USB控制中断(挂起,复位,标准请求,写⼊,写出等)然后USB就能正常⼯作了,这时候不如不写别的东西,电脑就可以检测出有USB设备插⼊了,具体的反应是在设备管理器⾥会发现闪了⼀下说明发现了新的USB设备,接下来电脑会发送各种标准请求,因为这个时候你的程序还没写完整,对这些请求不会有反应,所以电脑不可能识别出是什么东西。
接下来的⼯作就是在中断中响应电脑传来的各种标准请求。当必要的请求都被正确的响应的话,这个时候如果电脑⾥有正确的驱动,电脑就会去加载这个驱动,如果是第⼀次插⼊这个设备,还要把驱动安装⼀下,然后设备就进⼊正常⼯作了,电脑会显⽰“这个USB已经成功安装并可以应⽤了”。
这⾥捎带着说⼀下端点(endp oint)的概念,⼀般⼀个USB设备都会有数个端点,端点就是⼀个数据缓冲控制区(FIFO),每个缓冲区相当于有⼀个出⼝⼀个进⼝的池⼦,数据通过进⼝进⼊到池⼦,然后你再在固件⾥去⽤这些数据。固件往电脑写数据,也是把数据先放到池⼦⾥,然后打开出⼝,就可以⼲⾃⼰的事情,不⽤⼀个个的把数据发出了,池⼦的出⼝⾃动把数据流出。
⼀般的端⼝0是⽤来做标准请求响应⽤的,也就是在枚举阶段⽤到。我⼀般把端⼝1定义为出(OUT),端⼝2定义为⼊(IN)(注意,这个OUT和IN是相对与电脑的,也就是说OUT是数据从电脑出去到设备,IN是设备的数据进⼊电脑)。这些定义也是在标准请求中去告诉电脑的。
接下来就可以实现与电脑的通讯了,你把数据放到相应的池⼦⾥就⾏了。下⾯就可以⾃⼰定义通讯的数据格式了。⽐如控制开发板上的8个LED的第⼀个灯亮,那么上位机发送数据0x55,0x01,0x80,0xaa。我们就可以规定第⼀个数据是启⽰位,遇到这个表明开始⼀次控制指令,0x01表⽰这个是控制灯亮暗的指令,0x80表⽰LED的控制数据,最⾼位是1,表⽰第⼀个亮,其他位是0,表⽰都暗。最后⼀个数据是0xaa,表⽰这是结束。其实所谓的数据协议不过就是⾃⼰定义的⼀套让通讯双⽅都能正确理解对⽅的数据格式。电脑⽐较是电脑,什么都要规定好了,它才能正确的⼯作。
⼆驱动程序
对于快速开发⽤Driverstudio就可以了,我先装了VC6.0,然后装了DDK2600,最后装了Driverstudio,
⽹上有说这个顺序不容易出问题,我也没时间去试别的顺序会出怎么样的特效,姑且不管他是否在忽悠,先这样按了没坏处。
我⼀开始⽐较新潮的装了DriverStudio3.2版本,然后按⽹上的⽅法破解了,⽣成了驱动是能打开设备,但是就是传输不了数据,搞了两天还是不⾏,后来想到是不是3.2版本太新了?或者破解没完整?然后卸载了3.2装了3.1,果然可以了,真不知道是Compuware做了⼿脚故意玩我还是本⼈愚笨弄错了哪⾥。
1.启动Visual C++ 。
2.选择菜单 File|Open Workspace。打开位于DriverStudio/DriverWorks/Source/vdwlibs.dsw的⼯作空间⽂件。
3.选择菜单 Build|Batch Build,在弹出的对话框中选择你想编译的库。
4.点击Build编译你选择的库。
然后在VC的Driverstudio的⼯具条点击“change environment variables”,在第⼀个选型卡把DDK的路径选上,我的是
C:\WINDDK\2600。然后点OK,接下来点DriverStudio⼯具条的编译,就可以了,如果你还是碰到问题,你可以把VC显⽰的错误复制到百度。
usb设备描述符,usb请求,usb中断在固件中的处理框架
如果你对usb描述符和usb标准请求有⼀个⼤体认识,并仔细了解了你所⽤芯⽚对usb中断处理⽅式,那下⾯的内容或许对你会⼀些帮助。对usb描述符中要说两点,⼀.配置描述符,接⼝描述符,端点描述符三者是⼀起返回上位机的,接⼝描述符与端点描述符不能单独被返回。
⼆.usb是⼩端模式,注意wLength,wIndex,wValue这些双字节位域的赋值问题。
三.usb固件以usb中断,usb请求和usb描述符为基本框架进⾏编程,usb中断怎么处理各芯⽚会有差别,但⼤体都是产⽣usb中断后,固件进⼀步判断某⼀寄存器各个位来断定当前是usb何种中断,假设当前产⽣的是setup中断(端点0),那接下来就进⾏setup中断处理,在setup中断处理中我们就要通过标准请求来处理各种描述符。
void USB0_ISR(void) interrupt 8(这⾥的interrupt 8是C8051F340对中断的处理⽅式)
{
读相关寄存器来判断具体是usb何种中断
{
if 恢复中断
{
调⽤恢复中断处理函数
}
if 复位中断
{
复位中断处理
}
if setup中断
{
Handle_Setup(); // setup中断处理
}
挂起中断,端点中断(包括除端点0外不同端点的输⼊/输出中断,视具体要求)
}
//setup中断处理
void Handle_Setup(void)
{
1.从buffer中读取上位机发来的setup包
2.读取setup包各域进⾏分⽀处理(虽然过长的switch case不是好的编程思想,但是当⽤单⽚机做开发时考虑到单⽚机有限的存储空间,还是选switch case最合适)
switch(Setup.bRequest) //对标准请求中bRequest域进⾏判断处理
{
case GET_STATUS:
Get_Status();
break;
case CLEAR_FEATURE:
Clear_Feature();
break;
case SET_FEATURE:
Set_Feature();
break;
case SET_ADDRESS:
Set_Address(); //设置地址
break;
case GET_DEOR:
Get_Deor(); //获取设备描述符,你把准备好的设备描述符写到buffer⾥,等待上位机读buffer break;
case GET_CONFIGURATION:
Get_Configuration(); //获取配置描述符
break;
case SET_CONFIGURATION:
Set_Configuration(); //设置配置描述符
break;
case GET_INTERFACE:
Get_Interface();
break;
case SET_INTERFACE:
Set_Interface();
break;
default:
Force_Stall();
break;
}
}
setup其它的域,wLength,wIndex,wValue在各描述符中处理。
各描述符的处理函数可放⼀单独⽂件中统⼀管理。
接下来写各除端点0的各端点的输⼊/输出中断处理函数以及读写buffer函数

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。