10027|18

238

帖子

2

TA的资源

纯净的硅(高级)

楼主
 

LM3s usb学习(第一章) [复制链接]

  • 小川工作室编写,本书为LM3S的USB芯片编写,上传的均为草稿还有没修改,可能还有很多地方不足,希望各位网友原谅!

    QQ:2609828265

    TEL:15882446438

    E-mail:paulhyde@126.com

1 USB基础

 

1.1  USB介绍

     USBUniversal Serial BUS(通用串行总线)的缩写,而其中文简称为“通用串型总线”,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在PC领域的接口技术。USB接口支持设备的即插即用和热插拔功能。在1994年底由英特尔、康柏、IBMMicrosoft等多家公司联合提出的,目前使用最多的是USB1.1USB2.0,几乎每一台电脑上都有4-8USB接头。USB3.0已经“崛起”,并向下兼容,USB3.0芯片已经大量生产。USB具有传输速度快(USB1.112MbpsUSB2.0480Mbps, USB3.05 Gbps),使用方便,支持热插拔,连接灵活,独立供电等优点,可以连接鼠标、键盘、打印机、扫描仪、摄像头、闪存盘、MP3机、手机、数码相机、移动硬盘、外置光软驱、USB网卡、ADSL ModemCable Modem等,几乎所有的外部设备。所以,掌握一种USB开发是很重要的。

 

 

 

1.2  USB常用术语

USB主机:在任何USB系统中,只有一个主机。USB和主机系统的接口称作主机控制器,主机控制器可由硬件、固件和软件综合实现。

USB设备:主机的下行设备,为系统提供具体功能,并受主机控制的外部USB设备。也称作USB外设,使用USB B型连接器连接。

集线器:集线器扩展了USB主机所能连接设备的数量。

SIE:串行接口引擎,USB控制器内部的核心,将低级信号转换成字节,以供控制器使用,并负责处理底层协议,如填充位、CRC生成和校验,并可发出错误报告。

端点:位于USB外设内部,所有通信数据的来源或目的都基于这些端点,是一个可寻址的FIFO。似于高速公路收费口的入口或出口。一个端点地址对应一个方向。所以,端点2-IN与端点2-OUT完全不同。端点0默认双向控制传输,共享一个FIFO

设备接口:非物理接口,是一种与主机通信的信道管理。设备接口中包含多个端点,与主机进行通信。

描述符:是一个数据结构,使主机了解设备的格式化信息。每一个描述符可能包含整个设备的信息,或是设备中的一个组件。标准USB设备有5种描述符:设备描述符、配置描述符、字符串描述符、接口描述符、端点描述符。

枚举:USB主机通过一系列命令要求设备发送描述符信息。从而知道设备具有什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机确定了这些信息之后,设备才能真正开始工作。

三种传输速率:低速模式传输速率为1.5Mbps,多用于键盘和鼠标。全速模式传输速率为12Mbps。高速模式传输速率为480Mbps

    输入:相对主机而言,如果设备输入端点发送的数据为设备发送数据到主机。

输出:相对主机而言,如果设备输出端点接收的数据为主机发送到设备的数据。

1.3      USB设备枚举

对于USB设备来说,最重要的是枚举,让主机知道设备相关信息。枚举不成功,设备无法识别、使用。本节主要讲枚举过程,有关设备其它信息,请参阅USB官方协议手册。

 

1.3.1    USB设备请求

USB设备与主机连接时会发出USB请求命令。每个请求命令数据包由8个字节(5个字段)组成,具有相同的数据结构。

 

偏移量

大小

描述

0

bmRequestType

1

请求特征

1

bRequest

1

请求命令

2

wValue

2

请求不同,含义不同

4

wIndex

2

索引

请求不同,含义不同

6

wLength

2

数据传输阶段,为数据字节数

 

1. 数据包的格式

C语言数据结构为:

typedef struct

{

    //定义传输方向、接受者、接受者。

    unsigned char bmRequestType;

    //请求类型。

    unsigned char bRequest;

             //根据请求而定实际含义。

unsigned short wValue;

//根据请求而定,提供索引

   unsigned short wIndex;

    //在数据传输阶段时,指示传输数据的字节数

    unsigned short wLength;

}

tUSBRequest;

 

bmRequestType参数:

//7,说明请求的传输方向.

#define USB_RTYPE_DIR_IN        0x80

#define USB_RTYPE_DIR_OUT       0x00

//6:5,定义请求的类型

#define USB_RTYPE_TYPE_M        0x60

#define USB_RTYPE_VENDOR        0x40

#define USB_RTYPE_CLASS         0x20

#define USB_RTYPE_STANDARD      0x00

// 4:0,定义接收者

#define USB_RTYPE_RECIPIENT_M  0x1f

#define USB_RTYPE_OTHER        0x03

#define USB_RTYPE_ENDPOINT     0x02

#define USB_RTYPE_INTERFACE    0x01

#define USB_RTYPE_DEVICE       0x00

    bRequest参数:

//标准请求的请求类型

#define USBREQ_GET_STATUS       0x00

#define USBREQ_CLEAR_FEATURE    0x01

#define USBREQ_SET_FEATURE      0x03

#define USBREQ_SET_ADDRESS      0x05

