4.1 USB库函数简介

Luminary Micro公司提供USB处理器的USB库函数,应用在Stellaris处理器上,为USB设备、USB主机、OTG开发提供USB协议框架和API函数,适用于多种开发环境:Keil、CSS、IAR、CRT、CCS等。本书中的所有例程都在Keil uv4中编译。

使用USB库开发时,要加入两个已经编译好的.lib。KEIL中建立USB开发工程结构如图1所示:

<ignore_js_op>

图1 文件组织结构

在使用USB库之前必须了解USB库的结构,有助于开发者其理解与使用。USB库分为三个层次:USB设备API、设备类驱动、设备类,如图2 USB库架构:

<ignore_js_op>

图2 USB库架构

从图2中可以看出,最底层驱动是第三章讲的USB驱动程序,只使用USB驱动程序可以进行简单的USB开发。对于更为复杂的USB工程,仅仅使用驱动程序开发是很困难的。在引入USB库后,可以很方便、简单进行复杂的USB工程设计。USB库提供三层API,底层为USB设备API,提供最基础的USB协议和类定义;USB设备驱动是在USB设备API基础上扩展的USB各种设备驱动,比如HID类、CDC类等类驱动;为了更方便程序员使用,还提供设备类API,扩展USB库的使用范围,进一步减轻开发人员的负担,在不用考虑更底层驱动情况下完成USB工程开发。

<ignore_js_op>

图3

同时开发人员可有多种选择,开发USB设备。如图3,开发人员可以使用最底层的API驱动函数进行开发,应用程序通过底层驱动与USB主机通信、控制。但要求开发人员对USB协议完全了解,并熟练于协议编写。

<ignore_js_op>

图4

如图4,开发人员可以在最底层的API驱动函数基础上使用USB库函数的USB设备驱动函数,进行USB控制,应用程序通过底层驱动和USB设备驱动与USB主机通信、控制。减轻了开发人员的负担。

<ignore_js_op>

图5

如图5,开发人员可以利用最底层的API驱动函数、USB设备驱动函数和设备类驱动函数,进行USB开发。设备类驱动主要提供各种USB设备类的驱动,比如Audio类驱动、HID类驱动、Composite类驱动、CDC类驱动、Bulk类驱动、Mass Storage类驱动等6种基本类驱动,其它设备类驱动可以参考这5种驱动的源码,由开发者自己编写。

<ignore_js_op>

图6

如图6,开发人员可以利用最底层的API驱动函数、USB设备驱动函数、设备类驱动函数和设备类API,进行USB开发。设备类API主要提供各种USB设备类操作相关的函数,比如HID中的键盘、鼠标操作接口。设备类API也只提供了5种USB设备类API,其它不常用 的需要开发者自己编写。

Luminary Micro公司提供USB函数库支持多种使用方法,完全能够满足USB产品开发,并且使用方便、快捷。

4.2 使用底层驱动开发

使用最底层USB驱动开发,要求开发人员对USB协议及相关事务彻底了解,开发USB产品有一定难度,但是这种开发模式占用内存少,运行效率高。但有容易出现bug。

例如,使用底层USB驱动开发,开发一个音频设备。

第一:初始化usb处理器,包括内核电压、CPU主频、USB外设资源等。

SysCtlLDOSet(SYSCTL_LDO_2_75V);

// 主频50MHz

SysCtlClockSet(SYSCTL_XTAL_8MHZ | SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL  | SYSCTL_OSC_MAIN );

//打开USB外设

SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);

//打开USB主时钟

SysCtlUSBPLLEnable();

//清除中断标志,并重新打开中断

USBIntStatusControl(USB0_BASE);

USBIntStatusEndpoint(USB0_BASE);

USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |

USB_INTCTRL_DISCONNECT |

USB_INTCTRL_RESUME |

USB_INTCTRL_SUSPEND |

USB_INTCTRL_SOF);

USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);

//断开à连接

USBDevDisconnect(USB0_BASE);

