6.1 Audio设备介绍

USB协议制定时,为了方便不同设备的开发商基于USB进行设计,定义了不同的设备类来支持不同类型的设备。虽然在USB标准中定义了USB_DEVICE_CLASS_AUDIO--AUDIO设备。但是很少有此类设备问世。目前称为USB音箱的设备,大都使用 USB_DEVICE_CLASS_POWER,仅仅将USB接口作为电源使用。完全基于USB协议的USB_DEVICE_CLASS_AUDIO设备,采用一根USB连接线,在设备中不同的端点实现音频信号的输入,输出包括相关按键控制。

AUDIO设备是专门针对USB音频设备定义的一种专用类别,它不仅定义了音频输入、输出端点的标准,还提供了音量控制、混音器配置、左右声道平衡,甚至包括对支持杜比音效解码设备的支持,功能相当强大。不同的开发者可以根据不同的需求对主机枚举自己的设备结构,主机则根据枚举的不同设备结构提供相应的服务。

AUDIO设备采用USB传输模式中的Isochronous transfers模式,Isochronous transfers传输模式是专门针对流媒体特点的传输方法。它依照设备在链接初始化时枚举的参数,保证提供稳定的带宽给采用该模式的设备或端点。由于对实时性的要求,它不提供相应的接收/应答和握手协议。这很好地适应了音频数据流量稳定、对差错相对不敏感的特点。

6.2 Audio描述符

Audio设备定义了三种接口描述符子类,子协议恒为0x00。三种接口描述符子类分别定义为:

// Audio Interface Subclass Codes

#define USB_ASC_AUDIO_CONTROL   0x01

#define USB_ASC_AUDIO_STREAMING 0x02

#define USB_ASC_MIDI_STREAMING  0x03

USB_ASC_AUDIO_CONTROL,音频设备控制类;USB_ASC_AUDIO_STREAMING,音频流类;USB_ASC_MIDI_STREAMING,MIDI流类。以上三种用于描述接口描述符的子类,确定被描述接口的功能。Audio设备没有定义子协议,所以为定值0x00。

Audio设备接口描述符中要包含Class-Specific AC Interface Header Descriptor,用于定义接口的其它功能端口。Class-Specific AC Interface Header Descriptor(AC 接口头)描述符如下表:

偏移量

大小

描述

0

bLength

1

数字

字节数。

1

bDescriptorType

1

常量

配置描述符类型USB_DTYPE_CS_INTERFACE(36)

2

bDescriptorSubtype

1

数字

AC接口头:USB_DSUBTYPE_HEADER

3

bcdADC

2

数字

Audio设备发行号,BCD码

5

wTotalLength

2

数字

接口描述符总长度,包括标准接口描述符

6

bInCollection

1

索引

AudioStreaming、 MIDIStreaming使用代码

7

baInterfaceNr

2

位图

使用AudioStreaming 或者MIDIStreaming的接口号

表1. AC 接口头描述符

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

typedef struct

{

//本描述符长度.

unsigned char bLength;

//描述类型USB_DTYPE_CS_INTERFACE (36).

unsigned char bDescriptorSubtype;

//发行号(BCD码)

unsigned short bcdADC;

//接口描述符总长度,包括标准接口描述符

unsigned short wTotalLength;

// AudioStreaming、 MIDIStreaming使用代码

unsigned char bInCollection;

// 使用AudioStreaming 或者MIDIStreaming的接口号

unsigned char baInterfaceNr;

}

tACHeader;

例如:定义一个实际的AC 接口头描述符。

const unsigned char g_pAudioInterfaceHeader[] =

{

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),对于输入端定义。输入端口描述符如下表:

偏移量

大小

描述

0

bLength

1

数字

字节数。

1

bDescriptorType

1

常量

配置描述符类型USB_DTYPE_CS_INTERFACE(36)

2

bDescriptorSubtype

1

常量

USB_ACDSTYPE_IN_TERMINAL

3

bTerminalID

1

常量

本端口ID号

4

wTerminalType

2

常量

端口类型

6

bAssocTerminal

1

常量

对应输出端口ID

7

bNrChannels

2

位图

通道数量

8

wChannelConfig

2

数字

通道配置

10

iChannelNames

1

常量

通道名字

11

iTerminal

1

数字

端口字符串描述符索引

表1. HID描述符符

C语言输入端口描述符结构体为:

typedef struct

