Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2697430
  • 博文数量: 877
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5921
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-05 12:25
个人简介

技术的乐趣在于分享,欢迎多多交流,多多沟通。

文章分类

全部博文(877)

文章存档

2021年(2)

2016年(20)

2015年(471)

2014年(358)

2013年(26)

分类: 嵌入式

2014-07-03 13:58:09

开发环境:win7
开发板    :51单片机 + pdiusbd12 芯片


前言:在USB协议中规定,使用的是小端结构
        在上一节中我们知道设备接收到主机发送过来的数据为:0x80,0x06,0x00,0x01,0x00,0x00,0x40,0x00

1,USB标准设备请求的数据结构


            注意:wValue,wIndex,wLength这三个域都是两个字节的,在USB协议中规定,使用的是小端结构,即 低字节在先,高字节在后。

        1)bRequest
        

        2) wValue,wIndex 对于不同的请求,其各字段意义不同。
        

            2.1) 当 bRequest 为 GET_DESCRIPTOR/SET_DESCRIPTOR 时,wValue 为 描述符类型或索引。
                则 描述符类型 如下:
                

        2.2) 当 bRequest 为 CLEAR_FEATURE/SET_FEATURE 时, wValue 为 特性选择
            则 特性选择 如下:
            
    
        2.3) 当 wIndex 为接口号(interface) 时:
            
        2.4) 当 wIndex 为端口号(endpoint) 时:
            


    2,USB鼠标的数据结构解析           
            设备接收到的数据:0x80,0x06,0x00,0x01,0x00,0x00,0x40,0x00
            1) bmRequestType = 0x80
                即 bit[7] = [1]b,        表示 数据的传输方向为 设备到主机
                    bit[6~5] = [00]b,    表示 数据的请求类型 为 标准
                    bit[4~0] = [00000]b,表示 请求的接收者 为 设备

            2) bRequest   = 0x06
                即 bRequest 为 GET_DESCRIPTOR

            3) wValue = 0x00 0x01
                即 wValue_lsb(低字节) = 0x00,表示的是索引值,用来选择同一种描述符(例如字符串描述符和配置描述符)中具体的某个描述符。
                    wValue_msb(高字节) = 0x01,表示的是描述符的类型编号。1 表示 设备描述符(DEVICE)

            4) wIndex = 0x00 0x00

            5) wLength = 0x04 0x00
                即 wLength_lsb(低字节) = 0x40
                    wLengtg_msb(高字节) = 0x00
                    得到 wLength = 0x0040 = 64 .
                    wLength 域为请求设备返回数据的字节数,设备实际返回的字节数可以比该域指定的字节数。            

    3,设备描述符的实现
            
        1) bcdUSB
            该值用 BCD 码表示,例如:USB2.0协议就是 0x0200;而USB1.1协议就是0x0110.

        2) bDeviceClass 是设备所使用的类编码。
            对于大多数标准的USB设备类,该字段通常设置为0, 而在接口描述符中的bInterfaceClass中指定接口所实现的功能。
            当 bDeviceClass为0时,下面的bDeviceSubClass 也必须为0.
            如果 bDeviceClass 为 0xFF,表示是厂家自定义的设备类。

        3) bDeviceSubClass 是设备所使用的子类编码
            当类编码(bDeviceClass)不为 0 和 0xFF 时,子类编码有USB协议规定。

        4) bDeviceProtocol 是设备所使用的协议,协议编码由USB协议规定。
            当该字段为 0 时,表示设备不使用类所定义的协议。
            当该字段为 0xFF 时,表示设备使用厂家自定义的协议。
            bDeviceProtocol 必须要结合设备类和设备子类联合使用才有意义,因此当 类编码(bDeviceClass)为 0 时,bDeviceProtocol 应该也为 0。
            
        5) bMaxPacketSize0 是端点0的最大包长。其取值可以为 8,16,32,64.

        6) idVender 是厂家的ID号。该ID号由USB协会分配,不能随意使用。
            主机通常是靠厂家ID号,产品ID号及产品序列号来安装和加载驱动的。

        7) idProduct 是产品ID号。

        8) bcdDevice 是设备的版本号。
            同一个产品升级后,可以通过修改设备的版本号来区别。

        9) iManufacturer 是描述厂家的字符串的索引值。
            当该值为 0 时,表示没有厂家字符串。
            主机获取设备描述符时,会将索引值放在 wValue 的第一个字节中,用来选择不同的字符串。

        10) iProduct 是描述产品的字符串的索引值。
            当该值为 0 时,表示没有产品的字符串。
            当第一次插入某个 USB设备时,会在 Windows的右下方弹出一个对话框,显示发现新硬件,并且会显示该设备的名称。
            其实这里显示的信息就是从产品字符串里获取的,如果想它显示所需的信息,应该修改产品字符串。

        11) iSerialNumber 是设备的序列号字符串的索引值。
            最好给每个产品制定一个唯一的序列号,就好像每个英特尔的奔四处理器都有一个ID号一样。
            设备序列号可能被主机联合 VID 和 PID 来区分不同的设备,有时连接多个具有相同 VID 和 PID 以及 设备序列号的设备,
            可能会导致设备无法正确识别。
            当该值为 0 时,表示没有序列号字符串。

        12) bNumConfigurations 表示设备有多少种配置。
            每种配置都会有一个配置描述符,主机通过发送设置配置来选择某一个配置。
            大部分的USB 设备只有一个配置,即该字段的值为 1。