SysCtlDelay(SysCtlClockGet() / 30);

USBDevConnect(USB0_BASE);

//使能总中断

IntEnable(INT_USB0);

//音频设备会传输大量数据,打开DMA最好。

uDMAChannelControlSet(psDevice->psPrivateData->ucOUTDMA,

(UDMA_SIZE_32 | UDMA_SRC_INC_NONE|

UDMA_DST_INC_32 | UDMA_ARB_16));

USBEndpointDMAChannel(USB0_BASE, psDevice->psPrivateData->ucOUTEndpoint,

psDevice->psPrivateData->ucOUTDMA);

第二:USB音频设备描述符。

//语言描述符

const unsigned char g_pLangDescriptor[] =

{

4,

USB_DTYPE_STRING,

USBShort(USB_LANG_EN_US)

};

//制造商 字符串 描述符

const unsigned char g_pManufacturerString[] =

{

(17 + 1) * 2,

USB_DTYPE_STRING,

'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, 's', 0,

't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, 's', 0,

};

//产品 字符串 描述符

const unsigned char g_pProductString[] =

{

(13 + 1) * 2,

USB_DTYPE_STRING,

'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 0, 'E', 0, 'x', 0, 'a', 0,

'm', 0, 'p', 0, 'l', 0, 'e', 0

};

//产品 序列号 描述符

const unsigned char g_pSerialNumberString[] =

{

(8 + 1) * 2,

USB_DTYPE_STRING,

'1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0

};

//设备接口字符串描述符

const unsigned char g_pInterfaceString[] =

