USB Audio Device - Stm32f4Discovery
Posted: Mon Jul 15, 2013 1:21 pm
Hi,
I'm new in ChibiOS and usb applications, but I want to develop simple USB Desktop speaker using USB Audio Class 2.0 and I have problems with that.
I don't know how exactly initialize device, and how to handle requests from host. I found only one sample code in internet using freescale stack but I can't adapt it for me.
main.c
USBDescriptors.h
USBAudioCfg.c
USBAudioCfg. h has only externed USBDriver and USBConfig
AudioClass.h has defined descriptor macros and consts.
This is protocol anaysis from USBLyzer https://app.box.com/s/rphpni0pindoe1zdhodf
Sebastian
I'm new in ChibiOS and usb applications, but I want to develop simple USB Desktop speaker using USB Audio Class 2.0 and I have problems with that.
I don't know how exactly initialize device, and how to handle requests from host. I found only one sample code in internet using freescale stack but I can't adapt it for me.
main.c
Code: Select all
#include "ch.h"
#include "hal.h"
#include "UsbAudioCfg.h"
/*
* Application entry point.
*/
int main(void) {
halInit();
chSysInit();
usbDisconnectBus(usbp);
chThdSleepMilliseconds(1000);
usbStart(usbp, &usbcfg);
usbConnectBus(usbp);
while (TRUE) {
if(usbp->state == USB_ACTIVE)
{
}
chThdSleepMilliseconds(500);
}
}
USBDescriptors.h
Code: Select all
#include "ch.h"
#include "hal.h"
#include <AudioClass.h>
#include "UsbAudioCfg.h"
static const uint8_t audio_device_descriptor_data[18] = {
USB_DESC_DEVICE (0x0200, /* bcdUSB (2.0). */
0xEF, /* bDeviceClass (Misc). */
0x02, /* bDeviceSubClass. */
0x01, /* bDeviceProtocol. */
0x40, /* bMaxPacketSize. */
0x0483, /* idVendor (ST). */
0x5742, /* idProduct. */
0x0200, /* bcdDevice. */
1, /* iManufacturer. */
2, /* iProduct. */
3, /* iSerialNumber. */
1) /* bNumConfigurations. */
};
/*
* Device Descriptor wrapper.
*/
static const USBDescriptor audio_device_descriptor = {
sizeof audio_device_descriptor_data,
audio_device_descriptor_data
};
/*
* USB Device Qualifier Descriptor
*/
static const uint8_t audio_device_qualifier_descriptor_data[10] = {
USB_DESC_DEVICE_QUALIFIER (
0x0200, /* bcdUSB (2.0). */
0xEF, /* bDeviceClass (Misc). */
0x02, /* bDeviceSubClass. */
0x01, /* bDeviceProtocol. */
0x40, /* bMaxPacketSize. */
1)
};
static const USBDescriptor audio_device_qualifier_descriptor = {
sizeof audio_device_qualifier_descriptor_data,
audio_device_qualifier_descriptor_data
};
/*
* USB Configuration Descriptor
*/
#define AUDIO_CONF_SIZE 127
static const uint8_t audio_configuration_descriptor_data[AUDIO_CONF_SIZE] = {
/*Configuration Descriptor*/
USB_DESC_CONFIGURATION( /*Size: 9 */
AUDIO_CONF_SIZE, /* wTotalLength */
2, /* bNumInterfaces: 2 */
1, /* bConfigurationValue */
4, /* iConfiguration: 4 */
0xC0, /* bmAttributes: Self-powered */
0xFA), /* bMaxPower: 500mA */
/* Standard Interface Association Descriptor */
USB_DESC_INTERFACE_ASSOCIATION( /*Size: 8 */
0, /* bFirstInterface: 0 */
2, /* bInterfaceCount: 2 */
AUDIO, /* bFunctionClass: 0x01 */
FUNCTION_SUBCLASS_UNDEFINED, /* bFunctionSubClass: 0x00 */
AF_VERSION_02_00, /* bFunctionProtocol:0x200 */
5), /* iFunction:5 */
/* Standard AC Interface Descriptor */
USB_DESC_INTERFACE( /*Size: 9 */
0, /*bInterfaceNumber: 0 */
0, /*bAlternateSetting: 0 */
0, /*bNumEndpoints: 0 */
AUDIO, /*bInterfaceClass: 0x01 */
AUDIOCONTROL, /*bInterfaceSubClass: 0x01 */
IP_VERSION_02_00, /*bInterfaceProtocol: IP_VERSION_02_00 */
6), /*iInterface: 6 */
/* Class-Specific AC Interface Header Descriptor */
USB_DESC_INTERFACE_HEADER( /*Size: 9 */
0x0200, /*bcdADC: 2.0 */
DESKTOP_SPEAKER, /*bCategory: 0x01 */
46, /*wTotalLength: 46 */
0), /*bmControls: 0 */
/* Clock Source Descriptor */
USB_DESC_INTERFACE_CS( /*Size: 8 */
0x01, /*bClockID: 0x01 */
0x01, /*bmAttributes: Internal fixed Clock */
0x00, /*bmControls: None */
0, /*bAssocTerminal: None */
7), /*iClockSource: 7 */
/* Input Terminal Descriptor */
USB_DESC_INTERFACE_IT( /*Size: 17 */
0x02, /*bTerminalID: 0x02 */
0x0101, /*wTerminalType: USB Streaming */
0x00, /*bAssocTerminal: None */
0x01, /*bCSourceID: 0x01 */
0x02, /*bNrChannels: 2 */
3, /*bmChannelConfig: Left, Right */
0, /*iChannelNames: None(Default) */
0, /*bmControls: None */
8), /*iTerminal:8 */
/* Output Terminal Descriptor */
USB_DESC_INTERFACE_OT( /*Size: 12 */
0x03, /*bTerminalID: 0x03 */
0x0301, /*wTerminalType: Speaker */
0x02, /*bAssocTerminal: 0x02 */
0x02, /*bSourceID: 0x02 */
0x01, /*bCSourceID: 0x01 */
0x00, /*bmControls: None */
9), /*iTerminal: 9 */
/*Standard AS Interface Descriptor Alternate Setting 0*/
USB_DESC_INTERFACE( /*Size: 9 */
0x01, /*bInterfaceNumber: 0x01 */
0x00, /*bAlternateSetting: 0x00 */
0x00, /*bNumEndpoints:0x00 */
AUDIO, /*bInterfaceClass: AUDIO */
AUDIOSTREAMING, /*bInterfaceSubClass: AUDIO_STREAMING */
IP_VERSION_02_00, /*bInterfaceProtocol: IP_VERSION_02_00 */
0), /*iInterface: 0 */
/* Standard AS Interface Descriptor Alternate Setting 1 */
USB_DESC_INTERFACE( /*Size: 9 */
0x01, /*bInterfaceNumber: 0x01 */
0x01, /*bAlternateSetting: 0x01 */
0x01, /*bNumEndpoints:0x01 Isohronous Data */
AUDIO, /*bInterfaceClass: AUDIO */
AUDIOSTREAMING, /*bInterfaceSubClass: AUDIO_STREAMING */
IP_VERSION_02_00, /*bInterfaceProtocol: IP_VERSION_02_00 */
0), /*iInterface: 0 */
/* Class-Specific AS Interface Descriptor */
USB_DESC_CS_AS_INTERFACE( /*Size: 16 */
0x02, /*bTerminalLink: 0x02 */
0x00, /*bmControls: None */
0x01, /*bFormatType: Format Type 1 */
1, /*bmFormats: PCM */
2, /*bNrChannels: 2 */
3, /*bmChannelConfig: Left, Right */
0), /*iChannelNames: None(Default) */
/* Class-Specific AS Format Type Descriptor */
USB_DESC_BYTE (6), /*Size: 6 */
USB_DESC_BYTE (CS_INTERFACE), /*bDescriptorType: Class-Specific Interface */
USB_DESC_BYTE (FORMAT_TYPE), /*bDescriptorSubtype: Format Type Descriptor */
USB_DESC_BYTE (1), /*bFormatType: PCM */
USB_DESC_BYTE (1), /*bSubslotSize: 1 */
USB_DESC_BYTE (0x18), /*bBitResolution: 24bit */
/* AS Endpoint Descriptor */
USB_DESC_ENDPOINT( /*Size: 7 */
0x01, /*bEndpointAddress: 1 */
0x0D, /*bmAttributes: Iso+Synch+Data */
0x0040, /*wMaxPacketSize: 64 bytes */
0x01), /*bInterval: 1ms */
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor */
USB_DESC_AS_ISO_ENDPOINT( /*Size: 8 */
0x00, /*bmAttributes: None */
0x00, /*bmControls: None */
0x00, /*bLockDelayUnits: None */
0x0000) /*wLockDelay: 0 */
};
/*
* Configuration Descriptor wrapper.
*/
static const USBDescriptor audio_configuration_descriptor = {
sizeof audio_configuration_descriptor_data,
audio_configuration_descriptor_data
};
/*
* Endpoint Initialization
*/
/*
* U.S. English language identifier.
*/
static const uint8_t audio_string0[] = {
USB_DESC_BYTE(4), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */
};
/*
* Vendor string.
*/
static const uint8_t audio_string1[] = {
USB_DESC_BYTE(38), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'S', 0,
'T', 0,
'M', 0,
'i', 0,
'c', 0,
'r', 0,
'o', 0,
'e', 0,
'l', 0,
'e', 0,
'c', 0,
't', 0,
'r', 0,
'o', 0,
'n', 0,
'i', 0,
'c', 0,
's', 0
};
/*
* Device Description string.
*/
static const uint8_t audio_string2[] = {
USB_DESC_BYTE(56), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'C', 0,
'h', 0,
'i', 0,
'b', 0,
'i', 0,
'O', 0,
'S', 0,
'/', 0,
'R', 0,
'T', 0,
' ', 0,
'V', 0,
'i', 0,
'r', 0,
't', 0,
'u', 0,
'a', 0,
'l', 0,
' ', 0,
'C', 0,
'O', 0,
'M', 0,
' ', 0,
'P', 0,
'o', 0,
'r', 0,
't', 0
};
/*
* Serial Number string.
*/
static const uint8_t audio_string3[] = {
USB_DESC_BYTE(8), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'0' + CH_KERNEL_MAJOR, 0,
'0' + CH_KERNEL_MINOR, 0,
'0' + CH_KERNEL_PATCH, 0
};
static const uint8_t audio_string4[] = {
USB_DESC_BYTE(34), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'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,
' ', 0,
'1', 0,
};
static const uint8_t audio_string5[] = {
USB_DESC_BYTE(22), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'F', 0,
'u', 0,
'n', 0,
'c', 0,
't', 0,
'i', 0,
'o', 0,
'n', 0,
' ', 0,
'1', 0,
};
static const uint8_t audio_string6[] = {
USB_DESC_BYTE(24), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'I', 0,
'n', 0,
't', 0,
'e', 0,
'r', 0,
'f', 0,
'a', 0,
'c', 0,
'e', 0,
' ', 0,
'0', 0,
};
static const uint8_t audio_string7[] = {
USB_DESC_BYTE(56), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'C', 0,
'l', 0,
'o', 0,
'c', 0,
'k', 0,
' ', 0,
'S', 0,
'o', 0,
'u', 0,
'r', 0,
'c', 0,
'e', 0,
};
static const uint8_t audio_string8[] = {
USB_DESC_BYTE(30), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'I', 0,
'n', 0,
'p', 0,
'u', 0,
't', 0,
' ', 0,
'T', 0,
'e', 0,
'r', 0,
'm', 0,
'i', 0,
'n', 0,
'a', 0,
'l', 0,
};
static const uint8_t audio_string9[] = {
USB_DESC_BYTE(32), /* bLength. */
USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
'O', 0,
'u', 0,
't', 0,
'p', 0,
'u', 0,
't', 0,
' ', 0,
'T', 0,
'e', 0,
'r', 0,
'm', 0,
'i', 0,
'n', 0,
'a', 0,
'l', 0,
};
/*
* Strings wrappers array.
*/
static const USBDescriptor audio_strings[] = {
{sizeof audio_string0, audio_string0},
{sizeof audio_string1, audio_string1},
{sizeof audio_string2, audio_string2},
{sizeof audio_string3, audio_string3},
{sizeof audio_string4, audio_string4},
{sizeof audio_string5, audio_string5},
{sizeof audio_string6, audio_string6},
{sizeof audio_string7, audio_string7},
{sizeof audio_string8, audio_string8},
{sizeof audio_string9, audio_string9},
};
static const USBDescriptor *GetDescriptor(USBDriver *usbp,
uint8_t dtype,
uint8_t dindex,
uint16_t lang)
{
(void)usbp;
(void)lang;
switch(dtype) {
case USB_DESCRIPTOR_DEVICE:
return &audio_device_descriptor;
case USB_DESCRIPTOR_DEVICE_QUALIFIER:
return &audio_device_qualifier_descriptor;
case USB_DESCRIPTOR_OTHER_SPEED_CFG:
return 0;
case USB_DESCRIPTOR_CONFIGURATION:
return &audio_configuration_descriptor;
case USB_DESCRIPTOR_STRING:
if(dindex < 10)
return &audio_strings[dindex];
}
return NULL;
}
USBAudioCfg.c
Code: Select all
/*
* UsbAudioCfg
*
* Created on: 23-06-2013
* Author: Sebastian
*/
#include "ch.h"
#include "hal.h"
#include "USBDescriptors.h"
uint8_t recvBuffer;
USBDriver *usbp = &USBD1;
bool_t epConfigured = FALSE;
static void isocTransmitted(USBDriver *usbp, usbep_t ep)
{
chSysLockFromIsr();
usbPrepareReceive(usbp, ep, &recvBuffer, 64);
usbStartReceiveI(usbp, ep);
palTogglePad(GPIOD, GPIOD_LED4);
chSysUnlockFromIsr();
}
static USBOutEndpointState ep1outstate;
static USBEndpointConfig ep1config = {
USB_EP_MODE_TYPE_ISOC,
NULL,
NULL,
isocTransmitted,
0x0000,
0x0040,
NULL,
&ep1outstate,
1,
NULL
};
static void UsbEvent(USBDriver *usbp, usbevent_t event)
{
(void)usbp;
switch(event)
{
case USB_EVENT_RESET:
return;
case USB_EVENT_ADDRESS:
return;
case USB_EVENT_CONFIGURED:
chSysLockFromIsr();
usbInitEndpointI(usbp,1, &ep1config);
chSysUnlockFromIsr();
epConfigured = TRUE;
return;
case USB_EVENT_SUSPEND:
return;
case USB_EVENT_WAKEUP:
return;
case USB_EVENT_STALLED:
return;
}
}
static bool_t requestCB(USBDriver *usbp)
{
switch (((usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK |
USB_RTYPE_TYPE_MASK)) |
(usbp->setup[1] << 8))) {
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_DESCRIPTOR << 8):
break;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_CLEAR_FEATURE << 8):
break;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_SET_FEATURE << 8):
break;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_INTERFACE << 8):
break;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_SET_INTERFACE << 8):
//palSetPad(GPIOD, GPIOD_LED5);
//isocTransmitted(usbp, 1);
return TRUE;
break;
}
return FALSE;
}
static void sofCB(USBDriver *usbp)
{
if(epConfigured)
{
isocTransmitted(usbp, 1);
palTogglePad(GPIOD,GPIOD_LED3);
}
}
const USBConfig usbcfg = {
UsbEvent,
GetDescriptor,
requestCB,
sofCB
};
USBAudioCfg. h has only externed USBDriver and USBConfig
AudioClass.h has defined descriptor macros and consts.
This is protocol anaysis from USBLyzer https://app.box.com/s/rphpni0pindoe1zdhodf
Sebastian