#define USBREQ_GET_DESCRIPTOR   0x06

#define USBREQ_SET_DESCRIPTOR   0x07

#define USBREQ_GET_CONFIG       0x08

#define USBREQ_SET_CONFIG       0x09

#define USBREQ_GET_INTERFACE    0x0a

#define USBREQ_SET_INTERFACE    0x0b

#define USBREQ_SYNC_FRAME       0x0c

wValue参数:

USBREQ_CLEAR_FEATUREUSBREQ_SET_FEATURE请求命令时:

#define USB_FEATURE_EP_HALT     0x0000     // Endpoint halt feature.

#define USB_FEATURE_REMOTE_WAKE 0x0001   // Remote wake feature, device only.

#define USB_FEATURE_TEST_MODE   0x0002    // Test mode

USBREQ_GET_DESCRIPTOR请求命令时:

#define USB_DTYPE_DEVICE        1

#define USB_DTYPE_CONFIGURATION 2

#define USB_DTYPE_STRING        3

#define USB_DTYPE_INTERFACE     4

#define USB_DTYPE_ENDPOINT      5

#define USB_DTYPE_DEVICE_QUAL   6

#define USB_DTYPE_OSPEED_CONF   7

#define USB_DTYPE_INTERFACE_PWR 8

#define USB_DTYPE_OTG            9

#define USB_DTYPE_INTERFACE_ASC 11

#define USB_DTYPE_CS_INTERFACE  36

请求命令数据包由主机通过端点0发送,当设备端点为接收到请求命令数据包时,会发出端点0中断,控制器可以读取端点0中的数据,此数据格式为tUSBRequest所定义。根据bmRequestType判断是不是标准请求,bRequest获得具体请求类型,wValue指定更具体的对像,wIndex指出索引和偏移。在数据传输阶段时,wLength为传输数据的字节数。整个控制传输都依靠这11个标准请求命令,非标准请求通过callback函数返回给用户处理。

 

1.3.2    设备描述符

每一个设备都有自己的一套完整的描述符,包括设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符。这些描述符反映设备特性,由特定格式排列的一组数据结构组。在USB设备枚举过程中,主机通过标准命令USBREQ_GET_DESCRIPTOR获取描述符,从而得知设备的各种特性。

① 设备描述符:

设备描述符给出了USB设备的一般信息。一个USB设备只能有一个设备描述符。主机发出USBREQ_GET_DESCRIPTOR请求命令,且wValue 值为USB_DTYPE_DEVICE时,获取设备描述符,标准设备描述符如表2

偏移量

大小

描述

0

bLength

1

数字

此描述表的字节数

1

bDecriptorType

1

常量

描述表种类为设备

2

bcdUSB

2

BCD

USB设备版本号(BCD 码)

4

bDeviceClass

1

设备类码

5

bDeviceSubClass

1

子类

子类码

6

bDevicePortocol

1

协议

协议码

7

bMaxPacketSize0

1

数字