{

(15 + 1) * 2,

USB_DTYPE_STRING,

'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 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[] =

{

(20 + 1) * 2,

USB_DTYPE_STRING,

'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 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_pInterfaceString,

g_pConfigString

};

//音频设备描述符

static unsigned char g_pAudioDeviceDescriptor[] =

{

18,                     // Size of this structure.

USB_DTYPE_DEVICE,       // Type of this structure.

USBShort(0x110),        // USB version 1.1 (if we say 2.0, hosts assume

// high-speed - see USB 2.0 spec 9.2.6.6)

USB_CLASS_AUDIO,        // USB Device Class (spec 5.1.1)

USB_SUBCLASS_UNDEFINED, // USB Device Sub-class (spec 5.1.1)

USB_PROTOCOL_UNDEFINED, // USB Device protocol (spec 5.1.1)

64,                     // Maximum packet size for default pipe.

USBShort(0x1111),       // Vendor ID (filled in during USBDAudioInit).

USBShort(0xffee),       // Product ID (filled in during USBDAudioInit).

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

1,                      // Manufacturer string identifier.

2,                      // Product string identifier.

3,                      // Product serial number.

1                       // Number of configurations.

};

//音频配置描述符

static unsigned char g_pAudioDescriptor[] =

{

9,                          // Size of the configuration descriptor.

USB_DTYPE_CONFIGURATION,    // Type of this descriptor.

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

2,                          // The number of interfaces in this

// configuration.

1,                          // The unique value for this configuration.

0,                          // The string identifier that describes this

// configuration.

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

250,                        // The maximum power in 2mA increments.

};

//音频接口描述符

unsigned char g_pIADAudioDescriptor[] =

{

8,                          // Size of the interface descriptor.

USB_DTYPE_INTERFACE_ASC,    // Interface Association Type.

0x0,                        // Default starting interface is 0.

0x2,                        // Number of interfaces in this association.

USB_CLASS_AUDIO,            // The device class for this association.

USB_SUBCLASS_UNDEFINED,     // The device subclass for this association.

USB_PROTOCOL_UNDEFINED,     // The protocol for this association.

0                           // The string index for this association.

};

//音频控制接口描述符

const unsigned char g_pAudioControlInterface[] =

{

9,                          // Size of the interface descriptor.

USB_DTYPE_INTERFACE,        // Type of this descriptor.

AUDIO_INTERFACE_CONTROL,    // The index for this interface.

0,                          // The alternate setting for this interface.

0,                          // The number of endpoints used by this

// interface.

USB_CLASS_AUDIO,            // The interface class

USB_ASC_AUDIO_CONTROL,      // The interface sub-class.

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

// specified above.

0,                          // The string index for this interface.

// Audio Header Descriptor.

9,                          // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_HEADER,        // Descriptor sub-type is HEADER.

USBShort(0x0100),           // Audio Device Class Specification Release

// Number in Binary-Coded Decimal.

// Total number of bytes in

// g_pAudioControlInterface

USBShort((9 + 9 + 12 + 13 + 9)),

1,                          // Number of streaming interfaces.

1,                          // Index of the first and only streaming

// interface.

// Audio Input Terminal Descriptor.

12,                         // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_IN_TERMINAL,   // Descriptor sub-type is INPUT_TERMINAL.

AUDIO_IN_TERMINAL_ID,       // Terminal ID for this interface.

// USB streaming interface.

USBShort(USB_TTYPE_STREAMING),

0,                          // ID of the Output Terminal to which this

// Input Terminal is associated.

2,                          // Number of logical output channels in the

// Terminal抯 output audio channel cluster.

USBShort((USB_CHANNEL_L |   // Describes the spatial location of the

USB_CHANNEL_R)),   // logical channels.

0,                          // Channel Name string index.

0,                          // Terminal Name string index.

// Audio Feature Unit Descriptor

13,                         // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_FEATURE_UNIT,  // Descriptor sub-type is FEATURE_UNIT.

AUDIO_CONTROL_ID,           // Unit ID for this interface.

AUDIO_IN_TERMINAL_ID,       // ID of the Unit or Terminal to which this

// Feature Unit is connected.

2,                          // Size in bytes of an element of the

// bmaControls() array that follows.

// Master Mute control.

USBShort(USB_ACONTROL_MUTE),

// Left channel volume control.

USBShort(USB_ACONTROL_VOLUME),

// Right channel volume control.

USBShort(USB_ACONTROL_VOLUME),

0,                          // Feature unit string index.

// Audio Output Terminal Descriptor.

9,                          // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_OUT_TERMINAL,  // Descriptor sub-type is INPUT_TERMINAL.

AUDIO_OUT_TERMINAL_ID,      // Terminal ID for this interface.

// Output type is a generic speaker.

USBShort(USB_ATTYPE_SPEAKER),

AUDIO_IN_TERMINAL_ID,       // ID of the input terminal to which this

// output terminal is connected.

AUDIO_CONTROL_ID,           // ID of the feature unit that this output

// terminal is connected to.

0,                          // Output terminal string index.

};

//音频流接口描述符

const unsigned char g_pAudioStreamInterface[] =

{

9,                          // Size of the interface descriptor.

USB_DTYPE_INTERFACE,        // Type of this descriptor.

AUDIO_INTERFACE_OUTPUT,     // The index for this interface.

0,                          // The alternate setting for this interface.

0,                          // The number of endpoints used by this

// interface.

USB_CLASS_AUDIO,            // The interface class

USB_ASC_AUDIO_STREAMING,    // The interface sub-class.

0,                          // Unused must be 0.

0,                          // The string index for this interface.

// Vendor-specific Interface Descriptor.

9,                          // Size of the interface descriptor.

USB_DTYPE_INTERFACE,        // Type of this descriptor.

1,                          // The index for this interface.

1,                          // The alternate setting for this interface.

1,                          // The number of endpoints used by this

// interface.

USB_CLASS_AUDIO,            // The interface class

USB_ASC_AUDIO_STREAMING,    // The interface sub-class.

0,                          // Unused must be 0.

0,                          // The string index for this interface.

// Class specific Audio Streaming Interface descriptor.

7,                          // Size of the interface descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ASDSTYPE_GENERAL,       // General information.

AUDIO_IN_TERMINAL_ID,       // ID of the terminal to which this streaming

// interface is connected.

1,                          // One frame delay.

USBShort(USB_ADF_PCM),      //

// Format type Audio Streaming descriptor.

11,                         // Size of the interface descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ASDSTYPE_FORMAT_TYPE,   // Audio Streaming format type.

USB_AF_TYPE_TYPE_I,         // Type I audio format type.

2,                          // Two audio channels.

2,                          // Two bytes per audio sub-frame.

16,                         // 16 bits per sample.

1,                          // One sample rate provided.

USB3Byte(48000),            // Only 48000 sample rate supported.

// Endpoint Descriptor

9,                              // The size of the endpoint descriptor.

USB_DTYPE_ENDPOINT,             // Descriptor type is an endpoint.

// OUT endpoint with address

// ISOC_OUT_ENDPOINT.

USB_EP_DESC_OUT | USB_EP_TO_INDEX(ISOC_OUT_ENDPOINT),

USB_EP_ATTR_ISOC |              // Endpoint is an adaptive isochronous data

USB_EP_ATTR_ISOC_ADAPT |        //  endpoint.

USB_EP_ATTR_USAGE_DATA,

USBShort(ISOC_OUT_EP_MAX_SIZE), // The maximum packet size.

1,                              // The polling interval for this endpoint.

0,                              // Refresh is unused.

0,                              // Synch endpoint address.

// Audio Streaming Isochronous Audio Data Endpoint Descriptor

7,                              // The size of the descriptor.

USB_ACSDT_ENDPOINT,             // Audio Class Specific Endpoint Descriptor.

USB_ASDSTYPE_GENERAL,           // This is a general descriptor.

USB_EP_ATTR_ACG_SAMPLING,       // Sampling frequency is supported.

USB_EP_LOCKDELAY_UNDEF,         // Undefined lock delay units.

USBShort(0),                    // No lock delay.

};

第三:USB音频设备枚举。

/枚举用到函数

static void USBDGetStatus(tUSBRequest *pUSBRequest);

static void USBDClearFeature(tUSBRequest *pUSBRequest);

static void USBDSetFeature(tUSBRequest *pUSBRequest);

static void USBDSetAddress(tUSBRequest *pUSBRequest);

static void USBDGetDescriptor(tUSBRequest *pUSBRequest);

static void USBDSetDescriptor(tUSBRequest *pUSBRequest);

static void USBDGetConfiguration(tUSBRequest *pUSBRequest);

static void USBDSetConfiguration(tUSBRequest *pUSBRequest);

static void USBDGetInterface(tUSBRequest *pUSBRequest);

static void USBDSetInterface(tUSBRequest *pUSBRequest);

static void USBDEP0StateTx(void);

static long USBDStringIndexFromRequest(unsigned short usLang,

unsigned short usIndex);

//该结构能够完整表述USB设备枚举过程。

typedef struct

{

//当前USB设备地址,也可以能过DEV_ADDR_PENDING最高位改变.

volatile unsigned long ulDevAddress;

//保存设备当前生效的配置.

unsigned long ulConfiguration;

//当前设备的接口设置

unsigned char ucAltSetting;

//指向端点0正发接收或者发送的数据组。

unsigned char *pEP0Data;

//指示端点0正发接收或者发送数据的剩下数据量。

volatile unsigned long ulEP0DataRemain;

//端点0正发接收或者发送数据的数据总量

unsigned long ulOUTDataSize;

//当前设备状态

unsigned char ucStatus;

//在处理过程中是否使用wakeup信号。

tBoolean bRemoteWakeup;

//bRemoteWakeup信号计数。

unsigned char ucRemoteWakeupCount;

}

tDeviceState;

//定义端点输出/输入。

#define HALT_EP_IN              0

#define HALT_EP_OUT             1

//端点0的状态,在枚举过程中使用。

typedef enum

{

//等待主机请求。

USB_STATE_IDLE,

//通过IN端口0给主机发送数块。

USB_STATE_TX,

//通过OUT端口0从主机接收数据块。

USB_STATE_RX,

//端点0发送/接收完成,等待主机应答。

USB_STATE_STATUS,

//端点0STALL,等待主机响应STALL。

USB_STATE_STALL

}

tEP0State;

//端点0最大传输包大小。

#define EP0_MAX_PACKET_SIZE     64

//用于指示设备地址改变

#define DEV_ADDR_PENDING        0x80000000

//总线复位后,默认的配置编号。

#define DEFAULT_CONFIG_ID       1

//REMOTE_WAKEUP的信号毫秒数,在协议中定义为1ms-15ms.

#define REMOTE_WAKEUP_PULSE_MS 10

//REMOTE_WAKEUP保持20ms.

#define REMOTE_WAKEUP_READY_MS 20

//端点0的读数据缓存。

static unsigned char g_pucDataBufferIn[EP0_MAX_PACKET_SIZE];

//定义当前设备状态信息实例。

static volatile tDeviceState g_sUSBDeviceState;

//定义当前端点0的状态

static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE;

//请求函数表。

static const tStdRequest g_psUSBDStdRequests[] =

{

USBDGetStatus,

USBDClearFeature,

0,

USBDSetFeature,

0,

USBDSetAddress,

USBDGetDescriptor,

USBDSetDescriptor,

USBDGetConfiguration,

USBDSetConfiguration,

USBDGetInterface,

USBDSetInterface,

};

//在读取usb中断时合并使用。

#define USB_INT_RX_SHIFT        8

#define USB_INT_STATUS_SHIFT    24

#define USB_RX_EPSTATUS_SHIFT   16

//端点控制状态寄存器转换

#define EP_OFFSET(Endpoint)     (Endpoint - 0x10)

//从端点0的FIFO中获取数据。

long USBEndpoint0DataGet(unsigned char *pucData, unsigned long *pulSize)

{

unsigned long ulByteCount;

//判断端点0的数据是否接收完成。

if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0)

{

*pulSize = 0;

return(-1);

}

//USB_O_COUNT0指示端点0收到的数据量。

ulByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0);