{

unsigned char bLength;

unsigned char bDescriptorType;

unsigned char bDescriptorSubtype;

unsigned char bTerminalID;

unsigned short wTerminalType;

unsigned char bAssocTerminal;

unsigned char bNrChannels;

unsigned short wChannelConfig;

unsigned char iChannelNames;

unsigned char iTerminal;

}

tACInputTerminal;

Audio设备的输出端口描述符(Output Terminal Descriptor),对于输出端定义。输出端口描述符如下表:

偏移量

大小

描述

0

bLength

1

数字

字节数。

1

bDescriptorType

1

常量

配置描述符类型USB_DTYPE_CS_INTERFACE(36)

2

bDescriptorSubtype

1

常量

USB_ACDSTYPE_OUT_TERMINAL

3

bTerminalID

1

常量

本端口ID号

4

wTerminalType

2

常量

端口类型

6

bAssocTerminal

1

常量

对应输入端口ID

7

bSourceID

1

常量

连接端口的ID号

8

iTerminal

1

数字

端口字符串描述符索引

表1. HID描述符符

C语言输出端口描述符结构体为:

typedef struct

{

unsigned char bLength;

unsigned char bDescriptorType;

unsigned char bDescriptorSubtype;

unsigned char bTerminalID;

unsigned short wTerminalType;

unsigned char bAssocTerminal;

unsigned char bSourceID;

unsigned char iTerminal;

}

tACOutputTerminal;

其它与Audio设备相关的描述符,请读者参阅USB_Audio_Class手册。下面列出一个Audio设备的接口描述符:

const unsigned char g_pAudioControlInterface[] =

{

//标准接口描述符

9,                          // Size of the interface descriptor.

USB_DTYPE_INTERFACE,        // Type of this descriptor.

AUDIO_INTERFACE_CONTROL,    // 接口编号,从0开发编. AUDIO_INTERFACE_CONTROL = 0

0,                          // The alternate setting for this interface.

0,                          // The number of endpoints used by this interface.

USB_CLASS_AUDIO,            // AUDIO设备

USB_ASC_AUDIO_CONTROL,      // 子类,USB_ASC_AUDIO_CONTROL用于Audio控制.

0,                          // 无协议,定值0。

0,                          // The string index for this interface.

// Audio接口头描述符.

9,                          // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // 描述符类型.

USB_ACDSTYPE_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设备输入端口描述符.

12,                         // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_IN_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设备特征单元描述符

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.

//输出端口描述符.

9,                          // The size of this descriptor.

USB_DTYPE_CS_INTERFACE,     // Interface descriptor is class specific.

USB_ACDSTYPE_OUT_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.

//端点描述符

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.

};

6.3 Audio数据类型

usbdaudio.h中已经定义好Audio设备类中使用的所有数据类型和函数,下面介绍Audio设备类使用的数据类型。

typedef struct

{

unsigned long ulUSBBase;

//设备信息指针

tDeviceInfo *psDevInfo;

//配置描述符

tConfigDescriptor *psConfDescriptor;

//最大音量值

short sVolumeMax;

//最小音量值

short sVolumeMin;

//音量控制阶梯值

short sVolumeStep;

struct

{

//callback入口参数

void *pvData;

// pvData 大小

unsigned long ulSize;

// 可用pvData大小

unsigned long ulNumBytes;

// Callback

tUSBAudioBufferCallback pfnCallback;

} sBuffer;

//请求类型.

unsigned short usRequestType;

//请求标志

unsigned char ucRequest;

// 更新值

unsigned short usUpdate;

// 当前音量设置.

unsigned short usVolume;

// 静音设置.

unsigned char ucMute;

//采样率

unsigned long ulSampleRate;

// 使用输出端点

unsigned char ucOUTEndpoint;

// 输出端点DMA通道

unsigned char ucOUTDMA;

//控制接口

unsigned char ucInterfaceControl;

//Audio接口

unsigned char ucInterfaceAudio;

}

tAudioInstance;

tAudioInstance,Audio设备类实例。用于保存全部Audio设备类的配置信息,包括描述符、callback函数、控制事件等。

#define USB_AUDIO_INSTANCE_SIZE sizeof(tAudioInstance);

#define COMPOSITE_DAUDIO_SIZE   (8 + 52 + 52)

USB_AUDIO_INSTANCE_SIZE,定义Audio设备类实例信息的大小。COMPOSITE_DAUDIO_SIZE定义设备描述符与所有接口描述符总长度。

typedef struct