端点0最大包大小(8,16,32,64

8

idVendor

2

ID

厂商标志(VID

10

idProduct

2

ID

产品标志(PID

12

bcdDevice

2

BCD

设备发行号(BCD 码)

14

iManufacturer

1

索引

厂商信息字串索引

15

iProduct

1

索引

产品信息字串索引

16

iSerialNumber

1

索引

设备序列号信息字串索引

17

bNumConfigurations

1

数字

配置描述符数目

2. 标准设备描述符

C语言设备描述符结构体为:

typedef struct

{

    //本描述符字节数,设备描述符为18字节。

    unsigned char bLength;

    //本描述符类型,设备描述符为1USB_DTYPE_DEVICE

    unsigned char bDescriptorType;

    //USB版本号

    unsigned short bcdUSB;

    //设备类代码

    unsigned char bDeviceClass;

    //子类代码

    unsigned char bDeviceSubClass;

    //协议代码

    unsigned char bDeviceProtocol;

    //端点0最大包长

    unsigned char bMaxPacketSize0;

    //VIID

    unsigned short idVendor;

              //PID

    unsigned short idProduct;

    //设备发行号

    unsigned short bcdDevice;

//厂商信息字串索引

    unsigned char iManufacturer;

    //产品信息字串索引

    unsigned char iProduct;

    //设备序列号信息字串索引

    unsigned char iSerialNumber;

    //配置描述符数目

    unsigned char bNumConfigurations;

}

tDeviceDescriptor;

bDecriptorType表示本描述符类型,不同描述符,取值不一样:

#define USB_DTYPE_DEVICE        1

#define USB_DTYPE_CONFIGURATION 2

#define USB_DTYPE_STRING        3

#define USB_DTYPE_INTERFACE     4

#define USB_DTYPE_ENDPOINT      5

#define USB_DTYPE_DEVICE_QUAL   6

bDeviceClass本设备使用类的代码。

#define USB_CLASS_DEVICE        0x00

#define USB_CLASS_AUDIO         0x01

#define USB_CLASS_CDC           0x02

#define USB_CLASS_HID           0x03

#define USB_CLASS_PHYSICAL      0x05

#define USB_CLASS_IMAGE         0x06

#define USB_CLASS_PRINTER       0x07

#define USB_CLASS_MASS_STORAGE  0x08

#define USB_CLASS_HUB           0x09

#define USB_CLASS_CDC_DATA      0x0a

#define USB_CLASS_SMART_CARD    0x0b

#define USB_CLASS_SECURITY      0x0d

#define USB_CLASS_VIDEO         0x0e

#define USB_CLASS_HEALTHCARE    0x0f

#define USB_CLASS_DIAG_DEVICE   0xdc

#define USB_CLASS_WIRELESS      0xe0

#define USB_CLASS_MISC          0xef

#define USB_CLASS_APP_SPECIFIC  0xfe

#define USB_CLASS_VEND_SPECIFIC 0xff

#define USB_CLASS_EVENTS        0xffffffff

如果设备为鼠标,则bDeviceClass选为USB_CLASS_HID人机接口。

bDeviceSubClass子类码、bDevicePortocol设备协议码,根据不同的设备类bDeviceClass来选择。例如,bDeviceClass = USB_CLASS_HID,即为人机接口,则bDeviceSubClass有以下参数可选择:

#define USB_HID_SCLASS_NONE     0x00

#define USB_HID_SCLASS_BOOT     0x01

bDevicePortocol有以下参数可选择:

#define USB_HID_PROTOCOL_NONE   0

#define USB_HID_PROTOCOL_KEYB   1

#define USB_HID_PROTOCOL_MOUSE  2

配置一个键盘设备描述符如下:

tDeviceDescriptor  *HIDKEYDeviceDescriptor;

unsigned char g_pHIDDeviceDescriptor[] =

{

    18,                         // Size of this structure.

    USB_DTYPE_DEVICE,           // Type of this structure.

    USBShort(0x110),            // USB version 1.1

    USB_CLASS_HID,              // USB Device Class

    USB_HID_SCLASS_BOOT,        // USB Device Sub-class

    USB_HID_PROTOCOL_KEYB,      // USB Device protocol

    64,                         // Maximum packet size for default pipe.

    USBShort(0x1234),           // Vendor ID (VID).

    USBShort(0x5678),           // Product ID (PID).

    USBShort(0x100),            // Device Version BCD.

    1,                          // Manufacturer string identifier.

    2,                          // Product string identifier.

    3,                          // Product serial number.

    1                           // Number of configurations.

};

HIDKEYDeviceDescriptor = (tDeviceDescriptor   *)g_pHIDDeviceDescriptor;

② 配置描述符

         配置描述符包括描述符的长度、供电方式、最大耗电量等,与设备配置相关的数据组。主机发出USBREQ_GET_DESCRIPTOR请求,且wValue 值为USB_DTYPE_CONFIGURATION时,获取设备描述符,那么此配置包含的所有接口描述符与端点描述符都将发送给USB主机。USB标准配置描述符如下表3

偏移量

大小

描述

0

bLength

1

数字

字节数。

1

bDescriptorType

1

常量

配置描述符类型

2

wTotalLength

2

数字

配置总长(配置、接口、端点、设备类)

4

bNumInterfaces

1

数字

此配置所支持的接口个数

5

bCongfigurationValue

1

数字

USBREQ_SET_CONFIG请求选定此配置

6

iConfiguration

1

索引

配置的字串索引

7

bmAttributes

1

位图

实际电源模式

8

MaxPower

1

mA

总线电源耗费量,以 2mA 为一个单位

3. 标准配置描述符

C语言配置描述符结构体为:

typedef struct

{

    //配置描述符,长度为9

    unsigned char bLength;

    //本描述符类型,2USB_DTYPE_CONFIGURATION

    unsigned char bDescriptorType;

    //配置总长,包括配置、接口、端点、设备类描述符。

    unsigned short wTotalLength;

    //支持接口个数.

    unsigned char bNumInterfaces;

 

    // USBREQ_SET_CONFIG请求选定此配置

    unsigned char bConfigurationValue;

    //配置描述符的字串索引

    unsigned char iConfiguration;

    //电源模式

    unsigned char bmAttributes;

    //最大耗电量。2mA为单位。

    unsigned char bMaxPower;

}

tConfigDescriptor;

bmAttributes电源模式参数:

#define USB_CONF_ATTR_PWR_M     0xC0      //方便使用,定义了一个屏蔽参数。

#define USB_CONF_ATTR_SELF_PWR  0xC0      //自身供电

#define USB_CONF_ATTR_BUS_PWR   0x80      //总线取电

#define USB_CONF_ATTR_RWAKE     0xA0      //Remove Wakeup

配置一个键盘配置描述符如下:

tConfigDescriptor *HIDKEYConfigDescriptor;

unsigned char g_pHIDDescriptor[] =

{

    9,                          // Size of the configuration descriptor.

    USB_DTYPE_CONFIGURATION,    // Type of this descriptor.

    USBShort(34),               // The total size of this full structure.

    1,                          // The number of interfaces in this

                                // configuration.

    1,                          // The unique value for this configuration.

    5,                          // The string identifier that describes this

                                // configuration.

    USB_CONF_ATTR_SELF_PWR,     // Bus Powered, Self Powered, remote wake up.

    250,                        // The maximum power is.500mA.

};

HIDKEYConfigDescriptor = (tConfigDescriptor *)pHIDDescriptor;

③ 接口描述符

    配置描述符中包含了一个或多个接口描述符,“接口”为“功能”意义,例如一个设备既有鼠标功能又有键盘功能,则这个设备至少就有两个“接口”。

    如果配置描述符不止支持一个接口描述符,并且每个接口描述符都有一个或多个端点描述符,那么在响应USB主机的配置描述符命令时,USB设备的端点描述符总是紧跟着相关的接口描述符后面,作为配置描述符的一部分。接口描述符不可用Set_DescriptorGet_Descriptor来存取。如果一个接口仅使用端点0,则接口描述符以后就不再返回端点描述符,并且此接口表现的是一个控制接口的特性,在这种情况下bNumberEndpoints域应被设置成0。接口描述符在说明端点个数并不把端点0计算在内。标准接口描述符如下表4

偏移量

大小

说明

0

bLength

1

数字

此表的字节数

1

bDescriptorType

1

常量

接口描述表类

2

bInterfaceNumber

1

数字

接口号,从零开始

3

bAlternateSetting

1

数字

索引值

4

bNumEndpoints

1

数字

接口端点数量

5

bInterfaceClass

1

类值

6

bInterfaceSubClass

1

子类

子类码

7

bInterfaceProtocol

1

协议

协议码

8

iInterface

1

索引

接口字串描述索引

4. 标准接口描述符

C语言接口描述符结构体为:

typedef struct

{

    //接口描述符长度,9字节。

    unsigned char bLength;

    //本描述符类型,4USB_DTYPE_INTERFACE

    unsigned char bDescriptorType;

    //接口号,从0开始编排。

    unsigned char bInterfaceNumber;

    //接口索引值

    unsigned char bAlternateSetting;

    //本接口使用除端点0外的端点数。

    unsigned char bNumEndpoints;

        //USB接口类码。

    unsigned char bInterfaceClass;

//子类码

    unsigned char bInterfaceSubClass;

    //接口协议

    unsigned char bInterfaceProtocol;

    //描述本接口的字符串索引

    unsigned char iInterface;

}

tInterfaceDescriptor;

bInterfaceClass接口使用类的代码:

#define USB_CLASS_DEVICE        0x00

#define USB_CLASS_AUDIO         0x01

#define USB_CLASS_CDC           0x02

#define USB_CLASS_HID           0x03

#define USB_CLASS_PHYSICAL      0x05

#define USB_CLASS_IMAGE         0x06

#define USB_CLASS_PRINTER       0x07

#define USB_CLASS_MASS_STORAGE  0x08

#define USB_CLASS_HUB           0x09

#define USB_CLASS_CDC_DATA      0x0a

#define USB_CLASS_SMART_CARD    0x0b

#define USB_CLASS_SECURITY      0x0d

#define USB_CLASS_VIDEO         0x0e

#define USB_CLASS_HEALTHCARE    0x0f

#define USB_CLASS_DIAG_DEVICE   0xdc

#define USB_CLASS_WIRELESS      0xe0

#define USB_CLASS_MISC          0xef

#define USB_CLASS_APP_SPECIFIC  0xfe

#define USB_CLASS_VEND_SPECIFIC 0xff

#define USB_CLASS_EVENTS        0xffffffff

例如:定义USB键盘接口描述符:

tInterfaceDescriptor  *HIDKEYIntDescriptor;

unsigned char g_pHIDInterface[] =

{

    9,                          // Size of the interface descriptor.

    USB_DTYPE_INTERFACE,        // Type of this descriptor.

    0,                          // The index for this interface.

    0,                          // The alternate setting for this interface.

    2,                          // The number of endpoints used by this

                                // interface.

    USB_CLASS_HID,              // The interface class

    USB_HID_SCLASS_BOOT,        // The interface sub-class.

    USB_HID_PROTOCOL_KEYB,      // The interface protocol for the sub-class

                                // specified above.

    4,                          // The string index for this interface.

};

字符串描述符

字串描述符是可有可无的,如果一个设备无字串描述符,所有其它描述符中有关字串描述表的索引都必须为0。字串描述符使用UNICODE编码。标准字符串描述符如表5所示:

偏移量

大小

描述

0

bLength

1

数字

此描述表的字节数

1

bDescriptorType

1

常量

字串描述表类型

2

bString

N

数字

UNICODE 编码的字串

5. 标准字符串描述符

C语言字符串描述符结构体为:

typedef struct

{

    //字符串描述总长度

    unsigned char bLength;

    //本描述符类型USB_DTYPE_STRING (3)

    unsigned char bDescriptorType;

    //unicode字符串

    unsigned char bString;

}

tStringDescriptor;

例如:一设备的所有字符串描述符。

//****************************************************************************

// USB 键盘语言描述

//****************************************************************************

const unsigned char g_pLangDescriptor[] =

{

    4,

    USB_DTYPE_STRING,

    USBShort(USB_LANG_EN_US)

};

//****************************************************************************

// 制造商 字符串 描述

//****************************************************************************

const unsigned char g_pManufacturerString[] =

{

    (11 + 1) * 2,

    USB_DTYPE_STRING,

    'O', 0, 'g', 0, 'a', 0, 'w', 0, 'a', 0, 's', 0, 't', 0, 'u', 0, 'd', 0,

    'i', 0, 'o', 0,

};

//****************************************************************************

//产品 字符串 描述

//****************************************************************************

const unsigned char g_pProductString[] =

{

    (17 + 1) * 2,

    USB_DTYPE_STRING,

    'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0,

    'F', 0, 'o', 0, 'r', 0, ' ', 0, 'p', 0, 'a', 0, 'u', 0, 'l' , 0

};

//****************************************************************************

//   产品 序列号 描述

//****************************************************************************

const unsigned char g_pSerialNumberString[] =

{

    (7 + 1) * 2,

    USB_DTYPE_STRING,

    '6', 0, '6', 0, '7', 0, '2', 0, '1', 0, '1', 0, '5', 0,

};

//*****************************************************************************

// 设备接口字符串描述

//*****************************************************************************

const unsigned char g_pHIDInterfaceString[] =

{

    (22 + 1) * 2,

    USB_DTYPE_STRING,

    'H', 0, 'I', 0, 'D', 0, ' ', 0, 'K', 0, 'e', 0, 'y', 0, 'b', 0,

    'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0,

    'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0

};

//*****************************************************************************

//   设备配置字符串描述

//*****************************************************************************

const unsigned char g_pConfigString[] =

{

    (26 + 1) * 2,

    USB_DTYPE_STRING,

    'H', 0, 'I', 0, 'D', 0, ' ', 0, 'K', 0, 'e', 0, 'y', 0, 'b', 0,

    'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0,

    'f', 0, 'i', 0, 'g', 0, 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0,

    'o', 0, 'n', 0

};

//*****************************************************************************

//字符串描述集合

//*****************************************************************************

const unsigned char * const g_pStringDescriptors[] =

{

    g_pLangDescriptor,

    g_pManufacturerString,

    g_pProductString,

    g_pSerialNumberString,

    g_pHIDInterfaceString,

    g_pConfigString

};

也可以使用专用的软件生成USB字符串描述符,从而简化字符串描述符的生成,特别是在使用中文字符串描述符时,更简洁、方便。

 

⑤ 端点描述符

每个接口使用的端点都有自己的描述符,此描述符被主机用来决定每个端点的带宽需求。每个端点的描述符总是作为配置描述符的一部分,端点0无描述符。标准端点描述符如下表6

偏移量

大小

说明

0

bLength

1

数字

字节数

1

bDescriptorType

1

常量

端点描述符类型

2

bEndpointAddress

1

端点

端点的地址及方向

3

bmAttributes

1

位图

传送类型

4

wMaxPacketSize

2

数字

端点能够接收或发送的最大数据包的大小

6

bInterval

1

数字

数据传送端点的时间间隙

5. 标准端点描述符

C语言端点描述符结构体为:

typedef struct

{

    //本描述符总长度

    unsigned char bLength;

    //描述符类型 USB_DTYPE_ENDPOINT (5).   

    unsigned char bDescriptorType;

    //端点地址及方向

    unsigned char bEndpointAddress;

    //传输类型

    unsigned char bmAttributes;

    //传输包最大长度

    unsigned short wMaxPacketSize;

    //时间间隔

    unsigned char bInterval;

}

tEndpointDescriptor;

bEndpointAddress定义端点地址及方向,方向参数如下:

#define USB_EP_DESC_OUT                 0x00

#define USB_EP_DESC_IN                  0x80

bmAttributes定义端点传输类型:

#define USB_EP_ATTR_CONTROL             0x00

#define USB_EP_ATTR_ISOC                0x01

#define USB_EP_ATTR_BULK                0x02

#define USB_EP_ATTR_INT                 0x03

#define USB_EP_ATTR_TYPE_M              0x03

#define USB_EP_ATTR_ISOC_M              0x0c

#define USB_EP_ATTR_ISOC_NOSYNC         0x00

#define USB_EP_ATTR_ISOC_ASYNC          0x04

#define USB_EP_ATTR_ISOC_ADAPT          0x08

#define USB_EP_ATTR_ISOC_SYNC           0x0c

#define USB_EP_ATTR_USAGE_M             0x30

#define USB_EP_ATTR_USAGE_DATA          0x00

#define USB_EP_ATTR_USAGE_FEEDBACK      0x10

#define USB_EP_ATTR_USAGE_IMPFEEDBACK   0x20

键盘端点描述符:

const unsigned char g_pHIDInEndpoint[] =

{

    7,                          // The size of the endpoint descriptor.

    USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.

    USB_EP_DESC_IN | 3,        //  Endpoint 3  -->Input

    USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.

    USBShort(0x8),             // The maximum packet size.

    16,                         // The polling interval for this endpoint.

};

const unsigned char g_pHIDOutEndpoint[] =

{

    7,                          // The size of the endpoint descriptor.

    USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.

    USB_EP_DESC_OUT | 3,       //  Endpoint 3  -->Output

    USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.

    USBShort(0x8),              // The maximum packet size.

    16,                         // The polling interval for this endpoint.

};

g_pHIDInEndpoint定义了端点3方向为输入,g_pHIDOutEndpoint定义了端点3方向为输出,虽然是同一“端点3”,但使用的FIFO不一样,实际为两个端点。犹如高速路出口,一进一出,但是两个路口。注意,每个接口中使用的端点,相应端点描述符必须紧跟接口描述符返回给主机。

 

1.3.3    设备枚举过程

枚举是USB主机通过一系列命令要求设备发送描述符信息,标准USB设备有5种描述符:设备描述符、配置描述符、字符串描述符、接口描述符、端点描述符。枚举过程就是对设备识别过程。

① 首先,USB主机检测到有USB设备插入,会对设备复位。USB设备复位后其地址都为0,主机就可以和刚刚插入的设备通过0地址端点0进行通信。

USB主机对设备发送获取设备描述符的标准请求,设备收到请求后,将设备描述符发给主机。

③ 主机对总线进行复位,之后发送USBREQ_SET_ADDRESS请求,设置设备地址。

④ 主机发送请求到新USB地址,并再获取设备描述符的标准请求。

⑤ 主机获取配置描述符,包括配置描述符、接口描述符、设备类描述符(如HID设备)、端点描述符等。

⑥ 主机根据已获得的描述符,请求相关字符串描述符。

对于HID设备,主机还会请求HID报告描述符。此时枚举完成,USB设备初始化工作完成。可以通过端点与主机通信。

例如:C语言枚举程序。

定义标准请求调用函数,方便使用:

typedef void (* tStdRequest)(void *pvInstance, tUSBRequest *pUSBRequest);

static const tStdRequest g_psUSBDStdRequests[] =

{

    USBDGetStatus,

    USBDClearFeature,

    0,

    USBDSetFeature,

    0,

    USBDSetAddress,

    USBDGetDescriptor,

    USBDSetDescriptor,

    USBDGetConfiguration,

    USBDSetConfiguration,

    USBDGetInterface,

    USBDSetInterface,

    USBDSyncFrame

};

枚举处理主函数:

void USBDeviceEnumHandler(tDeviceInstance *pDevInstance)

{

    unsigned long ulEPStatus;

    //获取端点0的中断情况,并清0

    ulEPStatus = USBEndpointStatus(USB0_BASE, USB_EP_0);

    //判断端点0的当前状态

    switch(pDevInstance->eEP0State)

    {

        //如果处理于等待状态

        case USB_STATE_STATUS:

        {

            //修改端点0为空闲状态

            pDevInstance->eEP0State = USB_STATE_IDLE;

            // 检查地址是否改变。

            if(pDevInstance->ulDevAddress & DEV_ADDR_PENDING)

            {

                //设置设备地址

                pDevInstance->ulDevAddress &= ~DEV_ADDR_PENDING;

                USBDevAddrSet(USB0_BASE, pDevInstance->ulDevAddress);

            }

                //判断端点0是否有数据要接收

            if(ulEPStatus & USB_DEV_EP0_OUT_PKTRDY)

            {

                //接收并处理

                USBDReadAndDispatchRequest(0);

            }

            break;

        }

             //端点0 空闲状态

        case USB_STATE_IDLE:

        {

             //判断端点0是否有数据要接收

            if(ulEPStatus & USB_DEV_EP0_OUT_PKTRDY)

            {

                //接收并处理

                USBDReadAndDispatchRequest(0);

            }

            break;

        }

        //端点0 数据发送阶段

        case USB_STATE_TX:

        {

            USBDEP0StateTx(0);

            break;

        }

        // 发送端点0配置

        case USB_STATE_TX_CONFIG:

        {

            USBDEP0StateTxConfig(0);

            break;

        }

        //接收阶段      

        case USB_STATE_RX:

        {

            unsigned long ulDataSize;

            if(pDevInstance->ulEP0DataRemain > EP0_MAX_PACKET_SIZE)

            {

                ulDataSize = EP0_MAX_PACKET_SIZE;

            }

            else

            {            

                ulDataSize = pDevInstance->ulEP0DataRemain;

            }

            USBEndpointDataGet(USB0_BASE, USB_EP_0, pDevInstance->pEP0Data,

                               &ulDataSize);

            if(pDevInstance->ulEP0DataRemain < EP0_MAX_PACKET_SIZE)

            {             

                USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);

                pDevInstance->eEP0State =  USB_STATE_IDLE;

                if((pDevInstance->psInfo->sCallbacks.pfnDataReceived) &&

                   (pDevInstance->ulOUTDataSize != 0))

                {                   

                    pDevInstance->psInfo->sCallbacks.pfnDataReceived(

                        pDevInstance->pvInstance,

                        pDevInstance->ulOUTDataSize);

                    pDevInstance->ulOUTDataSize = 0;

                }

            }

            else

            {

                USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);

            }

            pDevInstance->pEP0Data += ulDataSize;          

            pDevInstance->ulEP0DataRemain -= ulDataSize;

 

            break;

        }

             // STALL状态

        case USB_STATE_STALL:

        {

            //发送STALL

            if(ulEPStatus & USB_DEV_EP0_SENT_STALL)

            {               

                USBDevEndpointStatusClear(USB0_BASE, USB_EP_0,

                                          USB_DEV_EP0_SENT_STALL);

                pDevInstance->eEP0State = USB_STATE_IDLE;

            }

            break;

        }

        default:

        {

            ASSERT(0);

        }

    }

}

枚举主要发生在端点0处于USB_STATE_STATUSUSB_STATE_IDLE阶段,USBDReadAndDispatchRequest(0)获取主机发送的请求,在内部进行主机请求解析并响应。USBDReadAndDispatchRequest()函数如下:

USBDReadAndDispatchRequest(unsigned long ulIndex)

{

    unsigned long ulSize;

    tUSBRequest *pRequest;

    pRequest = (tUSBRequest *)g_pucDataBufferIn;

    //端点0的最大数据包大小

    ulSize = EP0_MAX_PACKET_SIZE;

    /获取端点0中的数据

    USBEndpointDataGet(USB0_BASE,

                       USB_EP_0,

                       g_pucDataBufferIn,

                       &ulSize);

    //判断是否有数据读出

    if(!ulSize)

    {

        return;

    }

    //判断是否是标准请求

    if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)

    {

        //如果不是标准请求,通过callback函数返回给用户处理。

        if(g_psUSBDevice[0].psInfo->sCallbacks.pfnRequestHandler)

        {

            g_psUSBDevice[0].psInfo->sCallbacks.pfnRequestHandler(

                    g_psUSBDevice[0].pvInstance, pRequest);

        }

        else

        {

            USBDCDStallEP0(0);

        }

    }

    else

    {

        //标准请求,通过g_psUSBDStdRequests调用标准请求处理函数

        if((pRequest->bRequest <

           (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) &&

           (g_psUSBDStdRequests[pRequest->bRequest] != 0))

        {        

            g_psUSBDStdRequests[pRequest->bRequest](&g_psUSBDevice[0],

                                                    pRequest);

        }

        else

        {        

            USBDCDStallEP0(0);

        }

    }

}

标准请求中USBDGetDescriptor函数调用最多,用于描述符获取,使主机充分了解设备特性,是枚举的重要组成部分,下面是USBDGetDescriptor函数:

static void USBDGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest)