点击(此处)折叠或打开
  1. //标准的设备描述符结构
  2. typedef struct _device_descriptor
  3. {
  4.     uint8_t     blength; //设备描述符的字节数大小
  5.      uint8_t     bDescriptorType;     //设备描述符类型编号
  6.      uint16_t     bcdUSB; //USB版本号
  7.      uint8_t     bDeviceClass; //USB分配的设备类代码
  8.      uint8_t     bDeviceSubClass; //USB分配的子类代码
  9.      uint8_t     bDeviceProtocol; //USB分配的设备协议代码
  10.      uint8_t     bMaxPacketSize0; //端点0的最大包大小
  11.      uint16_t     idVendor; //厂商编号
  12.      uint16_t     idProduct; //产品编号
  13.      uint16_t     bcdDevice; //设备出厂编号
  14.      uint8_t     iManufacturer; //设备厂商字符串的索引
  15.      uint8_t     iProduct; //描述产品字符串的索引
  16.      uint8_t     iSerialNumber; //描述设备序列号字符串的索引
  17.      uint8_t     bNumConfigurations; //可能的配置数量
  18. }device_descriptor_t;




    4,设备描述符的返回
        现在设备描述符有了,那怎么把它返回给主机呢?
        这个就要通过控制输入端口0 来返回,当主机在下一次发送 IN 令牌后,pdiusbd12 将会自动将端点0输入缓冲区的数据返回给主机,这样就实现了获取设备描述符的请求。

        当数据写入到端点缓冲区之后,还需要使用一个命令将端点的发送缓冲区中的数据设置为有效后,数据才会在直接发送 IN 令牌包后发送出去。
        这个命令就是 Validate Buffer。
        使缓冲区有效(Validate Buffer
        命令Fah 
        数据无
        当微控制器已将数据写入IN 缓冲区它应当通过使缓冲区有效命令设置缓冲区满标志这表示缓冲区内的数据有效并可在接收到下一个IN标志时将其送入主机  

点击(此处)折叠或打开

  1. int32_t        validate_buffer(void)
  2. {
  3.     int32_t        ret = 0;

  4.     write_com(VALIDATE_BUFFER);

  5.     return ret;
  6. }



        写缓冲区
        命令F0h 
        数据写多个字节最大130
        写缓冲区命令后跟一系列需要写入端点缓冲区的数据。数据的结构必须与前面描述的读缓冲区命令一样。
        第一个字节保留总为0。 在DMA写操作中,头两个字节会被绕过。因此第一个写入的字节是数据字节1, 第二个写入的是数据字节2 等等。
        在非同步传输(批量或中断)中,数据被发送到主机之前缓冲区必须被完全填满并切换到下一个缓冲区。
        例外的情况是 ,当前的缓冲区内容将要被发送到主机时,由有效的EOT_N指示DMA传输的结束。

点击(此处)折叠或打开

  1. int32_t        write_endpoint_buffer(uint8_t endpoint,uint8_t *buffer,uint8_t len)
  2. {
  3.     int32_t        ret = 0;
  4.     int32_t        index = 0;

  5.     read_last_status(endpoint);        // 复位中断寄存器中的相应位并将状态清零表示已经读取
  6.     
  7.     /*当一个信息包完全接收之后内部端点缓冲区满标志置位所有后续的包将被返回的NAK拒绝当
  8. 微控制器已读取数据它应当通过清缓冲区命令来释放缓冲区 当缓冲区清空之后新的信息包就可被接
  9. 受了*/
  10.     select_endpoint(endpoint);        // 查看该端点的缓冲区是否满了

  11.     write_com(WRITE_BUFFER);
  12.     write_byte(0x01);                // 任意值
  13.     write_byte(len);                // 要写入到端点缓冲区的字节长点

  14.     for(index = 0; index < len; indexx)
  15.     {
  16.         write_byte(buffer[index]);    
  17.     }

  18.     validate_buffer();                // 是端点缓冲区的数据有效,可以被发送给主机    

  19.     return ret;
  20. }


        




未完,待续。。。



阅读(520) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~