//确定读回的数据量。

ulByteCount = (ulByteCount < *pulSize) ? ulByteCount : *pulSize;

*pulSize = ulByteCount;

//从FIFO中读取数据。

for(; ulByteCount > 0; ulByteCount--)

{

*pucData++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2));

}

return(0);

}

//端点0应答。

void USBDevEndpoint0DataAck(tBoolean bIsLastPacket)

{

HWREGB(USB0_BASE + USB_O_CSRL0) =

USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0);

}

// 向端点0中放入数据。

long USBEndpoint0DataPut(unsigned char *pucData, unsigned long ulSize)

{

if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)

{

return(-1);

}

for(; ulSize > 0; ulSize--)

{

HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pucData++;

}

return(0);

}

//向端点0中写入数据。

long USBEndpoint0DataSend(unsigned long ulTransType)

{

//判断是否已经有数据准备好。

if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)

{

return(-1);

}

HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ulTransType & 0xff;

return(0);

}

//端点0从主机上获取数据。

void USBRequestDataEP0(unsigned char *pucData, unsigned long ulSize)

{

g_eUSBDEP0State = USB_STATE_RX;

g_sUSBDeviceState.pEP0Data = pucData;

g_sUSBDeviceState.ulOUTDataSize = ulSize;

g_sUSBDeviceState.ulEP0DataRemain = ulSize;

}

//端点0请求发送数据。

void USBSendDataEP0(unsigned char *pucData, unsigned long ulSize)

{

g_sUSBDeviceState.pEP0Data = pucData;

g_sUSBDeviceState.ulEP0DataRemain = ulSize;

g_sUSBDeviceState.ulOUTDataSize = ulSize;

USBDEP0StateTx();

}

//端点0处于停止状态。

void USBStallEP0(void)

{

HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);

g_eUSBDEP0State = USB_STATE_STALL;

}

//从端点0中获取一个请求。

static void USBDReadAndDispatchRequest(void)

{

unsigned long ulSize;

tUSBRequest *pRequest;

pRequest = (tUSBRequest *)g_pucDataBufferIn;

ulSize = EP0_MAX_PACKET_SIZE;

USBEndpoint0DataGet(g_pucDataBufferIn, &ulSize);

if(!ulSize)

{

return;

}

//判断是否是标准请求。

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

{

UARTprintf("非标准请求...............\r\n");

}

else

{

//调到标准请求处理函数中。

if((pRequest->bRequest <

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

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

{

g_psUSBDStdRequests[pRequest->bRequest](pRequest);

}

else

{

USBStallEP0();

}

}

}

//枚举过程。

// USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE

//                 |                  |                     |

//                 |--> USB_STATE_RX -                      |

//                 |                                        |

//                 |--> USB_STATE_STALL ---------->---------

//

//  ----------------------------------------------------------------

// | Current State       | State 0           | State 1              |

// | --------------------|-------------------|----------------------

// | USB_STATE_IDLE      | USB_STATE_TX/RX   | USB_STATE_STALL      |

// | USB_STATE_TX        | USB_STATE_STATUS  |                      |

// | USB_STATE_RX        | USB_STATE_STATUS  |                      |

// | USB_STATE_STATUS    | USB_STATE_IDLE    |                      |

// | USB_STATE_STALL     | USB_STATE_IDLE    |                      |

//  ----------------------------------------------------------------

void USBDeviceEnumHandler(void)

{

unsigned long ulEPStatus;

//获取中断状态。

ulEPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1);

ulEPStatus |= ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) <<

USB_RX_EPSTATUS_SHIFT);

//端点0的状态。

switch(g_eUSBDEP0State)

{

case USB_STATE_STATUS:

{

UARTprintf("USB_STATE_STATUS...............\r\n");

g_eUSBDEP0State = USB_STATE_IDLE;

//判断地址改变。

if(g_sUSBDeviceState.ulDevAddress & DEV_ADDR_PENDING)

{

//设置地址。

g_sUSBDeviceState.ulDevAddress &= ~DEV_ADDR_PENDING;

HWREGB(USB0_BASE + USB_O_FADDR) =

(unsigned char)g_sUSBDeviceState.ulDevAddress;

}

//端点0接收包准备好。

if(ulEPStatus & USB_DEV_EP0_OUT_PKTRDY)

{

USBDReadAndDispatchRequest();

}

break;

}

//等待从主机接收数据。

case USB_STATE_IDLE:

{

if(ulEPStatus & USB_DEV_EP0_OUT_PKTRDY)

{

USBDReadAndDispatchRequest();

}

break;

}

//数据处理好,准备发送。

case USB_STATE_TX:

{

USBDEP0StateTx();

break;

}

//接收数据。

case USB_STATE_RX:

{

unsigned long ulDataSize;

if(g_sUSBDeviceState.ulEP0DataRemain > EP0_MAX_PACKET_SIZE)

{

ulDataSize = EP0_MAX_PACKET_SIZE;

}

else

{

ulDataSize = g_sUSBDeviceState.ulEP0DataRemain;

}

USBEndpoint0DataGet(g_sUSBDeviceState.pEP0Data, &ulDataSize);

if(g_sUSBDeviceState.ulEP0DataRemain < EP0_MAX_PACKET_SIZE)

{

USBDevEndpoint0DataAck(true);

g_eUSBDEP0State =  USB_STATE_IDLE;

if(g_sUSBDeviceState.ulOUTDataSize != 0)

{

}

}

else

{

USBDevEndpoint0DataAck(false);

}

g_sUSBDeviceState.pEP0Data += ulDataSize;

g_sUSBDeviceState.ulEP0DataRemain -= ulDataSize;

break;

}

//停止状态

case USB_STATE_STALL:

{

if(ulEPStatus & USB_DEV_EP0_SENT_STALL)

{

HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL);

g_eUSBDEP0State = USB_STATE_IDLE;

}

break;

}

default:

{

break;

}

}

}

