6324|6

238

帖子

2

TA的资源

纯净的硅(高级)

楼主
 

第四章 USB库介绍 [复制链接]

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

QQ:2609828265

TEL:15882446438

E-mail:paulhyde@126.com

第四章 USB库介绍

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所示:


文件组织结构

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


2 USB库架构

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


图3

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


图4

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


图5

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


图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;

        }

    }

}

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

// 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设备与主机。


04 USB库介绍.pdf (140.49 KB, 下载次数: 457)


最新回复

:carnation: :carnation: :carnation: 及时雨啊  详情 回复 发表于 2012-11-19 15:58
 
点赞 关注
个人签名QQ:1795100002
E-mail:paulhyde@qq.com

回复
举报

1729

帖子

0

TA的资源

五彩晶圆(初级)

沙发
 
MARK 下,回去慢慢看!
 
 

回复

25

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
谢谢分享!多谢!
 
 
 

回复

299

帖子

0

TA的资源

纯净的硅(高级)

4
 
好东西,期待楼主更多的分享。
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(初级)

5
 
thanks thanks
 
 
 

回复

4138

帖子

0

TA的资源

五彩晶圆(中级)

6
 
thank you xiao chuan
 
 
 

回复

31

帖子

0

TA的资源

一粒金砂(中级)

7
 
:carnation: :carnation: :carnation: 及时雨啊
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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