{

    tBoolean bConfig;

    tDeviceInstance *psUSBControl;

    tDeviceInfo *psDevice;

    psUSBControl = (tDeviceInstance *)pvInstance;

    psDevice = psUSBControl->psInfo;

    USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);

    bConfig = false;

    //通过Value判断获取什么描述符

    switch(pUSBRequest->wValue >> 8)

    {

        //获取设备描述符    

        case USB_DTYPE_DEVICE:

        {

                //把设备描述放入PEO中,等待发送。

            psUSBControl->pEP0Data =

                (unsigned char *)psDevice->pDeviceDescriptor;

            psUSBControl->ulEP0DataRemain = psDevice->pDeviceDescriptor[0];

            break;

        }

        //获取配置描述符

        case USB_DTYPE_CONFIGURATION:

        {

            const tConfigHeader *psConfig;

            const tDeviceDescriptor *psDeviceDesc;

            unsigned char ucIndex;          

            ucIndex = (unsigned char)(pUSBRequest->wValue & 0xFF);

            psDeviceDesc =

                (const tDeviceDescriptor *)psDevice->pDeviceDescriptor;

            if(ucIndex >= psDeviceDesc->bNumConfigurations)

            {

                USBDCDStallEP0(0);

                psUSBControl->pEP0Data = 0;

                psUSBControl->ulEP0DataRemain = 0;

            }

            else

            {             

                psConfig = psDevice->ppConfigDescriptors[ucIndex];        

                psUSBControl->ucConfigSection = 0;

                psUSBControl->ucSectionOffset = 0;

                psUSBControl->pEP0Data = (unsigned char *)

                                          psConfig->psSections[0]->pucData;              

                psUSBControl->ulEP0DataRemain =

                                            USBDCDConfigDescGetSize(psConfig);

                psUSBControl->ucConfigIndex = ucIndex;

                bConfig = true;

            }

            break;

        }

             //字符串描述符

        case USB_DTYPE_STRING:

        {

            long lIndex;                 

            lIndex = USBDStringIndexFromRequest(pUSBRequest->wIndex,

                                                pUSBRequest->wValue & 0xFF);           

            if(lIndex == -1)

            {

                USBDCDStallEP0(0);

                break;

            }

            psUSBControl->pEP0Data =

                (unsigned char *)psDevice->ppStringDescriptors[lIndex];

            psUSBControl->ulEP0DataRemain =

                psDevice->ppStringDescriptors[lIndex][0];

            break;

        }

        default:

        {

            if(psDevice->sCallbacks.pfnGetDescriptor)

            {

                psDevice->sCallbacks.pfnGetDescriptor(psUSBControl->pvInstance,

                                                      pUSBRequest);

                return;

            }

            else

            {

                USBDCDStallEP0(0);

            }

            break;

        }

    }

    //判断是否有数据要发送

    if(psUSBControl->pEP0Data)

    {

        if(psUSBControl->ulEP0DataRemain > pUSBRequest->wLength)

        {

            psUSBControl->ulEP0DataRemain = pUSBRequest->wLength;

        }

        if(!bConfig)

        {

                //发送上面的配置信息

            USBDEP0StateTx(0);

        }

        else

        {

                //发送端点0的状态信息

            USBDEP0StateTxConfig(0);

        }

    }

}

下面是一个枚举过程:

Start Demo:

Init Hardware...............

LED && KEY  Ok!...............

USB_STATE_IDLE...............(端点0处于USB_STATE_IDLE状态)

0x0008  0x0080  0x0006  0x0100  0x0000  0x0040    (主机请求数据:数据长度+数据包内容)

USBDGetDescriptor...............                  (解析为获取描述符)

USBDGetDescriptor USB_DTYPE_DEVICE.............   (获取设备描述符,并发送设备描述符)

USB_STATE_STATUS...............                   (端点0处于USB_STATE_STATUS状态)

USB_STATE_IDLE...............                    (端点0处于USB_STATE_IDLE状态)

0x0008  0x0000  0x0005  0x0002  0x0000  0x0000    (主机请求数据:数据长度+数据包内容)USBDSetAddress...............             (设置设备地址请求)

USB_STATE_STATUS...............

DEV is 0x0002...............                      (设置设备地址为2

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0100  0x0000  0x0012

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_DEVICE...............(设置地址后,再获取设备描述符)

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0200  0x0000  0x0009

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_CONFIGURATION...............(获取配置描述符)

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0300  0x0000  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............       (获取字符串描述符)

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0303  0x0409  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............

String is 0x0003,Vaule is 0x0409,Index is 0x0003

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0200  0x0000  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_CONFIGURATION...............

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0300  0x0000  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0302  0x0409  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............

String is 0x0002,Vaule is 0x0409,Index is 0x0002

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0300  0x0000  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............

USB_STATE_STATUS...............

USB_STATE_IDLE...............

0x0008  0x0080  0x0006  0x0302  0x0409  0x00ff

USBDGetDescriptor...............

USBDGetDescriptor USB_DTYPE_STRING...............

String is 0x0002,Vaule is 0x0409,Index is 0x0002

USB_STATE_STATUS...............

USB_STATE_IDLE...............

USB_STATE_IDLE...............

以上是枚举的实际过程,从上面枚举过程中可以看出枚举一般过程:上电检测à获取设备描述符à设置设备地址à再次获取设备描述符à获取配置描述符à获取字符串描述符à枚举成功。对于不同系统,枚举过程是不一样的,以上是在win xp下的枚举过程,在Linux下,枚举过程有很大不同。


01 USB基础.pdf (231.05 KB, 下载次数: 554)


 

最新回复

正在学习。谢谢分享  详情 回复 发表于 2012-3-30 15:22
 
点赞 关注
个人签名QQ:1795100002
E-mail:paulhyde@qq.com

回复
举报

1729

帖子

0

TA的资源

五彩晶圆(初级)

沙发
 
写的够详细,支持一个!
 
 

回复

815

帖子

0

TA的资源

纯净的硅(中级)

板凳
 
LZ给力! :
 
 
 

回复

10

帖子

0

TA的资源

一粒金砂(初级)

4
 

回复 楼主 paulhyde 的帖子

谢谢你的用心 我们菜鸟都感谢你
 
 
 

回复

64

帖子

0

TA的资源

一粒金砂(中级)

5
 
不错,USB
 
 
 

回复

1803

帖子

0

TA的资源

五彩晶圆(高级)

6
 

回复 楼主 paulhyde 的帖子

这个帖子太棒了。
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

7
 

楼主好人 非常感谢~ 学习了

 
 
 

回复

391

帖子

1

TA的资源

一粒金砂(高级)

8
 
很好的资料   谢谢分享
 
 
 

回复

2734

帖子

0

TA的资源

裸片初长成(初级)

9
 
拿去看看,给楼主顶一个帖子,算是对于楼主给大家做贡献的一个鼓励吧,嗯嗯,值得值得,希望楼主继续努力啊!加油
 
个人签名我爱电子!
 
 

回复

1万

帖子

16

TA的资源

版主

10
 

谢谢楼主哟

 
个人签名http://shop34182318.taobao.com/
https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
 
 

回复

131

帖子

0

TA的资源

一粒金砂(中级)

11
 

 

 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(中级)

12
 

谢谢楼主!

 
个人签名Jet Law
Email:Jet@jeansway.cn
QQ:1522721646
 
 

回复

8

帖子

0

TA的资源

一粒金砂(中级)

13
 
希望楼主能坚持下去, 支持支持!
 
 
 

回复

41

帖子

0

TA的资源

一粒金砂(中级)

14
 
绝对是好东西   感谢LZ
 
 
 

回复

10

帖子

0

TA的资源

一粒金砂(中级)

15
 
绝对是好东西 感谢LZ
 
 
 

回复

7228

帖子

195

TA的资源

五彩晶圆(高级)

16
 
LM3yeyou 也有USB功能啊  这个真的要学习的
USB用的太多了 啊
顶顶啊
 
 
 

回复

30

帖子

0

TA的资源

一粒金砂(中级)

17
 

谢谢,写得很详细,

 
 
 

回复

1412

帖子

15

TA的资源

版主

18
 
给力
 
个人签名https://bbs.eeworld.com.cn/thread-471646-1-1.html
欢迎加入我的团队
 
 

回复

471

帖子

0

TA的资源

一粒金砂(高级)

19
 
正在学习。谢谢分享
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表