设备枚举过程中USBDSetAddress和USBDGetDescriptor很重要,下面只列出这两个函数的具体内容。

// SET_ADDRESS 标准请求。

static void USBDSetAddress(tUSBRequest *pUSBRequest)

{

USBDevEndpoint0DataAck(true);

g_sUSBDeviceState.ulDevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING;

g_eUSBDEP0State = USB_STATE_STATUS;

//HandleSetAddress();

}

//GET_DESCRIPTOR 标准请求。

static void USBDGetDescriptor(tUSBRequest *pUSBRequest)

{

USBDevEndpoint0DataAck(false);

switch(pUSBRequest->wValue >> 8)

{

case USB_DTYPE_DEVICE:

{

g_sUSBDeviceState.pEP0Data =

(unsigned char *)g_pDFUDeviceDescriptor;

g_sUSBDeviceState.ulEP0DataRemain = g_pDFUDeviceDescriptor[0];

break;

}

case USB_DTYPE_CONFIGURATION:

{

unsigned char ucIndex;

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

if(ucIndex != 0)

{

USBStallEP0();

g_sUSBDeviceState.pEP0Data = 0;

g_sUSBDeviceState.ulEP0DataRemain = 0;

}

else

{

g_sUSBDeviceState.pEP0Data =

(unsigned char *)g_pDFUConfigDescriptor;

g_sUSBDeviceState.ulEP0DataRemain =

*(unsigned short *)&(g_pDFUConfigDescriptor[2]);

}

break;

}

case USB_DTYPE_STRING:

{

long lIndex;

lIndex = USBDStringIndexFromRequest(pUSBRequest->wIndex,

pUSBRequest->wValue & 0xFF);

if(lIndex == -1)

{

USBStallEP0();

break;

}

g_sUSBDeviceState.pEP0Data =

(unsigned char *)g_pStringDescriptors[lIndex];

g_sUSBDeviceState.ulEP0DataRemain = g_pStringDescriptors[lIndex][0];

break;

}

case 0x22:

{

//USBDevEndpoint0DataAck(false);

g_sUSBDeviceState.pEP0Data = (unsigned char *)ReportDescriptor;

g_sUSBDeviceState.ulEP0DataRemain = sizeof(&ReportDescriptor[0]);

//USBDEP0StateTx();

}

default:

{

USBStallEP0();

break;

}

}

if(g_sUSBDeviceState.pEP0Data)

{

if(g_sUSBDeviceState.ulEP0DataRemain > pUSBRequest->wLength)

{

g_sUSBDeviceState.ulEP0DataRemain = pUSBRequest->wLength;

}

USBDEP0StateTx();

}

}

第四:USB音频数据处理与控制。此过程包括数据处理,音量控制,静音控制等,控制过程较为复杂,在此不在一一讲解,可以参考相关USB音频设备书籍。在第6章有讲其它方法进行开发。

4.3 使用USB库开发

使用USB库函数进行开发,开发人员可以不深入研究USB协议,包括枚举过程、中断处理、数据处理等。使用库函数提供的API接口函数就可以完成开发工作。使用USB库函数方便、快捷、缩短开发周期、不易出现bug,但占用存储空间、内存较大,由于Stellaris  USB处理器的存储空间达128K,远远超过程序需要的存储空间,所以使用USB库函数开发是比较好的方法。

例如:使用库函数开发一个USB鼠标。

1.完成字符串描述符。

//语言描述符

const unsigned char g_pLangDescriptor[] =

{

4,

USB_DTYPE_STRING,

USBShort(USB_LANG_EN_US)

};

//制造商 字符串 描述符

const unsigned char g_pManufacturerString[] =

{

(17 + 1) * 2,

USB_DTYPE_STRING,

'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, 's', 0,

't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, 's', 0,

};

//产品 字符串 描述符

const unsigned char g_pProductString[] =

{

(13 + 1) * 2,

USB_DTYPE_STRING,

'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, 'E', 0, 'x', 0, 'a', 0,

'm', 0, 'p', 0, 'l', 0, 'e', 0

};

