精华内容
下载资源
问答
  • USB设备驱动程序开发

    2020-11-07 02:58:17
    由于其众多的优点,USB总线越来越多的被应用到计算机与外设的接口中,芯片厂家也提供了多种USB接口芯片供设计者使用,为了开发出功能强大的USB设备,设计者往往需要自己开发USB设备驱动程序,驱动程序开发一直是...
  • USB设备开发流程

    千次阅读 2019-01-05 17:41:01
    USB设备开发一般包括主机端(上位机)驱动程序的开发(如果您的USB设备符合某一标准设备类且主机端已经提供了此类设备的驱动程序的话,则可以省掉此步骤)和USB设备端驱动程序的开发,有时还可能包...

    转自

    http://www.baiheee.com/OpenSource/Easy%20USB%2051%20Programer/Easy%20USB%2051%20Programer2.htm

     

    USB设备的开发一般包括主机端(上位机)驱动程序的开发(如果您的USB设备符合某一标准设备类且主机端已经提供了此类设备的驱动程序的话,则可以省掉此步骤)和USB设备端驱动程序的开发,有时还可能包括主机端应用程序的设计工作。

    1、设备系统需求分析

      设备系统需求分析是进行USB设备设计的第一步,通过对USB设备功能特性和USB主机端操作系统的分析,可以获得实现该USB设备的软硬件设计需求。

      在该阶段,设计者需要充分了解该设备的应用环境(如USB主机的软件、硬件平台),这样以用来确定是否需要提供USB主机端相关软件工作,以便该设备能得到广泛地应用。为了提供合理的软硬件设计方案,设计者还需要充分了解市场上的USB接口芯片,不同的USB接口芯片在USB协议上有着不同程度的支持,比如,对数据包地址的硬件自动识别、CRC16CRC5的自动生成等等。

      当然,在确定具体的软硬件需求时,产品的开发费用和开发周期也是必须考虑的因素。

    2、设备硬件需求

      通过设备系统需求分析,以及对市场上USB接口芯片的充分了解,设计者必须确定相应的设备硬件结构以及可能采用的硬件。在选择器件时,需要考虑到器件体积、功耗等,因为,小的设备功耗,有利于采用总线供电模式。必须通过设备系统的功耗来确定是否需要提供本地电源。  

    3、设备软件需求

       在确定了设备的硬件结构以后,该设备的软件结构就会同时产生。不同的硬件平台,可能需要不同程度的软件支持。

    4、设备硬件设计

      在选定USB控制芯片以后,如果是带USB接口的单片机,则是一般单片机应用系统的开发;反之,就是如何把USB接口芯片与单片机应用系统融合的问题。一般USB接口芯片都支持多种并行总线结构(复用/非复用),可以方便的与多种单片机接口。硬件设计中要注意的就是USB接口芯片的时钟速度比较高,所以匹配网络的设计以及PCB布线要特别关注。

    5、设备软件设计

      USB设备的软件设计主要包括两部分:一是USB设备端的软件开发,主要完成USB协议处理与数据交换以及其它应用功能程序。二是主机端的程序,由USB通信程序(驱动程序)和用户服务程序两部分组成,主机端用户服务程序通过USB通信程序(驱动程序)与系统USBDI(USB Device Interface)通信,由系统完成USB协议的处理与数据传输。主机端程序的开发难度比较大,程序员不仅要熟悉USB协议,如果需要开发主机端驱动程序的话,还要熟悉主机端操作系统(如常用的WINDOWS系统)体系结构并能熟练运用DDK工具(驱动程序开发工具)。

    6、设备调试

    要快捷、成功的开发一个USB设备,正确、合理的调试方法是必不可少的环节。调试基本分三步进行:首先对外部设备(单片机部分)借助PC调试软件(常用的有:bus houndUSB MONITOR,某些芯片生产商还提供针对特定芯片的调试软件)将设备端的USB协议(主要有描述符请求、端口配置、地址设置以及基本数据交换)调通(当然我们还可以使用USB分析仪等开发设备,但此类设备一般比较昂贵)。然后,用调试好的USB设备接口来开发、调试PC软件,这一步相对比较容易。最后,加上USB设备端的其它用户程序,对整个完整的系统进行系统调试。

     

     

     

    了解USB的通讯过程

    USB的两根信号线负责与总线上的设备交换数据。这些电缆形成了所有设备必须共享的惟一的一条传输通路。 RS-232有一条Tx线用来传输一个方向的数据,一条Rx线用来传输另一个方向的数据。与RS-232不同,USB的一对电线只传输一个不同的信号,不 同方向的信号要按顺序来传输。

      因为所有的传输共享一个数据通道,所以每一个事务必须包括事务的源和目的地址。每个设备有一个由 主机分配的惟一的地址,所有的数据都是流向主机或从主机获取。每个事务都是以主机发送数据块开始的,这个数据块包括接收设备的地址以及设备中被称为终端的 一个特殊位置。一个设备发送的每个数据是为了响应从主机接到的请求而发送的接收到的数据或状态信息。  

      USB通信分为两类,根据它们被用于原始配置还是应用中。在配置通信中主机通知设备,设备收到通知后准备好交换数据。大部分这类通信发生在上电或连接时主机检测到外设的时候。应用通信出现在主机的应用程序与一个检测到的外设交换数据的时候。这些是实现设备应用的通信。例如,对鼠标来说,应用通信是发送点击动作给主机,主机端应用程序接收到这个动作后执行相应动作。

    配置通信

      在检测过程中,设备的固件对主机的一系列标准请求做出响应。设备必须识别出每一个请求,返回被请求的信息。

      在PC上,Windows执行检测工作,所以不涉及用户编程的问题。然而,为了完成检测工作,Windows必须有两个可用的文件:一个识别这个设备驱动程序的文件名和位置的INF文件和设备驱动程序本身,如果您的项目符合某种通用设备类,则操作系统可能已经提供了此类设备的所需的这两个文件,而不需要开发人员自己提供。

      根据设备以及设备将被如何使用,设备驱动可能是如下两者之一;Wlndows自带的或芯片或外设厂商提供的。INF文件是一个文本文件,通常你可以对驱动提供考提供例子,稍加修改就可以得到了。

    应用通信

      在主机已经与设备交换了检测信息并且设备驱动已经被分配并载入后,应用通信过程可以非常顺利地进行下去了。在主机上,应用程序可以使用标准Windows API功能来读和写设备。在外设上,传输数据通常需要把要发送的数据放在USB控制器的传输缓冲器中,当一个硬件中断发出数据已经到达的信号时从接收缓冲器中读取接收到的数据,并且在完成传输时确保外设准备好下一次传输。

    主机与设备建立通信的过程

      主机端的USB集线器监视着它的每个端口的信号线的电压,当USB设备插入主机时,信号线的电平会发生变化,此时主机知道有新设备插入了。

      当主机检测到设备的插入后会首选重启这个设备,接着主机发出Get_Port_Status请求来验证设备是否已经重启,设备重启后主机通过检测根信号线的电平状态判断设备的速度。

      主机发送第一次Get_DescriptorwValue字段的高字节为0x01,表示设备描述符)请求取得设备描述符,设备描述符提供了设备的多种信息,包括:设备通讯终端0的最大包的大小,设备支持的配置号以及有关这个设备的其它信息,主机通过对这些信息的分析以确定接下来的通信动作。

      设备描述符里规定了设备一个或多个配置描述符,主机再次或多次发出Get_DescriptorwValue字段的高字节为0x02,表示配置描述符)指令来读取这些配置描述符,第一次只读出配置描述符的前9个字节,这9个字节里包含了配置描述符和它的所有从属描述符(接口描述符、端点描述符)的总长度,然后主机根据这个长度读出设备的所有配置描述符(当然包括其所有从属描述符)。

      在读取完配置描述符后,若之间读取的设置描述中指定了相关字符串描述符(用来描述厂商、产品和设备序列号信息的)的索引,主机将发出若干次Get_DescriptorwValue字段的高字节为0x03,表示字符串描述符)命令来获得这些字符串描述,此时主机将会弹出窗口,展示发现新设备的信息,产商、产品描述、型号等。

      在主机已经从它的描述符中知道了能够知道的所有信息后,便开始为这个设备安装驱动程序。

      加载了USB设备驱动以后,主机发送Set_Configuration命令请求为该设备选择一个合适的配置。

      至此,USB枚举过程结束,设备可以正常使用了。

    USB命令(请求)和USB描述符

    一、USB命令

      USB规范里,对命令一词提供的单词为“Request”,但这里为了更好的理解主机与设备之间的主从关系,将它定义成命令

      所有的USB设备都要求对主机发给自己的控制命令作出响应,USB规范定义了11个标准命令,它们分别是:Clear_FeatureGet_ConfigurationGet_DescriptorGet_InterfaceGet_StatusSet_AddressSet_ConfigurationSet_DescriptorSet_InterfaceSet_FeatureSynch_Frame。所有USB设备都必须支持这些命令(个别命令除外,如Set_DescriptorSynch_Frame)。

      不同的命令虽然有不同的数据和使用目的,但所有的USB命令结构是一样的。下表所示为USB命令的结构: 

    1USB命令的结构

    偏移量

     长度(字节)

    描述

    0

    bmRequestType

    1

    位图

    请求特征:
    D7:传输方向
    0=主机至设备
    1=设备至主机
    D6..5:种类
    0=标准
    1=
    2=厂商
    3=保留
    D4..0:接受者
    0=设备
    1=接口
    2=端点
    3=其他
    4..31 保留

    1

    bRequest

    1

    命令类型编码值(见表3

    2

    wValue

    2

    根据不同的命令,含义也不同

    4

    wIndex

    2

    索引或偏移

    根据不同的命令,含义也不同,主要用于传送索引或偏 移

    6

    wLength

    2

     

    如有数据传送阶段,此为数据字节数。

    下表列出了USB11种标准命令

    2USB11种标准命令

    命令

    bmRequestType

    bRequest

    wValue

    wIndex

    wLength

    Data

    Clear_Feature

    00000000B
    00000001B
    00000010B

    CLEAR_FEATURE

    特性选择符


    接口号
    端点号

    Get_Configuration

    10000000B

    GET_CONFIGURATION

    配置值

    Get_Descriptor

    10000000B

    GET_DESCRIPTOR

    描述表种类(高字节,见表5)和索引(低字节)

    零或语言标志

    描述表长

    描述表

    Get_Interface

    10000001B

    GET_INTERFACE

    接口号

    可选设置

    Get_Status

    10000000B
    10000001B
    10000010B

    GET_STATUS

    零(返回设备状态)
    接口号(对像时接口时)
    端点号(对象是端点时)

    设备,
    接口 ,
    端点状态

    Set_Address

    00000000B

    SET_ADDRESS

    设备地址

    Set_Configuration

    00000000B

    SET_CONFIGURATION

    配置值(高字节为0,低字节表示要设置的配置值)

    Set_Descriptor

    00000000B

    SET_DESCRIPTOR

    描述表种类(高字节,见表5)和索引(低字节)

    零或语言标志

    描述表长

    描述表

    Set_Feature

    00000000B
    00000001B
    00000010B

    SET_FEATURE

    特性选择符(1表示设备,0表示端点)


    接口号
    端点号

    Set_Interface

    00000001B

    SET_INTERFACE

    可选设置

    接口号

    Synch_Frame

    100000010B

    SYNCH_FRAME

    端点号

    帧号

    其中bRequest为命令编码值,含意见表3

    3USB标准命令的编码值

    bRequest

    Value

    GET_STATUS

    0

    CLEAR_FEATURE

    1

    为将来保留

    2

    SET_FEATURE

    3

    为将来保留

    4

    SET_ADDRESS

    5

    GET_DESCRIPTOR

    6

    SET_DESCRIPTOR

    7

    GET_CONFIGURATION

    8

    SET_CONFIGURATION

    9

    GET_INTERFACE

    10

    SET_INTERFACE

    11

    SYNCH_FRAME

    12

     

    二、USB描述符

      USB协议为USB设备定义了一套描述设备功能和属性的有固定结构的描述符,包括标准的描述符即设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符,还有百标准描述符,如类描述符。USB设备通过这些描述符向USB主机汇报设备的各种各样属性,主机通过对这些描述符的访问对设备进行类型识别、配置并为其提供相应的客户端驱动程序。

      USB设备通过描述符反映自己的设备特性。USB描述符是由特定格式排列的一组数据结构组成。

      在USB设备枚举过程中,主机端的协义软件需要解析从USB设备读取的所有描述符信息。在USB主向设备发送读取描述符的请求后,USB设备将所有的描述符以连续的数据流方式传输给USB主机。主机从第一个读到的字符开始,根据双方规定好的数据格式,顺序地解析读到的数据流。

      USB描述符包含标准描述符、类描述符和厂商特定描述3种形式。任何一种设备必须USB标准描述符(队字符串描述符可选外)。

      在USB1.X中,规定了5种标准描述符:设备描述符(Device Descriptor)、配置描述符(Configuration Descriptor)、接口描述符(Interface Descriptor)、端点描述符(Endpoint Descriptor)和字符串描述符(String Descriptor)。

      每个USB设备只有一个设备描述符,而一个设备中可包含一个或多个配置描述符,即USB设备可以有多种配置。设备的每一个配置中又可以包含一个或多个接口描述符,即USB设备可以支持多种功能(接口),接口的特性通过描述符提供。

      在USB主机访问USB设备的描述符时,USB设备依照设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符顺序将所有描述符传给主机。一设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。

    1、设备描述符

      设备描述符给出了USB设备的一般信息,包括对设备及在设备配置中起全程作用的信息,包括制造商标识号ID、产品序列号、所属设备类号、默认端点的最大包长度和配置描述符的个数等。一个USB设备必须有且仅有一个设备描述符。设备描述符是设备连接到总线上时USB主机所读取的第一个描述符,它包含了14个字段,结构如下:

    4USB设备描述符的结构

    偏移量

    大小

    描述

    0

    bLength

    1

    数字

    此描述表的字节数

    1

    bDecriptorType

    1

    常量

    描述符的类型(此处应为0x01,即设备描述符)

    2

    bcdUSB

    2

    BCD

    此设备与描述表兼容的USB设备说明版本号(BCD 码)

    4

    bDeviceClass

    1

    设备类码:
    如果此域的值为0则一个设置下每个接口指出它自己的类,各个接口各自独立工作。
    如果此域的值处于1~FEH之间,则设备在不同的接口上支持不同的类。并这些接口可能不能独立工作。此值指出了这些接口集体的类定义。
    如果此域设为FFH,则此设备的类由厂商定义。

    5

    bDeviceSubClass

    1

    子类

    子类挖码
    这些码值的具体含义根据bDeviceClass 域来看。
    bDeviceClass 域为零,此域也须为零
    bDeviceClass 域为FFH,此域的所有值保留。

    6

    bDevicePortocol

    1

    协议

    协议码
    这些码的值视bDeviceClass bDeviceSubClass 的值而定。
    如果设备支持设备类相关的协议,此码标志了设备类的值。如果此域的值为零,则此设备不支持设备类相关的协议,然而,可能它的接口支持设备类相关的协议。如果此域的值为FFH,此设备使用厂商定义的协议。

    7

    bMaxPacketSize0

    1

    数字

    端点0的最大包大小(仅8,16,32,64
    为合法值)

    8

    idVendor

    2

    ID

    厂商标志(由USB-IF组织赋值)

    10

    idProduct

    2

    ID

    产品标志(由厂商赋值)

    12

    bcdDevice

    2

    BCD

    设备发行号(BCD 码)

    14

    iManufacturer

    1

    索引

    描述厂商信息的字符串描述符的索引值。

    15

    iProduct

    1

    索引

    描述产品信息的字串描述符的索引值。

    16

    iSerialNumber

    1

    索引

    描述设备序列号信息的字串描述符的索引值。

    17

    bNumConfigurations

    1

    数字

    可能的配置描述符数目

    其中bDescriptorType为描述符的类型,其含义可查下表(此表也适用于标准命令Get_DescriptorwValue域高字节的取值含义):

    5USB描述符的类型值

    类型

    描述符

    描述符值

    标准描述符

    设备描述符(Device Descriptor)

    0x01

    配置描述符(Configuration Descriptor

    0x02

    字符串描述符(String Descriptor

    0x03

    接口描述符(Interface Descriptor

    0x04

    端点描述符(EndPont Descriptor

    0x05

    类描述符

    集线器类描述符(Hub Descriptor

    0x29

    人机接口类描述符(HID

    0x21

    厂商定义的描述符

     

    0xFF

    设备类代码bDeviceClass可查下表:

    6、设备的类别(bDeviceClass

    值(十进制)

    值(十六进制)

    说明

    0

    0x00

    接口描述符中提供类的值

    2

    0x02

    通信类

    9

    0x09

    集线器类

    220

    0xDC

    用于诊断用途的设备类

    224

    0xE0

    无线通信设备类

    255

    0xFF

    厂商定义的设备类

    下表列出了一个USB鼠标的设备描述符的例子,供大家分析一下:

    7、一种鼠标的设备描述符示例

    字段

    描述符值(十六制)

    bLength

    0x12

    bDecriptorType

    0x01

    bcdUSB

    x0110

    bDeviceClass

    0x00

    bDeviceSubClass

    0x00

    bDevicePortocol

    0x00

    bMaxPacketSize0

    0x08

    idVendor

    0x045E(Microsoft Corporation

    idProduct

    0x0047

    bcdDevice

    0x300

    iManufacturer

    0x01

    iProduct

    0x03

    iSerialNumber

    0x00

    bNumConfigurations

    0x01

    2、配置描述符

      配置描述符中包括了描述符的长度(属于此描述符的所有接口描述符和端点描述符的长度的和)、供电方式(自供电/总线供电)、最大耗电量等。如果主机发出USB标准命令Get_Descriptor要求得到设备的某个配置描述符,那么除了此配置描述符以外,此配置包含的所有接口描述符与端点描述符都将提供给USB主机。

    8USB配置描述符的结构

       偏移量

        

     大小

      

       描述

          0

    bLength

    1

       数字

    此描述表的字节数长度。

          1

    bDescriptorType

    1

       常量

    配置描述表类型(此处为0x02

          2

    wTotalLength

    2

       数字

    此配置信息的总长(包括配置,接口,端点和设备类及厂商定义的描述符)

          4

    bNumInterfaces

    1

       数字

    此配置所支持的接口个数

          5

    bCongfigurationValue

    1

       数字

    SetConfiguration()请求中用作参数来选定此配置。

          6

    iConfiguration

    1

       索引

    描述此配置的字串描述表索引

          7

    bmAttributes

    1

       位图

    配置特性:
    D7 保留(设为一)
    D6 自给电源
    D5 远程唤醒
    D4..0:保留(设为一)
    一个既用总线电源又有自给电源的设备会在MaxPower域指出需要从总线取的电量。并设置D6为一。运行时期的实际电源模式可由GetStatus(DEVICE) 请求得到

          8

    MaxPower

    1

        mA

    在此配置下的总线电源耗费量。以 2mA 为一个单位。

    下面是一种硬盘的配置描述符示例:

    9、一种硬盘的配置描述符示例

    字段

    描述符值(十六进制)

    bLength

    0x09

    bDescriptorType

    0x02

    wTotalLength

    0x01F

    bNumInterfaces

    0x01

    bCongfigurationValue

    0x01

    iConfiguration

    0x00

    bmAttributes

    0x0C

    MaxPower

    0x32

    3、接口描述符

      配置描述符中包含了一个或多个接口描述符,这里的接口并不是指物理存在的接口,在这里把它称之为功能更易理解些,例如一个设备既有录音的功能又有扬声器的功能,则这个设备至少就有两个接口

      如果一个配置描述符不止支持一个接口描述符,并且每个接口描述符都有一个或多个端点描述符,那么在响应USB主机的配置描述符命令时,USB设备的端点描述符总是紧跟着相关的接口描述符后面,作为配置描述符的一部分被返回。接口描述符不可直接用Set_DescriptorGet_Descriptor来存取。

      如果一个接口仅使用端点0,则接口描述符以后就不再返回端点描述符,并且此接口表现的是一个控制接口的特性,它使用与端点0相关联的默认管道进行数据传输。在这种情况下bNumberEndpoints域应被设置成0。接口描述符在说明端点个数并不把端点0计算在内。

    10USB接口描述符的结构

    偏移量

    大小

    说明

           0

    bLength

    1

    数字

    此表的字节数

           1

    bDescriptorType

    1

    常量

    接口描述表类(此处应为0x04

           2

    bInterfaceNumber

    1

    数字

    接口号,当前配置支持的接口数组索引(从零开始)。

           3

    bAlternateSetting

    1

    数字

    可选设置的索引值。

           4

    bNumEndpoints

    1

    数字

    此接口用的端点数量,如果是零则说明此接口只用缺省控制管道。

           5

    bInterfaceClass

            1

    接口所属的类值:
    零值为将来的标准保留。
    如果此域的值设为FFH,则此接口类由厂商说明。
    所有其它的值由USB 说明保留。

           6

    bInterfaceSubClass

            1

    子类

    子类码
    这些值的定义视bInterfaceClass域而定。
    如果bInterfaceClass域的值为零则此域的值必须为零。
    bInterfaceClass域不为FFH则所有值由USB 所保留。

           7

    bInterfaceProtocol

            1

    协议

    协议码:bInterfaceClass bInterfaceSubClass 域的值而定.如果一个接口支持设备类相关的请求此域的值指出了设备类说明中所定义的协议.

           8

    iInterface

            1

    索引

    描述此接口的字串描述表的索引值。

    对于bInterfaceClass字段,表示接口所属的类别,USB协议根据功能将不同的接口划分成不的类,其具体含义如下表所示:

    11USB协议定义的接口类别(bInterfaceClass

    值(十六进制)

    类别

    0x01

    音频类

    0x02

    CDC控制类

    0x03

    人机接口类(HID

    0x05

    物理类

    0x06

    图像类

    0x07

    打印机类

    0x08

    大数据存储类

    0x09

    集线器类

    0x0A

    CDC数据类

    0x0B

    智能卡类

    0x0D

    安全类

    0xDC

    诊断设备类

    0xE0

    无线控制器类

    0xFE

    特定应用类(包括红外的桥接器等)

    0xFF

    厂商定义的设备

    4、端点描述符

      端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。

      除了描述符中描述的端点外,每个设备必须要有一个默认的控制型端点,地址为0,它的数据传输为双向,而且没有专门的描述符,只是在设备描述符中定义了它的最大包长度。主机通过此端点向设备发送命令,获得设备的各种描述符的信息,并通过它来配置设备。

    12USB端点描述符的结构

    偏移量

    大小

    说明

    0

    bLength

    1

    数字

    此描述表的字节数长度

    1

    bDescriptorType

    1

    常量

    端点描述表类(此处应为0x05

    2

    bEndpointAddress

    1

    端点

    此描述表所描述的端点的地址、方向:
    Bit 3..0 : 端点号.
    Bit 6..4 :
    保留,为零
    Bit 7:    方向,如果控制端点则略。
    0:输出端点(主机到设备)
    1:输入端点(设备到主机)

    3

    bmAttributes

    1

    位图

    此域的值描述的是在bConfigurationValue域所指的配置下端点的特性。
    Bit 1..0 :传送类型
    00=控制传送
    01=同步传送
    10=批传送
    11=中断传送
    所有其它的位都保留。

    4

    wMaxPacketSize

    2

    数字

    当前配置下此端点能够接收或发送的最大数据包的大小。
    对于实进传输,此值用于为每帧的数据净负荷预留时间。在实际运行时,管道可能不完全需要预留的带宽,实际带宽可由设备通过一种非USB定义的机制汇报给主机。对于中断传输,批量传输和控制传输,端点可能发送比之短的数据包
     

    6

    bInterval

    1

    数字

    周期数据传输端点的时间间隙。
    此域的值对于批传送的端点及控制传送的端点无意义。对于同步传送的端点此域必需为1,表示周期为1ms。对于中断传送的端点此域值的范围为1ms255ms

    下表是一种鼠标的端点描述符的示例,该端点是一个中断端点:

    13、一种鼠标的端点描述符示例

    值(十六进制)

    bLength

    0x07

    bDescriptorType

    0x05

    bEndpointAddress

    0x81

    bmAttributes

    0x03

    wMaxPacketSize

    0x04

    bInterval

    0x0A

    5、字符串描述符

      字符串描述符是一种可选的USB标准描述符,描述了如制商、设备名称或序列号等信息。如果一个设备无字符串描述符,则其它描述符中与字符串有关的索引值都必须为0。字符串使用的是Unicode编码。

      主机请示得到某个字符串描述符时一般分成两步:首先主机向设备发出USB标准命令Get_Descriptor,其中所使用的字符串的索引值为0,设备返回一个字符串描述符,此描述符的结构如下:

    14USB字符串描述符(响应主机请求时返回的表示语言ID的字符串描述符)

    偏移量

    大小

         描述

    0

    bLength

    1

    N+2

    此描述表的字节数

    1

    bDescriptorType

    1

    常量

    字串描述表类型(此处应为0x03

    2

    wLANGID[0]

    2

    数字

    语言标识(LANGID
    0

         

    N

    wLANGID[x]

    2

    数字

    语言标识(LANGID
    X

    该字符串描述符双字节的语言ID的数组,wLANGID[0]~wLANGID[x]指明了设备支持的语言,具体含义可查看USB_LANGIDs.pdf

      主机根据自己需要的语言,再次向设备发出USB标准命令Get_Descriptor,指明所要求得到的字符串的索引值和语言。这次设备所返回的是Unicode编号的字符串描述符,其结构如下:

    15Unicode字符串描述符(响应主机请求时真正表示字符串编码的字符串描述符)

    偏移量

    大小

    描述

    0

    bLength

    1

    数字

    此描述表的字节数(bString域的数值N2

    1

    bDescriptorType

    1

    常量

    字串描述表类型(此处应为0x03

    2

    bString

    N

    数字

    UNICODE 编码的字串

    bString域为设备实际返回的以UNICODE编码的字符串流,我们在编写设备端硬件驱动的时候需要将字符串转换为UNICODE编码,您可以通过一些UNICODE转换工具进行转换。这里推荐由百合电子工作室开发的一款USB描述符生成工具USB Unicode 字符串描述符生成器,它专门为编写设备端驱动程序的需要而定制,可以非常方便将您需要的字符串转换成UNICODE格式,进而导入您的C或汇编程序代码中,以下是它的界面:

    http://www.baiheee.com/Documents/090518/090518112619/USB%20Unicode%20StringDescriptor%20Generator1.jpg

    USB Unicode 字符串描述符生成器-生成C语言格式

    http://www.baiheee.com/Documents/090518/090518112619/USB%20Unicode%20StringDescriptor%20Generator2.jpg

    USB Unicode 字符串描述符生成器-生成汇编格式

    展开全文
  • STM32 USB设备开发详解

    2018-01-26 22:03:28
    USB 的用途就不多说了,下面的内容主要就是讲解如何利用ST 提供的USB 驱动库和libusb 上位机驱动库实现一个USB 数据传输功能,为了降低开发难度,我们仅仅讲解Bulk 传输模式,当然这也是用得比较多的传输模式
  • USB的用途就不多说了,下面的内容主要就是讲解如何利用ST提供的USB驱动库和libusb的上位机驱动库实现一个USB数据传输功能,为了降低开发难度,我们仅仅讲解Bulk传输模式,当然这也是用得比较多的传输模式。...
  • Windows下USB驱动开发入门小结

    万次阅读 多人点赞 2018-08-20 11:01:06
    便将开发板通过USB接口插上电脑后发现显示的未识别的设备,我记得在学校里都是在网上找一个USB转串口的驱动程序安装下来就可以通过串口助手来传输数据了,现在需要自己开发一个驱动程序,只会点单片机的我感觉难度...

           今年刚从学校毕业,来到公司后学了学画板子然后经理便给了我了一块板子,需要用到USB传输数据,让我学习一下Windows驱动程序开发并将这个USB驱动解决。当时一脸懵逼,便将开发板通过USB接口插上电脑后发现显示的未识别的设备,我记得在学校里都是在网上找一个USB转串口的驱动程序安装下来就可以通过串口助手来传输数据了,现在需要自己开发一个驱动程序,只会点单片机的我感觉难度巨大。

           接下来便是疯狂的百度搜索资料,后来发现CSDN真是个好东西,里面有很多大佬用心编辑的好文章,对于新手有着非常巨大的帮助。在此我也分享一下近一个月的Windows驱动开发之USB的学习过程,不够详细,只是学习过程,以便日后回顾及新手学习流程参考。

     

    1.百度Windows驱动开发对其有个大致的了解,然后浏览相关的书籍,以下是我主要浏览的Windows驱动开发的书籍。

          《Windows7设备驱动程序开发》       下载地址:http://www.jb51.net/books/87699.html

          《Windows设备驱动程序WDF开发》 下载地址:https://download.csdn.net/download/qq_25648927/10317997

          《WDF USB驱动开发指南》              下载地址:http://www.jb51.net/books/234606.html

             注:现在大多数都是用WDF框架进行Windows驱动开发(WDF是对WDM更高层次的封装,降低了开发难度),不过网上面能搜到很多关于WDM框架开发的内容,可稍微了解下。

     

    2.配置驱动开发环境,都是CSDN上的文章,驱动开发调试环境搭建的文章非常多,在此列出一篇较好的文章。

           大佬博客地址https://blog.csdn.net/qing666888/article/details/50858272

           注:CSDN博客最下面还有很多相关的内容都可以进行参考,这过程新手需要花费大量的时间,坑也比较多,在此列出几点本人遇到的坑。

           1)最后一个步骤VS2015附加到进程失败时可参考https://blog.csdn.net/zhouzixin053/article/details/51289237,且VS2015一定要用管理员权限运行才能附加成功。

            2)VS2015想要生成运行于WIN7环境下的驱动程序的话不仅需要将自己工程属性页里的Driver Settings->Target OS Version设置成WIN7,还应将Driver Settings->Driver Model里的KMDF Version Minor设置成11。因为KMDF分不同的版本,支持的操作系统也不一样,设置有误的话有些API函数无法使用,编译会报未声明的错误,借用官方的编译错误提示:你可能会调用了你的生成环境中当前并不支持的 SDK 头文件中的函数。

     

    3.从微软官网上下载USB-FX2的驱动程序示例代码并仔细研究里面的驱动程序(里面还包含有控制台应用程序)。

           代码示例:https://developer.microsoft.com/zh-cn/windows/hardware/drivers-code-samples

           详细下载地址:https://github.com/Microsoft/Windows-driver-samples

           注:其中的.inx文件是驱动安装信息文件,应该首先了解,将里面的VID&PID值改成与自己的设备相对应,然后将编译后生成.inf文件和.sys文件拷贝到目标计算机中并将目标计算机的强制驱动签名关掉,然后打开设备管理器进行驱动安装,如果安装不了的话可以查看Windows 安装程序日志文件进行问题排查(比如我从里面发现了WIN7系统的话还需要WdfCoinstaller01011.dll文件才能安装)。

     

    4.开发出来的驱动倘若正确并安装成功后便可研究示例代码里面的控制台应用程序,驱动程序必须与应用程序进行通信,才能最终达到Windows下通过USB驱动与设备进行交互,不然驱动程序的作用便体现不出来,如何验证驱动程序里面的功能是否正常运行就靠应用程序与驱动程序间的通信了。

           参考博客:https://blog.csdn.net/hustd10/article/details/50589743

           注:我的开发环境是WIN10(主计算机) +VS2015 + VM虚拟机WIN10(目标计算机),一开始我目标计算机装的是WIN7系统,运行编译出来的WIN7控制台应用程序时始终找不到USB设备,但是在WIN10弄上就可以,不知道什么原因,后来便学习了下QT,在QT下使用libusb库写了个USB的界面应用程序实现了读写功能。

    展开全文
  • USB设备开发之STM32

    千次阅读 2015-07-22 23:05:11
    根据项目的开发进度要求,接下来的主要阶段是开发USB设备和上位机PC的通信。主要包括:USB硬件开发、驱动开发和软件开发。 (1)硬件开发  由于时间紧迫,电子组的硬件还未完成,所以这部分先用手头上的STM32的...

        根据项目的开发进度要求,接下来的主要阶段是开发USB设备和上位机PC的通信。主要包括:USB硬件开发、驱动开发和软件开发。

    (1)硬件开发

           由于时间紧迫,电子组的硬件还未完成,所以这部分先用手头上的STM32的USB来调试驱动程序和上位机应用程序。

    这部分主要完成固件程序的编写。

    (2)驱动程序开发

      USB借口通过驱动程序来实现外部USB设备与上位机应用程序的通信。驱动程序是不可或缺的,也是难度比较大的一个环节。在windows操作系统下,开发驱动程序常用工具:driver studio 和 winddriver等专业驱动开发工具,或直接上DDK开发。目前采用driver studio完成。

    (3)USB应用程序。

       应用程序直接呈现给使用者的操作终端,这里采用MFC完成,原因自己比较熟悉MFC。


    接下来的时间就按照这样安排执行。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

    展开全文
  • 由于其众多的优点,USB总线越来越多的被应用到计算机与外设的接口中,芯片厂家也提供了多种USB接口芯片供设计者使用,为了开发出功能强大的USB设备,设计者往往需要自己开发USB设备驱动程序,驱动程序开发一直是...
  • USB的用途就不多说了,下面的内容主要就是讲解如何利用ST提供的USB驱动库和libusb的上位机驱动库实现一个USB数据传输功能,为了降低开发难度,我们仅仅讲解Bulk传输模式,当然这也是用得比较多的传输模式。...

    前言
    USB的用途就不多说了,下面的内容主要就是讲解如何利用ST提供的USB驱动库和libusb的上位机驱动库实现一个USB数据传输功能,为了降低开发难度,我们仅仅讲解Bulk传输模式,当然这也是用得比较多的传输模式。

    开发流程
    1,完成STM32单片机端的USB程序; 
    2,利用libusb自带的inf-wizard工具生成USB驱动; 
    3,基于libusb编写USB通信程序; 
    4,测试PC和单片机的数据通信; 

    STM32程序编写
    1,完成描述符的修改,修改后的描述符如下(在usb_desc.c文件中)
    设备描述符:

    const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
    {
        0x12,                       /*bLength */
        USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
        0x00,                       /*bcdUSB */
        0x02,
        0x00,                       /*bDeviceClass*/
        0x00,                       /*bDeviceSubClass*/
        0x00,                       /*bDeviceProtocol*/
        0x40,                       /*bMaxPacketSize40*/
        LOBYTE(USBD_VID),           /*idVendor*/
        HIBYTE(USBD_VID),           /*idVendor*/
        LOBYTE(USBD_PID),           /*idVendor*/
        HIBYTE(USBD_PID),           /*idVendor*/
        0x00,                       /*bcdDevice rel. 2.00*/
        0x02,
        1,                          /*Index of string descriptor describing manufacturer */
        2,                          /*Index of string descriptor describing product*/
        3,                          /*Index of string descriptor describing the device serial number */
        0x01                        /*bNumConfigurations*/
    }; /* CustomHID_DeviceDescriptor */

    配置描述符:

    const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] =
    {
        0x09, /* bLength: Configuation Descriptor size */
        USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
        CUSTOMHID_SIZ_CONFIG_DESC,
        /* wTotalLength: Bytes returned */
        0x00,
        0x01,         /* bNumInterfaces: 1 interface */
        0x01,         /* bConfigurationValue: Configuration value */
        0x00,         /* iConfiguration: Index of string descriptor describing
                                     the configuration*/
        0xE0,         /* bmAttributes: Bus powered */
                      /*Bus powered: 7th bit, Self Powered: 6th bit, Remote wakeup: 5th bit, reserved: 4..0 bits */
        0xFA,         /* MaxPower 500 mA: this current is used for detecting Vbus */
        /************** Descriptor of Custom HID interface ****************/
        /* 09 */
        0x09,         /* bLength: Interface Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: Interface descriptor type */
        0x00,         /* bInterfaceNumber: Number of Interface */
        0x00,         /* bAlternateSetting: Alternate setting */
        0x04,         /* bNumEndpoints */
        0xDC,         /* bInterfaceClass: Class code = 0DCH */
        0xA0,         /* bInterfaceSubClass : Subclass code = 0A0H */
        0xB0,         /* nInterfaceProtocol : Protocol code = 0B0H */
        0,            /* iInterface: Index of string descriptor */
        /******************** endpoint descriptor ********************/
        /* 18 */
        0x07,         /* endpoint descriptor length = 07H */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
        0x81,         /* endpoint 1 IN */
        0x02,                                        /* bulk transfer = 02H */
        0x40,0x00,    /* endpoint max packet size = 0040H */
        0x00,         /* the value is invalid when bulk transfer */
     
        0x07,         /* endpoint descriptor length = 07H */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
        0x01,         /* endpoint 1 OUT */
        0x02,                                        /* bulk transfer = 02H */
        0x40,0x00,    /* endpoint max packet size = 0040H */
        0x00,         /* the value is invalid when bulk transfer */
                     
        0x07,         /* endpoint descriptor length = 07H */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
        0x82,         /* endpoint 2 IN */
        0x02,                                        /* bulk transfer = 02H */
        0x40,0x00,    /* endpoint max packet size = 0040H */
        0x00,         /* the value is invalid when bulk transfer */
                     
        0x07,         /* endpoint descriptor length = 07H */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
        0x02,         /* endpoint 2 OUT */
        0x02,                                        /* bulk transfer = 02H */
        0x40,0x00,    /* endpoint max packet size = 0040H */
        0x00,         /* the value is invalid when bulk transfer */
    }; /* CustomHID_ConfigDescriptor */

    配置描述符就包含了端点描述符,我们用了4个端点,两个BULK-OUT端点,两个BULK-IN端点。

    其他的描述符:

    /* USB String Descriptors (optional) */
    const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] =
    {
        CUSTOMHID_SIZ_STRING_LANGID,
        USB_STRING_DESCRIPTOR_TYPE,
        0x09,
        0x04
    }; /* LangID = 0x0409: U.S. English */
     
    const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] =
    {
        CUSTOMHID_SIZ_STRING_VENDOR, /* Size of Vendor string */
        USB_STRING_DESCRIPTOR_TYPE,  /* bDescriptorType*/
        // Manufacturer: "STMicroelectronics" 
        'M', 0, 'y', 0, 'U', 0,'S', 0,'B', 0, '_', 0, 'H', 0,'I',0,'D',0
    };
     
    const uint8_t CustomHID_StringProduct[CUSTOMHID_SIZ_STRING_PRODUCT] =
    {
        CUSTOMHID_SIZ_STRING_PRODUCT,          /* bLength */
        USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
        'B', 0, 'y', 0, ' ', 0, 'e', 0, 'm', 0, 'b', 0,'e',0,'d',0,'-',0,'n',0,'e',0,'t',0
    };
    uint8_t CustomHID_StringSerial[CUSTOMHID_SIZ_STRING_SERIAL] =
    {
        CUSTOMHID_SIZ_STRING_SERIAL,           /* bLength */
        USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
        'x', 0, 'x', 0, 'x', 0,'x', 0,'x', 0, 'x', 0, 'x', 0
    };

    2,根据端点缓冲区大小配置端点缓冲区地址,配置信息如下(在usb_conf.h文件中):

    /* buffer table base address */
    #define BTABLE_ADDRESS      (0x00)
     
    /* EP0  */
    /* rx/tx buffer base address */
    #define ENDP0_RXADDR        (0x18)
    #define ENDP0_TXADDR        (0x58)
     
    /* EP1  */
    /* tx buffer base address */
    //地址为32位对其,位4的倍数,不能超过 bMaxPacketSize
    //EP1
    #define ENDP1_RXADDR        (0x98)
    #define ENDP1_TXADDR        (0x98+64)
    EP2
    #define ENDP2_RXADDR        (0xA0+64+64)
    #define ENDP2_TXADDR        (0xA0+64+64+64)

    3,初始化每个端点(在usb_prop.c文件中的CustomHID_Reset函数中)

    /* Initialize Endpoint 0 */
    SetEPType(ENDP0, EP_CONTROL);
    SetEPTxStatus(ENDP0, EP_TX_STALL);
    SetEPRxAddr(ENDP0, ENDP0_RXADDR);
    SetEPTxAddr(ENDP0, ENDP0_TXADDR);
    Clear_Status_Out(ENDP0);
    SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
    SetEPRxValid(ENDP0);
     
    /* Initialize Endpoint 1 */
           SetEPType(ENDP1, EP_BULK);
           SetEPRxAddr(ENDP1, ENDP1_RXADDR);
           SetEPTxAddr(ENDP1, ENDP1_TXADDR);
           SetEPRxCount(ENDP1, EP_SIZE);
           SetEPRxStatus(ENDP1, EP_RX_VALID);
     SetEPTxStatus(ENDP1, EP_TX_NAK);
     
    /* Initialize Endpoint 2 */
           SetEPType(ENDP2, EP_BULK);
           SetEPRxAddr(ENDP2, ENDP2_RXADDR);
           SetEPTxAddr(ENDP2, ENDP2_TXADDR);
           SetEPRxCount(ENDP2, EP_SIZE);
           SetEPRxStatus(ENDP2, EP_RX_VALID);
           SetEPTxStatus(ENDP2, EP_TX_NAK);

    4,实现端点的回调函数(需要在usb_conf.h中注释掉对应的回调函数宏定义)

    /*******************************************************************************
    * Function Name  : EP1_OUT_Callback.
    * Description    : EP1 OUT Callback Routine.
    * Input          : None.
    * Output         : None.
    * Return         : None.
    *******************************************************************************/
    void EP1_OUT_Callback(void)
    {
            EP1_ReceivedCount = GetEPRxCount(ENDP1);
            PMAToUserBufferCopy(USB_Receive_Buffer, ENDP1_RXADDR, EP1_ReceivedCount);
            SetEPRxStatus(ENDP1, EP_RX_VALID);
    }
    /*******************************************************************************
    * Function Name  : EP2_OUT_Callback.
    * Description    : EP2 OUT Callback Routine.
    * Input          : None.
    * Output         : None.
    * Return         : None.
    *******************************************************************************/
    void EP2_OUT_Callback(void)
    {
            EP2_ReceivedCount = GetEPRxCount(ENDP2);
            PMAToUserBufferCopy(USB_Receive_Buffer, ENDP2_RXADDR, EP2_ReceivedCount);
            SetEPRxStatus(ENDP2, EP_RX_VALID);
    }

    5,完成主函数的测试程序

    int main(void)
    {
            uint8_t data[256];
            uint32_t i=0;
            Set_System();//系统时钟初始化
            USART_Configuration();//串口1初始化
            printf("\x0c\0");printf("\x0c\0");//超级终端清屏
            printf("\033[1;40;32m");//设置超级终端背景为黑色,字符为绿色
            printf("\r\n*******************************************************************************");
            printf("\r\n************************ Copyright 2009-2012, EmbedNet ************************");
            printf("\r\n*************************** [url=http://www.embed-net.com]http://www.embed-net.com[/url] **************************");
            printf("\r\n***************************** All Rights Reserved *****************************");
            printf("\r\n*******************************************************************************");
            printf("\r\n");
     
            USB_Interrupts_Config();
            Set_USBClock();
            USB_Init();
     
            while(1)
            {
                    if(EP1_ReceivedCount > 0){
                            USB_GetData(ENDP1,data,EP1_ReceivedCount);
                            USB_SendData(ENDP1,data,EP1_ReceivedCount);
                            printf("usb EP1 get data %d byte data\n\r",EP1_ReceivedCount);
                            for(i=0;i<EP1_ReceivedCount;i++){
                                    printf("0x%02X ",data[i]);
                            }
                            printf("\n\r");
                            EP1_ReceivedCount=0;
                    }
                    if(EP2_ReceivedCount > 0){
                            USB_GetData(ENDP2,data,EP2_ReceivedCount);
                            USB_SendData(ENDP2,data,EP2_ReceivedCount);
                            printf("usb EP2 get data %d byte data\n\r",EP2_ReceivedCount);
                            for(i=0;i<EP2_ReceivedCount;i++){
                                    printf("0x%02X ",data[i]);
                            }
                            printf("\n\r");
                            EP2_ReceivedCount=0;        
                    }
            }
    }

    到此,STM32的程序基本上编写完成,然后编译下载程序,如果一切顺利,系统会检测到一个新的设备并试图加载对应的驱动,由于我们还没做驱动程序,所以肯定会加载驱动失败,如下图所示:
     

    驱动程序生成
    下面我们就利用libusb的自带的INF-向导工具生成的USB驱动程序,该工具可以到本文章的附件下载,其具体过程如下:
     

    运行该程序,出现下图对话框,点击“下一步”。
     

    出现下图对话框后选择我们需要生成驱动程序的设备;
     

    这里可以写该设备名称,我们保持默认值,其他的都不需要修改;
     

    点击下一步后出现下图对话框,我们选择一个目录保存这个INF文件;
     

    保存后的文件
     

    若要立即安装驱动,可以点击下面对话框的红色框按钮;
     

    Win7的下可能会出现如下对话框,点击始终安装;
     

    到此,USB驱动程序自动生成完毕,若安装了驱动,则在设备管理器里面会看到如下信息
     

    基于libusb的上位的机驱动程序关系编写

    首先建立一个驱动程序工程,然后将libusb的的库(附件有下载)添加到工程里面,以下关系编写几个函数
    设备扫描函数,该函数用来找到插入电脑上的USB设备

    /**
      * @brief  扫描设备连接数
      * @param  NeedInit 是否需要初始化,第一次调用该函数需要初始化
      * @retval 识别到的指定设备个数
      */
    int __stdcall USBScanDev(int NeedInit)
    {
            if(NeedInit){
                    usb_init(); /* initialize the library */
                    usb_find_busses(); /* find all busses */
                    usb_find_devices(); /* find all connected devices */
            }
            return scan_dev(pBoard);
    }

    打开设备

    /**
      * @brief  打开指定的USB设备
      * @param  devNum        需要打开的设备号
      * @retval 打开状态
      */
    int __stdcall USBOpenDev(int DevIndex)
    {
            pBoardHandle[DevIndex] = open_dev(DevIndex,pBoard);
            if(pBoardHandle[DevIndex]==NULL){
                    return SEVERITY_ERROR;
            }else{
                    return SEVERITY_SUCCESS;
            }
    }

    关闭设备

    /**
      * @brief  关闭指定的USB设备
      * @param  devNum        需要关闭的设备号
      * @retval 打开状态
      */
    int __stdcall USBCloseDev(int DevIndex)
    {
            return close_dev(DevIndex,pBoardHandle);
    }

    BULK端点写数据

    /**
      * @brief  USB Bulk端点写数据
      * @param  nBoardID 设备号
      * @param  pipenum 端点号
      * @param  sendbuffer 发送数据缓冲区
      * @param  len 发送数据字节数
      * @param  waittime 超时时间
      * @retval 成功发送的数据字节数
      */
     
    int __stdcall USBBulkWriteData(unsigned int nBoardID,int pipenum,char *sendbuffer,int len,int waittime)
    {
            int ret=0;
            if(pBoardHandle[nBoardID] == NULL){
                    return SEVERITY_ERROR;
            }
    #ifdef TEST_SET_CONFIGURATION
        if (usb_set_configuration(pBoardHandle[nBoardID], MY_CONFIG) < 0)
        {
            usb_close(pBoardHandle[nBoardID]);
            return SEVERITY_ERROR;
        }
    #endif
     
    #ifdef TEST_CLAIM_INTERFACE
        if (usb_claim_interface(pBoardHandle[nBoardID], 0) < 0)
        {
            usb_close(pBoardHandle[nBoardID]);
            return SEVERITY_ERROR;
        }
    #endif
     
    #if TEST_ASYNC
        // Running an async write test
        ret = transfer_bulk_async(dev, pipenum, sendbuffer, len, waittime);
    #else
            ret = usb_bulk_write(pBoardHandle[nBoardID], pipenum, sendbuffer, len, waittime);
            /*if((len%64) == 0){
                    usb_bulk_write(pBoardHandle[nBoardID], pipenum, sendbuffer, 0, waittime);
            }*/
    #endif
    #ifdef TEST_CLAIM_INTERFACE
        usb_release_interface(pBoardHandle[nBoardID], 0);
    #endif
        return ret;
    }

    BULK端点读数据

    /**
      * @brief  USB Bulk读数据
      * @param  nBoardID 设备号
      * @param  pipenum 端点号
      * @param  readbuffer 读取数据缓冲区
      * @param  len 读取数据字节数
      * @param  waittime 超时时间
      * @retval 读到的数据字节数
      */
    int __stdcall USBBulkReadData(unsigned int nBoardID,int pipenum,char *readbuffer,int len,int waittime)
    {
            int ret=0;
            if(pBoardHandle[nBoardID] == NULL){
                    return SEVERITY_ERROR;
            }
    #ifdef TEST_SET_CONFIGURATION
        if (usb_set_configuration(pBoardHandle[nBoardID], MY_CONFIG) < 0)
        {
            usb_close(pBoardHandle[nBoardID]);
            return SEVERITY_ERROR;
        }
    #endif
     
    #ifdef TEST_CLAIM_INTERFACE
        if (usb_claim_interface(pBoardHandle[nBoardID], 0) < 0)
        {
            usb_close(pBoardHandle[nBoardID]);
            return SEVERITY_ERROR;
        }
    #endif
     
    #if TEST_ASYNC
        // Running an async read test
        ret = transfer_bulk_async(pGinkgoBoardHandle[nBoardID], pipenum, sendbuffer, len, waittime);
    #else
            ret = usb_bulk_read(pBoardHandle[nBoardID], pipenum, readbuffer, len, waittime);
    #endif
    #ifdef TEST_CLAIM_INTERFACE
        usb_release_interface(pBoardHandle[nBoardID], 0);
    #endif
        return ret;
    }

    到此,PC端的驱动程序编写基本完成,下面就是驱动程序的测试,我们可以把之前这个程序生成为一个DLL文件,然后单独建立一个测试工程来测试这个DLL文件中的函数,测试程序如下:

    // USB_DriverTest.cpp : 定义控制台应用程序的入口点。
    //
     
    #include "stdafx.h"
     
    #define        EP1_OUT_SIZE        64
    #define        EP1_IN_SIZE        64
     
    int _tmain(int argc, _TCHAR* argv[])
    {
            int DevNum;
            int ret;
            char WriteTestData[256]={1,2,3,4,5,6,7,8,9};
            char ReadTestData[256]={0};
            for(int i=0;i<256;i++){
                    WriteTestData[i] = i;
            }
            //扫描设备连接数,需要初始化
            DevNum = USBScanDev(1);
            printf("设备连接数为:%d\n",DevNum);
            //打开设备0
            ret = USBOpenDev(0);
            if(ret == SEVERITY_ERROR){
                    printf("打开设备失败!\n");
                    return SEVERITY_ERROR;
            }else{
                    printf("打开设备成功!\n");
            }
     
            //端点1写数据
            ret = USBBulkWriteData(0,EP1_OUT,WriteTestData,EP1_OUT_SIZE,500);
            if(ret != EP1_OUT_SIZE){
                    printf("端点1写数据失败!%d\n",ret);
                    return SEVERITY_ERROR;
            }else{
                    printf("端点1写数据成功!\n");
            }
            //端点1读数据
            ret = USBBulkReadData(0,EP1_IN,ReadTestData,EP1_IN_SIZE,500);
            if(ret != EP1_IN_SIZE){
                    printf("端点1读数据失败!%d\n",ret);
                    return SEVERITY_ERROR;
            }else{
                    printf("端点1读数据成功!\n");
                    for(int i=0;i<EP1_IN_SIZE;i++){
                            printf("%02X ",ReadTestData[i]);
                            if(((i+1)%16)==0){
                                    printf("\n");
                            }
                    }
                    printf("\n");
            }
            Sleep(100);
            //端点2写数据
            ret = USBBulkWriteData(0,EP2_OUT,WriteTestData+64,64,500);
            if(ret != 64){
                    printf("端点2写数据失败!%d\n",ret);
                    return SEVERITY_ERROR;
            }else{
                    printf("端点2写数据成功!\n");
            }
            //端点2读数据
            ret = USBBulkReadData(0,EP2_IN,ReadTestData,64,500);
            if(ret != 64){
                    printf("端点2读数据失败!%d\n",ret);
                    return SEVERITY_ERROR;
            }else{
                    printf("端点2读数据成功!\n");
                    for(int i=0;i<64;i++){
                            printf("%02X ",ReadTestData[i]);
                            if(((i+1)%16)==0){
                                    printf("\n");
                            }
                    }
                    printf("\n");
            }
            getchar();
            return 0;
    }

    到此,整个开发流程基本完成,的英文下面本。套程序的测试图片

    串口打印输出
     

    PC端测试程序输出
     

    Bus Hound抓取到的USB数据
     

    程序源码下载

    libusb的驱动生成工具下载:  inf_tool.rar 
    STM32程序源码下载:  USB_DriverSTM32F103.rar 
    PC端USB驱动下载:  USB Driver.rar 
    PC端USB驱动程序源码下载:  USB_DriverBulk.rar 
    PC端USB驱动测试程序源码下载:  USB_DriverTest.rar 
    libusb的驱动包下载:  libusb-win32-bin-1.2.6.0.rar 

    展开全文
  • USB的用途就不多说了,下面的内容主要就是讲解如何利用ST提供的USB驱动库和libusb上位机驱动库实现一个USB数据传输功能,为了降低开发难度,我们仅仅讲解Bulk传输模式,当然这也是用得比较多的传输模式。 开发...
  • 可以真正实现免驱的WinUSB设备为...每个USB设备在PC主机上都有对应的一个驱动程序,Windows操作系统为常用标准USB设备类型(如HID设备类、USB接口打印机、优盘等)提供了对应的驱动程序,但如果您开发USB设备不是标准
  • 嵌入式Linux下基于libusb的USB驱动开发

    千次阅读 2018-01-06 16:39:53
    由于usb设备的普遍性及其多样性,大量的usb设备的驱动开发也就成为开发者做的最多的事情。Linux平台上,内核驱动的开发由于内核的复杂和版本问题,初学者难以入手,驱动程序也不易升级和维护。本文主要介绍Linux平台...
  • USB开发基础:USB设备开发流程

    千次阅读 2010-09-30 23:41:00
    USB设备开发一般包括主机端(上位机)驱动程序的开发USB设备端驱动程序的开发,有时还可能包括主机端应用程序的设计工作。
  • 2、搭建开发环境 3、配置内核支持USB WIFI网卡 使用WIFI网卡相关概念并利用工具iw(STA模式) 使用WIFI网卡准备工作 对于我们的手机一般来说都会连着理由器的WIFI,此时手机为STA模式,而路由器为AP模式(也叫热点)...
  •  调试STM32的USB CDC设备已经有好多次了,可以看一下前面写的日志,针对不同的STM32 MCU都进行了调试。原本以为STM32F4会很简单,可处处是坑,已经调到半夜才解决问题,把问题重新梳理。  我现在使用的芯片时STM...
  • 意法半导体日前推出一套与STR7和STR9系列微控制器配套使用的USB软件开发工具,这套工具大幅度简化了嵌入式软件的实现难度,能够处理相对比较复杂的USB接口标准。今天,USB在嵌入式系统中应用非常广泛,这是因为USB...
  • 免固件开发是新一代的FPGA USB开发方式。本文对比了免固件开发方式与传统方式的开发流程揭示了出免固件开发所具有的开发模型清晰,开发机制强大、开发周期短暂等优势
  • 目前笔者从事音频开发工作,借助公司硬件资源,给自己做了个迷你声卡,接下来让笔者介绍一下相关开发过程。 USB声卡,这里借助度娘的解释:USB声卡是插在USB口的声卡,通过USB总线与计算机系统链接。。。。。。 ...
  • 意法半导体(ST)近日推出一套与STR7和STR9系列微控制器配套使用的USB开发工具,这套工具大幅度简化了嵌入式软件的实现难度,能够处理相对比较复杂的USB接口标准。今天,USB在嵌入式系统中应用非常广泛,这是因为USB...
  • VHP 电子板可以用电池供电,并集成到可穿戴设备、手镯、袖子和手机壳中 其中一位在日常生活中采用读唇术的开发者每天佩戴该手镯几个月,发现它比以前的设备能提供更好的信息来促进读唇术,允许用手镯与单独读唇术...
  • 最近,有朋友正好在开发一个USB音频设备,所以询问我一些USB音频设备开发方面的技术细节问题;也和音响发烧友聊到USB音频设备的实现方式与其优缺点;后来,也和人谈到实现一个USB音频设备的难易度. 以前在...
  • Linux驱动之USB设备驱动 2003 年毕业于中国科学技术大学,电子专业...
  • 端点(endpoint):端点是USB设备的唯一可识别部分,其是主机和设备之间的通信流的终点。它是一个USB设备或主机上的一个数据缓冲区,用来存放和发送USB的各种数据。每个USB逻辑设备由一组独立的端点组成。每个逻辑...
  • USB HID学习:一点开发记录

    千次阅读 热门讨论 2020-02-13 22:44:10
    某天,曾经的前同事找我,说有个USB项目。因为知道我当时离职在找工作,于是转给我,然后介绍客户给我。
  • 摘要 本文介绍WDM型USB设备驱动程序的基本概念、结构和特性,并说明了利用Driverworks进行开发的方法。关键词 WDM;USB设备驱动程序;Driverworks 导言 通用串行总线USB是1995年康柏、微软、IBM、DEC等公司推广的一...
  • USB接口是应用很广泛的一种外设接口,相对于单片机系统的串口、IIC、SPI等嵌入式接口,USB接口开发难度更高需要开发工程师投入的精力更多。USB接口也有各种现成的USB类型的接口芯片,如大家调试时经常使用到的USB转...
  • 5. 启动设备 WDM下, AddDevice 调用成功后, Pnp 管理器会紧接着发送 PNP_MN_START_DEVICE 函数,我们一般会为这个子分发定义一个函数,比如 StartDevice 。 WDF 的 StartDevice 在哪里呢?其实我们...
  • 摘要 本文介绍WDM型USB设备驱动程序的基本概念、结构和特性,并说明了利用Driverworks进行开发的方法。 关键词 WDM;USB设备驱动程序;Driverworks 导言 通用串行总线USB是1995年康柏、微软、IBM、DEC等公司推广的...
  • 摘要 USB设备及其驱动程序的复杂性给开发人员带来了很大的开发难度。本文给出一种采用C8051F120微控制器和PDIUSBD12 USB控制器结合的方式实现人机接口设备(Human Interface Devices)的方法,以及如何编写应用程序来...
  • Android设备USB通讯

    千次阅读 2015-12-17 14:33:24
    摘 要: AOA协议是Google公司推出的用于实现Android设备与外围设备之间USB通信的协议。该协议拓展了Android设备USB接口的功能,为基于Android系统的智能设备应用于数据采集和设备控制领域提供了条件。介绍了Android...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,423
精华内容 1,769
关键字:

usb设备开发难度