{

// VID

unsigned short usVID;

// PID

unsigned short usPID;

//8字节供应商字符串

unsigned char pucVendor[8];

//16字节产品字符串

unsigned char pucProduct[16];

//4字节版本号

unsigned char pucVersion[4];

//最大耗电量

unsigned short usMaxPowermA;

//电源属性  USB_CONF_ATTR_SELF_PWR   USB_CONF_ATTR_BUS_PWR

//USB_CONF_ATTR_RWAKE.

unsigned char ucPwrAttributes;

// callback函数

tUSBCallback pfnCallback;

//字符串描述符集合

const unsigned char * const *ppStringDescriptors;

//字符串描述符个数

unsigned long ulNumStringDescriptors;

//最大音量

short sVolumeMax;

//最小音量

short sVolumeMin;

//音量调节步进

short sVolumeStep;

//Audio设备类实例

tAudioInstance *psPrivateData;

}

tUSBDAudioDevice;

tUSBDAudioDevice,Audio设备类。定义了VID、PID、电源属性、字符串描述符等,还包括了一个Audio设备类实例。其它设备描述符、配置信息通过API函数储入tAudioInstance定义的Audio设备实例中。

6.4 API函数

在Audio设备类API库中定义了4个函数,完成USB Audio设备初始化、配置及数据处理。下面为usbdaudio.h中定义的API函数:

void *USBDAudioInit(unsigned long ulIndex,

const tUSBDAudioDevice *psAudioDevice);

void *USBDAudioCompositeInit(unsigned long ulIndex,

const tUSBDAudioDevice *psAudioDevice);

int USBAudioBufferOut(void *pvInstance, void *pvBuffer, unsigned long ulSize,

tUSBAudioBufferCallback pfnCallback);

void USBDAudioTerm(void *pvInstance);

void *USBDAudioInit(unsigned long ulIndex,

const tUSBDAudioDevice *psAudioDevice);

作用:初始化Audio设备硬件、协议,把其它配置参数填入psAudioDevice实例中。

参数:ulIndex,USB模块代码,固定值:USB_BASE0。psAudioDevice,Audio设备类。

返回:指向配置后的tUSBDAudioDevice。

void *USBDAudioCompositeInit(unsigned long ulIndex,

const tUSBDAudioDevice *psAudioDevice);

作用:初始化Audio设备协议,本函数在USBDAudioInit中已经调用。

参数:ulIndex,USB模块代码,固定值:USB_BASE0。psAudioDevice,Audio设备类。

返回:指向配置后的tUSBDAudioDevice。

int USBAudioBufferOut(void *pvInstance, void *pvBuffer, unsigned long ulSize,

tUSBAudioBufferCallback pfnCallback);

作用:从输出端点获取数据,并放入pvBuffer中。

参数:pvInstance,指向tUSBDAudioDevice。pvBuffer,用于存放输出端点数据。ulSize,设置数据大小。pfnCallback,输出端点返回,只有一个事件,USBD_AUDIO_EVENT_DATAOUT。

返回:无。

void USBDAudioTerm(void *pvInstance);

作用:结束Audio设备。

参数:pvInstance,指向tUSBDAudioDevice。

返回:无。

在这些函数中USBDAudioInit和USBAudioBufferOut函数最重要并且使用最多,USBDAudioInit第一次使用Audio设备时,用于初始化Audio设备的配置与控制。USBAudioBufferOut从输出端点中获取数据,并放入数据缓存区内。

6.5 Audio设备开发

Audio设备开发只需要5步就能完成。如图2所示,Audio设备配置(主要是字符串描述符)、callback函数编写、USB处理器初始化、DMA控制、数据处理。

<ignore_js_op>

图2

第一步:Audio设备配置(主要是字符串描述符),按字符串描述符标准完成串描述符配置,进而完成Audio设备配置。

#include "inc/hw_ints.h"

#include "inc/hw_memmap.h"

#include "inc/hw_types.h"

#include "inc/hw_sysctl.h"

#include "inc/hw_udma.h"

#include "inc/hw_gpio.h"

#include "driverlib/gpio.h"

#include "driverlib/interrupt.h"

#include "driverlib/sysctl.h"

#include "driverlib/udma.h"

#include "usblib/usblib.h"

#include "usblib/usb-ids.h"

#include "usblib/device/usbdevice.h"

#include "usblib/device/usbdaudio.h"

//根据具体Audio芯片修改

#define VOLUME_MAX              ((short)0x0C00)  // +12db

#define VOLUME_MIN              ((short)0xDC80)  // -34.5db

#define VOLUME_STEP             ((short)0x0180)  // 1.5db

//Audio 设备

const tUSBDAudioDevice g_sAudioDevice;

//DMA 控制

tDMAControlTable sDMAControlTable[64] __attribute__ ((aligned(1024)));

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

// 缓存与标志.

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

#define AUDIO_PACKET_SIZE       ((48000*4)/1000)

#define AUDIO_BUFFER_SIZE       (AUDIO_PACKET_SIZE*20)

#define SBUFFER_FLAGS_PLAYING   0x00000001

#define SBUFFER_FLAGS_FILLING   0x00000002

struct

{

//主要buffer,USB audio class和sound driver使用.

volatile unsigned char pucBuffer[AUDIO_BUFFER_SIZE];

// play pointer.

volatile unsigned char *pucPlay;

// USB fill pointer.

volatile unsigned char *pucFill;

// 采样率 调整.

volatile int iAdjust;

// 播放状态

volatile unsigned long ulFlags;

} g_sBuffer;

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

// 当前音量

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

short g_sVolume;

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

// 通过USBDAudioInit() 函数,完善Audio设备配置信息

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

void *g_pvAudioDevice;

// 音量更新

#define FLAG_VOLUME_UPDATE      0x00000001

// 更新静音状态

#define FLAG_MUTE_UPDATE        0x00000002

// 静音状态

#define FLAG_MUTED              0x00000004

// 连接成功

#define FLAG_CONNECTED          0x00000008

volatile unsigned long g_ulFlags;

extern unsigned long

AudioMessageHandler(void *pvCBData, unsigned long ulEvent,

unsigned long ulMsgParam, void *pvMsgData);

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

// 设备语言描述符.

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

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

};

#define NUM_STRING_DESCRIPTORS (sizeof(g_pStringDescriptors) /                \

sizeof(unsigned char *))

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

// 定义Audio设备实例

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

static tAudioInstance g_sAudioInstance;

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

// 定义Audio设备类

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

const tUSBDAudioDevice g_sAudioDevice =

{

// VID

USB_VID_STELLARIS,

// PID

USB_PID_AUDIO,

// 8字节供应商字符串.

"TI      ",

//16字节产品字符串.

"Audio Device    ",

//4字节版本字符串.

"1.00",

500,

USB_CONF_ATTR_SELF_PWR,

AudioMessageHandler,

g_pStringDescriptors,

NUM_STRING_DESCRIPTORS,

VOLUME_MAX,

VOLUME_MIN,

VOLUME_STEP,

&g_sAudioInstance

};

第二步:完成Callback函数。Callback函数用于处理输出端点数据事务。主机发出的音频流数据,也可能是状态信息。Audio设备中包含了以下事务:USBD_AUDIO_EVENT_IDLE、USBD_AUDIO_EVENT_ACTIVE、USBD_AUDIO_EVENT_MUTE、USBD_AUDIO_EVENT_VOLUME、USB_EVENT_DISCONNECTED、USB_EVENT_CONNECTED。如下表:

名称

说明

USB_EVENT_CONNECTED

USB设备已经连接到主机

USB_EVENT_DISCONNECTED

USB设备已经与主机断开

USBD_AUDIO_EVENT_VOLUME

更新音量

USBD_AUDIO_EVENT_MUTE

静音

USBD_AUDIO_EVENT_ACTIVE

Audio处于活动状态

USBD_AUDIO_EVENT_IDLE

Audio处于空闲状态

表2. Audio事务

根据以上事务编写Callback函数:

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

//USB Audio设备类返回事件处理函数(callback).

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

unsigned long AudioMessageHandler(void *pvCBData, unsigned long ulEvent,

unsigned long ulMsgParam, void *pvMsgData)

{

switch(ulEvent)

{

//Audio 正处于空闲或者工作状态。

case USBD_AUDIO_EVENT_IDLE:

case USBD_AUDIO_EVENT_ACTIVE:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x10,0x10);

g_ulFlags |= FLAG_CONNECTED;

break;

}

// 静音控制.

case USBD_AUDIO_EVENT_MUTE:

{

// 检查是否静音.

if(ulMsgParam == 1)

{

//静音.

g_ulFlags |= FLAG_MUTE_UPDATE | FLAG_MUTED;

}

else

{

// 取消静音.

g_ulFlags &= ~(FLAG_MUTE_UPDATE | FLAG_MUTED);

g_ulFlags |= FLAG_MUTE_UPDATE;

}

break;

}

//音量控制.

case USBD_AUDIO_EVENT_VOLUME:

{

g_ulFlags |= FLAG_VOLUME_UPDATE;

//最大音量.

if(ulMsgParam == 0x8000)

{

//设置为最小

g_sVolume = 0;

}

else

{

//声音控制器,设置音量.

g_sVolume = (short)ulMsgParam - (short)VOLUME_MIN;

}

break;

}

// 断开连接.

case USB_EVENT_DISCONNECTED:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x10,0x00);

GPIOPinWrite(GPIO_PORTF_BASE,0x80,0x00);

g_ulFlags &= ~FLAG_CONNECTED;

break;

}

//连接

case USB_EVENT_CONNECTED:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x80,0x80);

g_ulFlags |= FLAG_CONNECTED;

break;

}

default:

{

break;

}

}

return(0);

}

第三步:系统初始化,配置内核电压、系统主频、使能端口、配置按键端口、LED控制等,本例中使用4个LED进行指示。原理图如图3所示

<ignore_js_op>

图3

系统初始化:

//设置内核电压、主频 50Mhz

SysCtlLDOSet(SYSCTL_LDO_2_75V);

SysCtlClockSet(SYSCTL_XTAL_8MHZ | SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL  | SYSCTL_OSC_MAIN );

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,0xf0);

GPIOPinTypeGPIOInput(GPIO_PORTF_BASE,0x0f);

HWREG(GPIO_PORTF_BASE+GPIO_O_PUR) |= 0x0f;

// 全局状态标志.

g_ulFlags = 0;

// 初始化Audio设备.

g_pvAudioDevice = USBDAudioInit(0, (tUSBDAudioDevice *)&g_sAudioDevice);

第四步:使能、配置DMA,Audio设备要传输大量数据,所以USB库函数内部已经使用了DMA,在使用前必须使能、配置DMA。

//配置使能DMA

SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

SysCtlDelay(10);

uDMAControlBaseSet(&sDMAControlTable[0]);

uDMAEnable();

第五步:数据处理。主要使用USBAudioBufferOut从输出端点中获取数据并处理,并且进行Audio设备控制。

while(1)

{

//等待连接结束.

while((g_ulFlags & FLAG_CONNECTED) == 0)

{

}

//初始化Buffer

g_sBuffer.pucFill = g_sBuffer.pucBuffer;

g_sBuffer.pucPlay = g_sBuffer.pucBuffer;

g_sBuffer.ulFlags = 0;

//从Audio设备类中获取数据

if(USBAudioBufferOut(g_pvAudioDevice,

(unsigned char *)g_sBuffer.pucFill,

AUDIO_PACKET_SIZE, USBBufferCallback) == 0)

{

//标记数据放入buffer中.

g_sBuffer.ulFlags |= SBUFFER_FLAGS_FILLING;

}

//设备连接到主机.

while(g_ulFlags & FLAG_CONNECTED)

{

// 检查音量是否有改变.

if(g_ulFlags & FLAG_VOLUME_UPDATE)

{

// 清除更新音量标志.

g_ulFlags &= ~FLAG_VOLUME_UPDATE;

// 修改音量,自行添加代码.在此以LED灯做指示。

//UpdateVolume();

GPIOPinWrite(GPIO_PORTF_BASE,0x40,~GPIOPinRead(GPIO_PORTF_BASE,0x40));

}

//是否静音

if(g_ulFlags & FLAG_MUTE_UPDATE)

{

//修改静音状态,自行添加函数.在此以LED灯做指示。

//UpdateMute();

if(g_ulFlags & FLAG_MUTED)

GPIOPinWrite(GPIO_PORTF_BASE,0x20,0x20);

else

GPIOPinWrite(GPIO_PORTF_BASE,0x20,0x00);

// 清除静音标志

g_ulFlags &= ~FLAG_MUTE_UPDATE;

}

}

}

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

//USBAudioBufferOut 的Callback入口参数

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

void USBBufferCallback(void *pvBuffer, unsigned long ulParam, unsigned long ulEvent)

{

//数据处理,自行加入代码。

// Your Codes .........

//再一次获取数据.

USBAudioBufferOut(g_pvAudioDevice, (unsigned char *)g_sBuffer.pucFill,

AUDIO_PACKET_SIZE, USBBufferCallback);

}

使用上面五步就完成Audio设备开发。Audio设备开发时要加入两个lib库函数: usblib.lib和DriverLib.lib,在启动代码中加入USB0DeviceIntHandler中断服务函数。以上Audio设备开发完成,在Win xp下运行效果如下图所示:

<ignore_js_op>

在枚举过程中可以看出,在电脑右下脚可以看到“Audio Example”字样,标示正在进行枚举。枚举成功后,在“设备管理器”的“声音、视屏和游戏控制器”中看到“USB Audio Device”设备,如下图。现在Audio设备可以正式使用。

<ignore_js_op>

Audio设备开发源码如下:

#include "inc/hw_ints.h"

#include "inc/hw_memmap.h"

#include "inc/hw_types.h"

#include "inc/hw_sysctl.h"

#include "inc/hw_udma.h"

#include "inc/hw_gpio.h"

#include "driverlib/gpio.h"

#include "driverlib/interrupt.h"

#include "driverlib/sysctl.h"

#include "driverlib/udma.h"

#include "usblib/usblib.h"

#include "usblib/usb-ids.h"

#include "usblib/device/usbdevice.h"

#include "usblib/device/usbdaudio.h"

//根据具体Audio芯片修改

#define VOLUME_MAX              ((short)0x0C00)  // +12db

#define VOLUME_MIN              ((short)0xDC80)  // -34.5db

#define VOLUME_STEP             ((short)0x0180)  // 1.5db

//Audio 设备

const tUSBDAudioDevice g_sAudioDevice;

//DMA 控制

tDMAControlTable sDMAControlTable[64] __attribute__ ((aligned(1024)));

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

// 缓存与标志.

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

#define AUDIO_PACKET_SIZE       ((48000*4)/1000)

#define AUDIO_BUFFER_SIZE       (AUDIO_PACKET_SIZE*20)

#define SBUFFER_FLAGS_PLAYING   0x00000001

#define SBUFFER_FLAGS_FILLING   0x00000002

struct

{

//主要buffer,USB audio class和sound driver使用.

volatile unsigned char pucBuffer[AUDIO_BUFFER_SIZE];

// play pointer.

volatile unsigned char *pucPlay;

// USB fill pointer.

volatile unsigned char *pucFill;

// 采样率 调整.

volatile int iAdjust;

// 播放状态

volatile unsigned long ulFlags;

} g_sBuffer;

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

// 当前音量

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

short g_sVolume;

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

// 通过USBDAudioInit() 函数,完善Audio设备配置信息

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

void *g_pvAudioDevice;

// 音量更新

#define FLAG_VOLUME_UPDATE      0x00000001

// 更新静音状态

#define FLAG_MUTE_UPDATE        0x00000002

// 静音状态

#define FLAG_MUTED              0x00000004

// 连接成功

#define FLAG_CONNECTED          0x00000008

volatile unsigned long g_ulFlags;

extern unsigned long

AudioMessageHandler(void *pvCBData, unsigned long ulEvent,

unsigned long ulMsgParam, void *pvMsgData);

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

// 设备语言描述符.

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

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

};

#define NUM_STRING_DESCRIPTORS (sizeof(g_pStringDescriptors) /                \

sizeof(unsigned char *))

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

// 定义Audio设备实例

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

static tAudioInstance g_sAudioInstance;

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

// 定义Audio设备类

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

const tUSBDAudioDevice g_sAudioDevice =

{

// VID

USB_VID_STELLARIS,

// PID

USB_PID_AUDIO,

// 8字节供应商字符串.

"TI      ",

//16字节产品字符串.

"Audio Device    ",

//4字节版本字符串.

"1.00",

500,

USB_CONF_ATTR_SELF_PWR,

AudioMessageHandler,

g_pStringDescriptors,

NUM_STRING_DESCRIPTORS,

VOLUME_MAX,

VOLUME_MIN,

VOLUME_STEP,

&g_sAudioInstance

};

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

//USB Audio设备类返回事件处理函数(callback).

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

unsigned long AudioMessageHandler(void *pvCBData, unsigned long ulEvent,

unsigned long ulMsgParam, void *pvMsgData)

{

switch(ulEvent)

{

//Audio 正处于空闲或者工作状态。

case USBD_AUDIO_EVENT_IDLE:

case USBD_AUDIO_EVENT_ACTIVE:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x10,0x10);

g_ulFlags |= FLAG_CONNECTED;

break;

}

// 静音控制.

case USBD_AUDIO_EVENT_MUTE:

{

// 检查是否静音.

if(ulMsgParam == 1)

{

//静音.

g_ulFlags |= FLAG_MUTE_UPDATE | FLAG_MUTED;

}

else

{

// 取消静音.

g_ulFlags &= ~(FLAG_MUTE_UPDATE | FLAG_MUTED);

g_ulFlags |= FLAG_MUTE_UPDATE;

}

break;

}

//音量控制.

case USBD_AUDIO_EVENT_VOLUME:

{

g_ulFlags |= FLAG_VOLUME_UPDATE;

//最大音量.

if(ulMsgParam == 0x8000)

{

//设置为最小

g_sVolume = 0;

}

else

{

//声音控制器,设置音量.

g_sVolume = (short)ulMsgParam - (short)VOLUME_MIN;

}

break;

}

// 断开连接.

case USB_EVENT_DISCONNECTED:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x10,0x00);

GPIOPinWrite(GPIO_PORTF_BASE,0x80,0x00);

g_ulFlags &= ~FLAG_CONNECTED;

break;

}

case USB_EVENT_CONNECTED:

{

GPIOPinWrite(GPIO_PORTF_BASE,0x80,0x80);

g_ulFlags |= FLAG_CONNECTED;

break;

}

default:

{

break;

}

}

return(0);

}

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

//USBAudioBufferOut 的Callback入口参数

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

void USBBufferCallback(void *pvBuffer, unsigned long ulParam, unsigned long ulEvent)

{

//数据处理,自行加入代码。

// Your Codes .........

//再一次获取数据.

USBAudioBufferOut(g_pvAudioDevice, (unsigned char *)g_sBuffer.pucFill,

AUDIO_PACKET_SIZE, USBBufferCallback);

}

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

// 应用主函数.

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

int  main(void)

{

//设置内核电压、主频 50Mhz

SysCtlLDOSet(SYSCTL_LDO_2_75V);

SysCtlClockSet(SYSCTL_XTAL_8MHZ | SYSCTL_SYSDIV_4 |

SYSCTL_USE_PLL  | SYSCTL_OSC_MAIN );

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,0xf0);

GPIOPinTypeGPIOInput(GPIO_PORTF_BASE,0x0f);

HWREG(GPIO_PORTF_BASE+GPIO_O_PUR) |= 0x0f;

//配置使能DMA

SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

SysCtlDelay(10);

uDMAControlBaseSet(&sDMAControlTable[0]);

uDMAEnable();

// 全局状态标志.

g_ulFlags = 0;

// 初始化Audio设备.

g_pvAudioDevice = USBDAudioInit(0, (tUSBDAudioDevice *)&g_sAudioDevice);

while(1)

{

//等待连接结束.

while((g_ulFlags & FLAG_CONNECTED) == 0)

{

}

//初始化Buffer

g_sBuffer.pucFill = g_sBuffer.pucBuffer;

g_sBuffer.pucPlay = g_sBuffer.pucBuffer;

g_sBuffer.ulFlags = 0;

//从Audio设备类中获取数据

if(USBAudioBufferOut(g_pvAudioDevice,

(unsigned char *)g_sBuffer.pucFill,

AUDIO_PACKET_SIZE, USBBufferCallback) == 0)

{

//标记数据放入buffer中.

g_sBuffer.ulFlags |= SBUFFER_FLAGS_FILLING;

}

//设备连接到主机.

while(g_ulFlags & FLAG_CONNECTED)

{

// 检查音量是否有改变.

if(g_ulFlags & FLAG_VOLUME_UPDATE)

{

// 清除更新音量标志.

g_ulFlags &= ~FLAG_VOLUME_UPDATE;

// 修改音量,自行添加代码.在此以LED灯做指示。

//UpdateVolume();

GPIOPinWrite(GPIO_PORTF_BASE,0x40,~GPIOPinRead(GPIO_PORTF_BASE,0x40));

}

//是否静音

if(g_ulFlags & FLAG_MUTE_UPDATE)

{

//修改静音状态,自行添加函数.在此以LED灯做指示。

//UpdateMute();

if(g_ulFlags & FLAG_MUTED)

GPIOPinWrite(GPIO_PORTF_BASE,0x20,0x20);

else

GPIOPinWrite(GPIO_PORTF_BASE,0x20,0x00);

// 清除静音标志

g_ulFlags &= ~FLAG_MUTE_UPDATE;

}

}

}

}

第六章Audio设备的更多相关文章

  1. 《Linux Device Drivers》第十六章 块设备驱动程序——note

    基本介绍 块设备驱动程序通过主传动固定大小数据的随机访问设备 Linux核心Visual块设备作为基本设备和不同的字符设备类型 Linux块设备驱动程序接口,使块设备最大限度地发挥其效用.一个问题 一 ...

  2. 精通Web Analytics 2.0 (8) 第六章:使用定性数据解答”为什么“的谜团

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第六章:使用定性数据解答"为什么"的谜团 当我走进一家超市,我不希望员工会认出我或重新为我布置商店. 然而, ...

  3. 第六章第一个linux个程序:统计单词个数

    第六章第一个linux个程序:统计单词个数 从本章就开始激动人心的时刻——实战,去慢慢揭开linux神秘的面纱.本章的实例是统计一片文章或者一段文字中的单词个数.  第 1 步:建立 Linu x 驱 ...

  4. (转)iOS Wow体验 - 第六章 - 交互模型与创新的产品概念(2)

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第六章译文精选的第二部分,其余章节将陆续放出.上一 ...

  5. (转)iOS Wow体验 - 第六章 - 交互模型与创新的产品概念(1)

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第六章译文精选,其余章节将陆续放出.上一篇:Wow ...

  6. [CSAPP笔记][第六章存储器层次结构]

    第六章 存储器层次结构 在简单模型中,存储器系统是一个线性的字节数组,CPU能够在一个常数访问每个存储器位置. 虽然是一个行之有效的模型,但没有反应现代系统实际工作方式. 实际上,存储器系统(memo ...

  7. CSS3秘笈复习:十三章&十四章&十五章&十六章&十七章

    第十三章 1.在使用浮动时,源代码的顺序非常重要.浮动元素的HTML必须处在要包围它的元素的HTML之前. 2.清楚浮动: (1).在外围div的底部添加一个清除元素:clear属性可以防止元素包围浮 ...

  8. 第六章、Linux 的文件权限与目录配置

    第六章.Linux 的文件权限与目录配置 1. 使用者与群组 2. Linux文件权限概念 2.1 Linux文件属性 2.2 如何改变文件属性与权限: chgrp, chown, chmod 2.3 ...

  9. 第六章:Reminders实验:第二部分[Learn Android Studio 汉化教程]

    Learn Android Studio 汉化教程 Reminders Lab: Part 2 This chapter covers capturing user input through the ...

随机推荐

  1. Kettle ETL 来进行mysql 数据同步——试验环境搭建(表中无索引,无约束,无外键连接的情况)

    今天试验了如何在Kettle的图形界面(Spoon)下面来整合来mysql 数据库中位于不同数据库中的数据表中的数据. 试验用的数据表是customers: 第三方的数据集下载地址是:http://w ...

  2. mac 查看系统时区

    sudo systemsetup -gettimezone https://developer.apple.com/library/mac/documentation/Darwin/Reference ...

  3. 百练_4120 硬币(DP)

    描述 宇航员Bob有一天来到火星上,他有收集硬币的习惯.于是他将火星上所有面值的硬币都收集起来了,一共有n种,每种只有一个:面值分别为a1,a2… an. Bob在机场看到了一个特别喜欢的礼物,想买来 ...

  4. strcpy函数导致release版程序崩溃

    最近在写一个读取模型文件的小程序.很随意的使用了strcpy函数进行char字符数组的拷贝,这个数组是需要传递给PostMessage作为WPARAM的参数.代码部分如下: char pStrCurr ...

  5. python isinstance 判断各种类型的小细节

    1. 基本语法 isinstance(object, classinfo) Return true if the object argument is an instance of the class ...

  6. 建造者模式(Builder Pattern)

    建造者模式:使用多个简单对象一步步构建成一个复杂的对象. 有时候,我们会创建一个“复杂”的对象,这个对象的由很多子对象构成,由于需求的变化,这个对象的各个部分经常面临剧烈的变化. 继续工厂模式的披萨店 ...

  7. java中的IO流

    Java中的IO流 在之前的时候我已经接触过C#中的IO流,也就是说集中数据固化的方式之一,那么我们今天来说一下java中的IO流. 首先,我们学习IO流就是要对文件或目录进行一系列的操作,那么怎样操 ...

  8. asp.net导出excel较为简约的代码

    ds为数据源 Response.Buffer = true; Response.AppendHeader("Content-Disposition", "attachme ...

  9. Android_Json实例

    概要: 最近由于自己的兴趣,想在Android开发一个自己的App,需要使用服务器,所以交换数据是逃不掉了的,但是学生党没有固定的服务器,因此使用的新浪的SAE,在学习的前期下可以尝试一下,挺不错的一 ...

  10. hdu 5094 Maze 状态压缩dp+广搜

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092176.html 题目链接:hdu 5094 Maze 状态压缩dp+广搜 使用广度优先 ...