USB Component  Version 6.7
MDK Middleware for USB Device and Host Communication
 All Data Structures Functions Variables Enumerations Enumerator Groups Pages
ADC: Audio Device Class

Implement application specific behavior of an Audio Device Class (ADC) USB Device. More...

Content

 User API
 User API reference of the Audio Device Class.
 
 Configuration
 Configuration of the USB Device ADC Class in µVision.
 

Description

Implement application specific behavior of an Audio Device Class (ADC) USB Device.

Use the following class specific functions to customize the functionality of an Audio Device Class (ADC) Device. Adapt these functions in the user code template file USBD_User_ADC_Audio_n.c.

Refer to:

The USB Component allows multiple instances of the ADC class. This feature is used to create USB Composite Devices. Each ADC class instance has a separate files and interface functions:

This documentation uses n as a placeholder for the instance number 0 - 3. Most applications only require one instance of an ADC class. For the first ADC class instance the instance number is 0:

Software Structure

The handling for the ADC class endpoint events is implemented in USBD_ADC_Thread which is started by USBD_Initialize. Each instance of an ADC class runs an instance of the USBD_ADCn_Thread. This thread handles the Isochronous IN/OUT Endpoints of the USB ADC Device.

msc_inline_mscgraph_2

Implementation

To create an USB Device with an ADC class:

User Code Templates
There is one user code template available that helps to add support for an ADC device:

  1. USBD_User_ADC_Audio.c is a code template for the application specific functionality of a USB ADC Device with Audio Interface.

User Code Template USBD_User_ADC_Audio.c

The following source code can be used to implement the application specific behavior of an USB ADC Device with Audio Interface.

/*------------------------------------------------------------------------------
* MDK Middleware - Component ::USB:Device
* Copyright (c) 2004-2016 ARM Germany GmbH. All rights reserved.
*------------------------------------------------------------------------------
* Name: USBD_User_ADC_Audio_n.c
* Purpose: USB Device Audio Device Class (ADC) User module
* Template for USB Audio Device Class (ADC) Sound Card
* Rev.: V6.3.0
*----------------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rl_usb.h"
#include ".\RTE\USB\USBD_Config_ADC_n.h"
#include "Board_Audio.h"
// Imported settings from USBD_Config_ADC_n.h file
#define PLAYBACK_AVAILABLE (USBD_ADCn_EP_ISO_OUT_EN != 0U)
#define PLAYBACK_CHANNELS (USBD_ADCn_OUT_CH_NUM)
#define PLAYBACK_FREQ (USBD_ADCn_OUT_TSAM_FREQ)
#define PLAYBACK_SAMPLE_SIZE (USBD_ADCn_OUT_BSUBFRAMESIZE)
#define PLAYBACK_USB_BUFFER_SIZE (USBD_ADCn_OUT_BUF_SIZE)
#define PLAYBACK_AUDIO_BUFFER_SIZE (USBD_ADCn_OUT_BUF_SIZE / 8U)
#define RECORD_AVAILABLE (USBD_ADCn_EP_ISO_IN_EN != 0U)
#define RECORD_CHANNELS (USBD_ADCn_IN_CH_NUM)
#define RECORD_FREQ (USBD_ADCn_IN_TSAM_FREQ)
#define RECORD_SAMPLE_SIZE (USBD_ADCn_IN_BSUBFRAMESIZE)
#define RECORD_USB_BUFFER_SIZE (USBD_ADCn_IN_BUF_SIZE)
#define RECORD_AUDIO_BUFFER_SIZE (USBD_ADCn_IN_BUF_SIZE / 8U)
// Supported configuration check
#if (PLAYBACK_AVAILABLE != 0U)
#if ((PLAYBACK_CHANNELS == 0U) || (PLAYBACK_CHANNELS > 2U))
#error Playback channel configuration mono or stero supported!
#endif
#if ((PLAYBACK_SAMPLE_SIZE != 2U) && (PLAYBACK_SAMPLE_SIZE != 4U))
#error Playback channel resolutions of 16 or 32 bits supported!
#endif
#endif
#if (RECORD_AVAILABLE != 0U)
#if ((RECORD_CHANNELS == 0U) || (RECORD_CHANNELS > 2U))
#error Recording channel configuration mono or stero supported!
#endif
#if ((RECORD_SAMPLE_SIZE != 2U) && (RECORD_SAMPLE_SIZE != 4U))
#error Recording channel resolutions of 16 or 32 bits supported!
#endif
#endif
#if (PLAYBACK_AVAILABLE != 0U)
static uint8_t play_idx = 0U;
static int32_t play_num = 0;
static uint8_t play_buf [2][PLAYBACK_SAMPLE_SIZE*(PLAYBACK_AUDIO_BUFFER_SIZE+PLAYBACK_CHANNELS)];
#endif
#if (RECORD_AVAILABLE != 0U)
static uint8_t rec_idx = 0U;
static int32_t rec_num = 0;
static uint8_t rec_buf [2][RECORD_SAMPLE_SIZE*(RECORD_AUDIO_BUFFER_SIZE+RECORD_CHANNELS)];
#endif
// Audio Events Handling Callback function
// \param[in] event notification mask
static void AudioCallback (uint32_t event) {
uint32_t samples_available;
// Restart new audio reception and new transmission first
if (event & AUDIO_EVENT_RECEIVE_COMPLETE) {
// Start new audio data reception (double buffering)
Audio_ReceiveData ((void *)(&rec_buf[rec_idx ^ 1U][0U]), RECORD_AUDIO_BUFFER_SIZE);
}
if ((event & AUDIO_EVENT_SEND_COMPLETE) && (play_num != 0U)) {
// Start new audio data transmission (double buffering)
Audio_SendData ((void *)(&play_buf[play_idx][0U]), play_num);
play_idx ^= 1U; // Change active buffer index
}
// Handling of recording
if (event & AUDIO_EVENT_RECEIVE_COMPLETE) {
// Compensate frequency difference between USB and Audio Interface
// by adding or removing 1 sample for mono or 2 samples for stereo
samples_available = USBD_ADC_WrittenSamplesPending (nU) + rec_num;
if (samples_available <= RECORD_AUDIO_BUFFER_SIZE) {
// Add (repeat last) 1 sample for mono or 2 samples for stereo
// to send to USB if USB is faster than Audio Interface
memcpy((void *)(&rec_buf[rec_idx][(RECORD_AUDIO_BUFFER_SIZE ) * RECORD_SAMPLE_SIZE]),
(void *)(&rec_buf[rec_idx][(RECORD_AUDIO_BUFFER_SIZE - RECORD_CHANNELS) * RECORD_SAMPLE_SIZE]),
RECORD_CHANNELS*RECORD_SAMPLE_SIZE);
rec_num = RECORD_AUDIO_BUFFER_SIZE + RECORD_CHANNELS;
}
if (samples_available >= (RECORD_USB_BUFFER_SIZE - RECORD_AUDIO_BUFFER_SIZE)) {
// Remove 1 sample for mono or 2 samples for stereo
// to send to USB if USB is slower than Audio Interface
rec_num = RECORD_AUDIO_BUFFER_SIZE - RECORD_CHANNELS;
}
// Send last received buffer of samples to USB
USBD_ADC_WriteSamples (nU, (void *)(&rec_buf[rec_idx][0U]), rec_num);
rec_idx ^= 1U; // Change active buffer index
}
// Handling of playback
if ((event & AUDIO_EVENT_SEND_COMPLETE) && (play_num != 0U)) {
// Read next buffer of samples from USB
play_num = USBD_ADC_ReadSamples (nU, (void *)(&play_buf[play_idx][0U]), PLAYBACK_AUDIO_BUFFER_SIZE);
// Compensate frequency difference between USB and Audio Interface
// by adding or removing 1 sample for mono or 2 samples for stereo
samples_available = USBD_ADC_ReceivedSamplesAvailable (nU) + play_num;
if (samples_available <= PLAYBACK_AUDIO_BUFFER_SIZE) {
// Add (repeat last) 1 sample for mono or 2 samples for stereo
// to send to Audio Interface if USB is slower than Audio Interface
memcpy((void *)(&play_buf[play_idx][(play_num ) * PLAYBACK_SAMPLE_SIZE]),
(void *)(&play_buf[play_idx][(play_num-PLAYBACK_CHANNELS) * PLAYBACK_SAMPLE_SIZE]),
PLAYBACK_CHANNELS*PLAYBACK_SAMPLE_SIZE);
play_num += PLAYBACK_CHANNELS;
}
if (samples_available >= (PLAYBACK_USB_BUFFER_SIZE - PLAYBACK_AUDIO_BUFFER_SIZE)) {
// Remove 1 sample for mono or 2 samples for stereo
// to send to Audio Interface if USB is faster than Audio Interface
play_num -= PLAYBACK_CHANNELS;
}
}
}
// Called during USBD_Initialize to initialize the USB ADC class instance.
void USBD_ADCn_Initialize (void) {
// Set stereo speakers volume range to 0 to 100 with step 1, initially positioned at 50 %
USBD_ADC_SpeakerSetVolumeRange (nU, 0U, 0U, 100U, 1U, 50U);
// Initialize Audio Interface driver
Audio_Initialize (&AudioCallback);
// Initialize Audio Interface for speakers according to USBD_Config_ADC_0.h file settings, not muted and volume at 50 %
Audio_SetDataFormat (AUDIO_STREAM_OUT, PLAYBACK_SAMPLE_SIZE | ((PLAYBACK_CHANNELS - 1U) << 7));
Audio_SetFrequency (AUDIO_STREAM_OUT, PLAYBACK_FREQ);
Audio_SetMute (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, false);
Audio_SetVolume (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, 50U);
// Set microphone volume range to 0 to 100 with step 1, initially positioned at 50 %
USBD_ADC_MicrophoneSetVolumeRange (nU, 0U, 0U, 100U, 1U, 50U);
// Initialize Audio Interface for microphone according to USBD_Config_ADC_0.h file settings, not muted and volume at 50 %
Audio_SetDataFormat (AUDIO_STREAM_IN, RECORD_SAMPLE_SIZE | ((RECORD_CHANNELS - 1U) << 7));
Audio_SetFrequency (AUDIO_STREAM_IN, RECORD_FREQ);
Audio_SetMute (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, false);
Audio_SetVolume (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, 50U);
}
// Called during USBD_Uninitialize to de-initialize the USB ADC class instance.
Audio_Uninitialize ();
}
// Callback function called when speaker activity (interface) setting changed event.
// \param[in] active activity status.
void USBD_ADCn_SpeakerStatusEvent (bool active) {
if (active == true) { // If playback was activated
Audio_Start (AUDIO_STREAM_OUT); // Start playback audio stream
} else { // If playback was de-activated
Audio_Stop (AUDIO_STREAM_OUT); // Stop playback audio stream
}
}
// Callback function called when speaker mute setting changed event.
// \param[in] ch channel index.
// - value 0: master channel
// - value 1: left speaker (in stereo mode)
// - value 2: right speaker (in stereo mode)
// \param[in] cur current setting.
void USBD_ADCn_SpeakerMuteEvent (uint8_t ch, bool cur) {
Audio_SetMute (AUDIO_STREAM_OUT, AUDIO_CHANNEL_MASTER, cur);
}
// Callback function called when speaker volume setting changed event.
// \param[in] ch channel index.
// - value 0: master channel
// - value 1: left speaker (in stereo mode)
// - value 2: right speaker (in stereo mode)
// \param[in] cur current setting.
void USBD_ADCn_SpeakerVolumeEvent (uint8_t ch, uint16_t cur) {
Audio_SetVolume (AUDIO_STREAM_OUT, ch, cur);
}
// Callback function called when microphone activity (interface) setting changed event.
// \param[in] active activity status.
void USBD_ADCn_MicrophoneStatusEvent (bool active) {
if (active == true) { // If recording was activated
rec_idx = 0U; // Current receiving buffer index is 0
rec_num = RECORD_AUDIO_BUFFER_SIZE; // Current receiving length
// Start initial audio data reception (record)
Audio_ReceiveData (&rec_buf[0U][0U], RECORD_AUDIO_BUFFER_SIZE);
Audio_Start (AUDIO_STREAM_IN); // Start recording audio stream
} else { // If recording was de-activated
Audio_Stop (AUDIO_STREAM_IN); // Stop recording audio stream
}
}
// Callback function called when microphone mute setting changed event.
// \param[in] ch channel index.
// - value 0: master channel
// - value 1: left microphone (in stereo mode)
// - value 2: right microphone (in stereo mode)
// \param[in] cur current setting.
void USBD_ADCn_MicrophoneMuteEvent (uint8_t ch, bool cur) {
Audio_SetMute (AUDIO_STREAM_IN, AUDIO_CHANNEL_MASTER, cur);
}
// Callback function called when microphone volume setting changed event.
// \param[in] ch channel index.
// - value 0: master channel
// - value 1: left microphone (in stereo mode)
// - value 2: right microphone (in stereo mode)
// \param[in] cur current setting.
void USBD_ADCn_MicrophoneVolumeEvent (uint8_t ch, uint16_t cur) {
Audio_SetVolume (AUDIO_STREAM_IN, ch, cur);
}
// Callback function called when data in buffer for speaker samples reaches from empty to half-full.
// Read initial data for playback
play_num = USBD_ADC_ReadSamples (nU, (void *)(&play_buf[0U][0U]), PLAYBACK_AUDIO_BUFFER_SIZE);
// Start initial audio data transmission (play)
Audio_SendData ((void *)(&play_buf[0U][0U]), play_num);
// Read next data for playback from Audio callback
play_idx = 1U;
play_num = USBD_ADC_ReadSamples (nU, (void *)(&play_buf[1U][0U]), PLAYBACK_AUDIO_BUFFER_SIZE);
}