//产品 序列号 描述符

const unsigned char g_pSerialNumberString[] =

{

(8 + 1) * 2,

USB_DTYPE_STRING,

'1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0

};

//设备接口字符串描述

const unsigned char g_pHIDInterfaceString[] =

{

(19 + 1) * 2,

USB_DTYPE_STRING,

'H', 0, 'I', 0, 'D', 0, ' ', 0, 'M', 0, 'o', 0, 'u', 0, 's', 0,

'e', 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[] =

{

(23 + 1) * 2,

USB_DTYPE_STRING,

'H', 0, 'I', 0, 'D', 0, ' ', 0, 'M', 0, 'o', 0, 'u', 0, 's', 0,

'e', 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

};

#define NUM_STRING_DESCRIPTORS (sizeof(g_pStringDescriptors) /                \

sizeof(unsigned char *))

2.了解鼠标设备tUSBDHIDMouseDevice在库函数中的定义,并完成鼠标设备实例。

//定义USB鼠标实例

tHIDMouseInstance g_sMouseInstance;

//定义USB鼠标相关信息

const tUSBDHIDMouseDevice g_sMouseDevice =

{

USB_VID_STELLARIS,

USB_PID_MOUSE,

500,

USB_CONF_ATTR_SELF_PWR,

MouseHandler,

(void *)&g_sMouseDevice,

g_pStringDescriptors,

NUM_STRING_DESCRIPTORS,

&g_sMouseInstance

};

3.初始化USB鼠标设备,并进行数据处理。

//初始化USB鼠标设备,只需用这个函数就完成配置,包括枚举配置。

USBDHIDMouseInit(0, (tUSBDHIDMouseDevice *)&g_sMouseDevice);

//数据处理,改变鼠标位置和按键状态。

USBDHIDMouseStateChange((void *)&g_sMouseDevice,

(char)lDeltaX, (char)lDeltaY,

ucButtons);

从库函数开发USB鼠标设备过程中可以看出,使用USB库函数开发非常简单、方便、快捷,不用考虑底层的驱动、类协议。在HID类中,报告符本身就很复杂,但是使用USB库函数开发完全屏蔽报告符配置过程。从第五章开始介绍使用USB库函数开发USB设备与主机。

最新文章

  1. 作为前端应当了解的Web缓存知识
  2. Android杂记:genymotion与eclipse报错问题
  3. oracle用户创建及权限设置
  4. 实现3D摄像机缓冲系统的一些思考
  5. apache开源项目 -- VXQuery
  6. Nginx高性能服务器安装、配置、运维 (3) —— Nginx配置详解
  7. 1_使用Java文件的并发写
  8. 2 weekend110的hadoop的自定义排序实现 + mr程序中自定义分组的实现
  9. this关键字的解析
  10. find tar 压缩第一层目录,用于资料备份。
  11. Unity_新手必懂知识点
  12. ArrayList源码学习
  13. Oracle 12C CRS-5013
  14. 视频人脸检测——Dlib版(六)
  15. 2.4 if-else
  16. Oracle12c Release1 安装图解(详解)
  17. Java WebSocket实现网络聊天室(群聊+私聊)
  18. 复习一下property
  19. 如何减少block的嵌套层次?
  20. javascript面向对象之Object.defineProperty(a,b,c)

热门文章

  1. VBA实现随意输入组合码,查询唯一标识码
  2. zabbix的邮件报警
  3. RDLC打印或导出Word的 分页设置 页边距和页面大小
  4. UITableViewCell和UITableViewHeaderFooterView的重用
  5. 12天学好C语言——记录我的C语言学习之路(Day 7)
  6. sgu 110 Dungeon
  7. PHP学习笔记——上传文件到服务端的文件夹下
  8. 未指定的错误,发生了一个 Oracle 错误,但无法从 Oracle 中检索错误信息。数据类型不被支持。
  9. 一个空格也可以让html格式显示大不相同
  10. normalize.css介绍