MickMad
Well-known member
Hello there, I'm having a difficult time trying to setup an USB Audio core type for the Teensy. I'm currently working on Teensy 3.0, and I want it to enumerate as an USB Audio Device. I started from the MIDI core type, deleted all the MIDI stuff, and started adding the Audio Class Device descriptors.
First thing, was to add the core type in the Arduino IDE contextual menu: I edited hardware/boards.txt and added the following:
then I edited hardware/cores/teensy/core_id.h, hardware/cores/teensy/usb.c , hardware/cores/teensy/usb_api.cpp, hardware/cores/teensy/usb_api.h, hardware/cores/teensy/usb_private.h, hardware/cores/teensy3/core_id.h and added:
where xxx is the name of the file to include(core_id.h, usb.c, and so on)
next, I edited /hardware/cores/teensy3/usb_inst.cpp and added:
I left usb_desc.c as it is, but I edited usb_desc.h and added:
I set NUM_INTERFACES to 3 because the Audio Class is defined to have one AudioControl interface, which is the main control interface put on endpoint 0, and an AudioStreaming interface, which handles the actual data transfer and it is connected to endpoint 3, which is an isochronous endpoint.
Then, I finally started to actually modify the usb core. In usb_api.cpp and usb_api.h I just block-commented the whole usb_midi_class class definitions; in usb_private.h the only modified part is the defines:
The config descriptor in usb.c is the big part of everything: there's the Interface Association Descriptor, which tells that the device is a composite audio device, then the Audio Control interface, which contains the definitions for a Clock Source Unit, an Input Terminal (the virtual microphone), and an Output Terminal, which is the actual USB stream from Teensy to PC; then there's the AudioStreaming interface definition, which contains the audio Format defintion, and the Isochronous endpoint description.
Unfortunately, the only thing that I can get to work is the "Teensy Audio" to appear in the device informations; I tried the whole bcdDevice thing, but it doesn't seem to update; if I look at the device informations, it states, under Hardware ID: "USB\VID_16C0&PID_0485&REV_0100"; I suppose that the REV number should be the actual bcdDevice field, but it always reads as 0100. There's also one thing that bugs me so hard, which is the supported sampling frequencies definition in the Type I Format Descriptor: according to USB DCD for Audio Data Formats 2.0 there's no supported sampling frequency field at all, while the USB DCD for Audio Data Formats 1.0 does define it, and you can see I added those lines in the descriptor, as documented in the Freescale Application Note AN4665. I really don't know where to look for the error. In the meanwhile, I'll try to remove everything except for the AC interface, and see if that enumerates the Teensy as a no-function audio device (USB 2.0 allows that). If anybody finds anything that can help , please let me know!
EDIT: in regard to the bcdDevice not updating, I've found the problem: I had to edit usb_desc.c and usb_desc.h a bit; I've added the Audio Configuration Descriptor as defined in my usb.c into usb_desc.c, just like for the other usb types I've added an "#ifdef AUDIO_INTERFACE [.....] #endif" block containing all the descriptor stuff, then I added a #define BCD_DEVICE into usb_desc.h and modified the definition of the device descriptor like this:
Now, I can easily update the bcdDevice field.
I've tried to remove everything from the config descriptor, leaving only the Interface Association Descriptor, the Standard AC Interface Descriptor and the class-specific AC Interface Descriptor, and it does something; the PC finds a peripheral called "Teensy Audio", which is composed of a not working audio interface, and some HID stuff related to the Serial emulation. Well, at least, the Serial emulation is working AND the PC finds an audio peripheral. Hope I get the Teensy to actually spit some audio on an USB endpoint soon!
First thing, was to add the core type in the Arduino IDE contextual menu: I edited hardware/boards.txt and added the following:
Code:
teensy3.menu.usb.audio.name=Audio
teensy3.menu.usb.audio.build.define0=-DUSB_AUDIO
teensy3.menu.usb.audio.fake_serial=teensy_gateway
then I edited hardware/cores/teensy/core_id.h, hardware/cores/teensy/usb.c , hardware/cores/teensy/usb_api.cpp, hardware/cores/teensy/usb_api.h, hardware/cores/teensy/usb_private.h, hardware/cores/teensy3/core_id.h and added:
Code:
#elif defined(USB_AUDIO)
#include "../usb_audio/xxx"
next, I edited /hardware/cores/teensy3/usb_inst.cpp and added:
Code:
#ifdef USB_AUDIO
usb_seremu_class Serial;
#endif
I left usb_desc.c as it is, but I edited usb_desc.h and added:
Code:
#elif defined(USB_AUDIO)
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0485
#define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
#define MANUFACTURER_NAME_LEN 11
#define PRODUCT_NAME {'T','e','e','n','s','y',' ','A','u','d','i','o'}
#define PRODUCT_NAME_LEN 12
#define EP0_SIZE 64
#define NUM_ENDPOINTS 3
#define NUM_USB_BUFFERS 16
#define NUM_INTERFACE 3
#define SEREMU_INTERFACE 2 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
#define SEREMU_RX_SIZE 32
#define SEREMU_RX_INTERVAL 2
#define AUDIO_INTERFACE 0 // Audio
#define AUDIO_TX_ENDPOINT 3
#define AUDIO_TX_SIZE 64
#define SEREMU_DESC_OFFSET (9 + 118 + 9)
#define CONFIG_DESC_SIZE (9 + 118 + 9+9+7+7)
#define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY
I set NUM_INTERFACES to 3 because the Audio Class is defined to have one AudioControl interface, which is the main control interface put on endpoint 0, and an AudioStreaming interface, which handles the actual data transfer and it is connected to endpoint 3, which is an isochronous endpoint.
Then, I finally started to actually modify the usb core. In usb_api.cpp and usb_api.h I just block-commented the whole usb_midi_class class definitions; in usb_private.h the only modified part is the defines:
Code:
#define STR_PRODUCT L"Teensy Audio"
#define ENDPOINT0_SIZE 64
#define DEBUG_INTERFACE 2
#define DEBUG_TX_ENDPOINT 1
#define DEBUG_TX_SIZE 64
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER
#define DEBUG_TX_INTERVAL 1
#define DEBUG_RX_ENDPOINT 2
#define DEBUG_RX_SIZE 32
#define DEBUG_RX_BUFFER EP_DOUBLE_BUFFER
#define DEBUG_RX_INTERVAL 2
#define AUDIO_INTERFACE 0
#define AUDIO_TX_ENDPOINT 3
#define AUDIO_TX_SIZE 64
#define AUDIO_TX_BUFFER EP_DOUBLE_BUFFER
#define NUM_ENDPOINTS 3
#define NUM_INTERFACE 3
#endif
The config descriptor in usb.c is the big part of everything: there's the Interface Association Descriptor, which tells that the device is a composite audio device, then the Audio Control interface, which contains the definitions for a Clock Source Unit, an Input Terminal (the virtual microphone), and an Output Terminal, which is the actual USB stream from Teensy to PC; then there's the AudioStreaming interface definition, which contains the audio Format defintion, and the Isochronous endpoint description.
Code:
#define CONFIG1_DESC_SIZE ( 9 + 122 + 32 )
#define DEBUG_HID_DESC_OFFSET ( 9 + 122 + 9 )
static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), MSB(CONFIG1_DESC_SIZE), // wTotalLength
3, // bNumInterfaces (one AC interface, one AS interface, one HID interface)
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower
// Standard Interface Assoctiation Descriptor (IAD) (Table 4.3, p.46, USB DCD for Audio Devices 2.0)
8, // bLength
0x0B, // bDescriptorType
0, // bFirstInterface
2, // bInterfaceCount
1, // FunctionClass = AUDIO
0, // bFuncionSubClass
0x20, // bFunctionProtocol = AF_VERSION_02_00
0, // iFunction
// Standard AudioControl (AC) Interface Descriptor (Table 4.4, p.47, USB DCD for Audio Devices 2.0)
9, // bLength
4, // bDescriptorType = INTERFACE
0, // bInterfaceNumber
0, // bAlternateSetting
0, // bNumEndpoints
1, // bInterfaceClass = AUDIO
1, // bInterfaceSubclass = AUDIO_CONTROL
0x20, // bInterfaceProtocol = IP_VERSION_02_00
0, // iInterface
// Class-specific AC Interface Descriptor (Table 4.5, p.48, USB DCD for Audio Devices 2.0)
9, // bLength
0x24, // bDescriptorType = CS_INTERFACE
1, // bDescriptorSubtype = HEADER
0x00, 0x02, // bcdADC
3, // bCategory = MICROPHONE
0x2E, 0x00, // wTotalLength (9 + 8 + 17 + 12)
0, // bmControls
// Clock Source Descriptor (Table 4.6, p. 49, USB Device Class Definition for Audio Devices 2.0)
8, //bLength
0x24, //bDescriptorType = CS_INTERFACE
0x0A, //bDescriptorSubType = CLOCK_SOURCE
0x10, //bClockID = CLOCK_SOURCE_ID
1, //bmAttributes = internal fixed clock
7, //bmControls
0, //bAssocTerminal
0, //iClockSource
// Input Terminal Descriptor (Table 4.9, p.53, USB Device Class Definition for Audio Devices 2.0)
17, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x02, // bDescriptorSubtype = INPUT_TERMINAL
0x20, // bTerminalID
0x01, 0x02, // wTerminalType = MICROPHONE
0x00, // bAssocTerminal
0x10, // bCSourceID = CLOCK_SOURCE_ID
1, // bNrChannels
0, // bmChannelConfig = MONO
0, // iChannelNames
0x00, 0x00, // bmControls
0x00, // iTerminal
// Output Terminal Descriptor (Table 4.10, p. 54, USB Device Class Definition for Audio Devices 2.0)
12, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x03, // bDescriptorSubtype = INPUT_TERMINAL
0x30, // bTerminalID
0x01, 0x01, // wTerminalType = USB STREAMING
0x00, // bAssocTerminal
0x20, // bSourceID = INPUT_TERMINAL_ID
0x10, // bCSourceID = CLOCK_SOURCE_ID
0x00, 0x00, // bmControls
0x00, // iTerminal
// Standard AudioStreaming (AS) Interface Descriptor (Table 4.26, p. 75, USB Device Class Definition for Audio Devices 2.0)
// Alternate 0
// default setting with zero bandwidth
9, // bLenght
4 // bDescriptorType = INTERFACE
1, // bInterfaceNumber
0, // bAlternateSetting
0, // bNumEndpoints
1, // bInterfaceClass = AUDIO
2, // bInterfaceSubclass = AUDIO_STREAMING
0x20, // bInterfaceProtocol = IP 2.0
0, // iInterface
// Alternate 1
// alternate interface for data streaming
9, // bLenght
4 // bDescriptorType = INTERFACE
1, // bInterfaceNumber
1, // bAlternateSetting
1, // bNumEndpoints
1, // bInterfaceClass = AUDIO
2, // bInterfaceSubclass = AUDIO_STREAMING
0x20, // bInterfaceProtocol = IP 2.0
0, // iInterface
// Class-Specific AS Interface Descriptor (Table 4.27, p. 76, USB Device Class Definition for Audio Devices 2.0)
16, // bLength
0x24, // bDescriptorType = CS_INTERFACE
1, // bDescriptorSubtype = AS_GENERAL
0x30, // bTerminalLink = OUTPUT_TERMINAL_ID
0, // bmControls
1, // bFormatType
0x01, 0x00, 0x00, 0x00, // bmFormats
1, // bNrChannels
0,0,0,0, // bmChannelConfig
0, // iChannelNames
// Type I Format Descriptor (Table 2.2, p. 15, USB Device Class Definition for Audio Data Formats 2.0)
6, // bLength
0x24, // bDescriptorType = CS_INTERFACE
2, // bDescriptorSubtype = FORMAT_TYPE
1, // bFormatType = FORMAT_TYPE_I
2, // bSubslotSize = 16 bits
16, // bBitResolution
//not documented in USB DCD for Audio Data Formats 2.0
0x01, // bSamFreqType
0x40,0x1F,0x00, // tSamFreq
// Standard AS Isochronous Audio Data Endpoint Descriptor(4.33, p. 85, USB Device Class Definition for Audio Devices 2.0)
7, // bLength
0x05, // bDescriptorType = ENDPOINT_DESCRIPTOR
AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress = 3 - IN
0x05, // bmAttributes = iso+asynch+data
AUDIO_TX_SIZE, 0x00, // wMaxPacketSize = 8(8 samples * 1 bytes * 1 channel)
AUDIO_TX_INTERVAL, // bInterval = 2^x ms
// Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2)
0x08, // bLength
0x25, // bDescriptorType = CS_ENDPOINT
0x01, // bDescriptorSubtype = EP_GENERAL
0x00, // bmAttributes = MaxPacketsOnly = FALSE
0x00, // bmControls
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
DEBUG_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(debug_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_TX_SIZE, 0, // wMaxPacketSize
DEBUG_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_RX_SIZE, 0, // wMaxPacketSize
DEBUG_RX_INTERVAL, // bInterval
};
Unfortunately, the only thing that I can get to work is the "Teensy Audio" to appear in the device informations; I tried the whole bcdDevice thing, but it doesn't seem to update; if I look at the device informations, it states, under Hardware ID: "USB\VID_16C0&PID_0485&REV_0100"; I suppose that the REV number should be the actual bcdDevice field, but it always reads as 0100. There's also one thing that bugs me so hard, which is the supported sampling frequencies definition in the Type I Format Descriptor: according to USB DCD for Audio Data Formats 2.0 there's no supported sampling frequency field at all, while the USB DCD for Audio Data Formats 1.0 does define it, and you can see I added those lines in the descriptor, as documented in the Freescale Application Note AN4665. I really don't know where to look for the error. In the meanwhile, I'll try to remove everything except for the AC interface, and see if that enumerates the Teensy as a no-function audio device (USB 2.0 allows that). If anybody finds anything that can help , please let me know!
EDIT: in regard to the bcdDevice not updating, I've found the problem: I had to edit usb_desc.c and usb_desc.h a bit; I've added the Audio Configuration Descriptor as defined in my usb.c into usb_desc.c, just like for the other usb types I've added an "#ifdef AUDIO_INTERFACE [.....] #endif" block containing all the descriptor stuff, then I added a #define BCD_DEVICE into usb_desc.h and modified the definition of the device descriptor like this:
Code:
static uint8_t device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
#ifdef DEVICE_CLASS
DEVICE_CLASS, // bDeviceClass
#else
0,
#endif
#ifdef DEVICE_SUBCLASS
DEVICE_SUBCLASS, // bDeviceSubClass
#else
0,
#endif
#ifdef DEVICE_PROTOCOL
DEVICE_PROTOCOL, // bDeviceProtocol
#else
0,
#endif
EP0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
#ifdef BCD_DEVICE
LSB(BCD_DEVICE), MSB(BCD_DEVICE), // bcdDevice
#else
0x00, 0x01, // bcdDevice
#endif
1, // iManufacturer
2, // iProduct
3, // iSerialNumber
1 // bNumConfigurations
};
Now, I can easily update the bcdDevice field.
I've tried to remove everything from the config descriptor, leaving only the Interface Association Descriptor, the Standard AC Interface Descriptor and the class-specific AC Interface Descriptor, and it does something; the PC finds a peripheral called "Teensy Audio", which is composed of a not working audio interface, and some HID stuff related to the Serial emulation. Well, at least, the Serial emulation is working AND the PC finds an audio peripheral. Hope I get the Teensy to actually spit some audio on an USB endpoint soon!
Last edited: