Skip to main content
Associate II
Oct 29, 2026 12:34 PM UTC
Question

AL94 USB COMOPSITE MICROPHONE

Greetings all,

This is my first go around with a USB microphone with the AL94 Composite USB library. Currently I have the device enumerating as a USB audio device, which I can select and use via an application such as Sound Recorder on Windows. Additionally, the SOF interrupt is firing, the USB link is active, the descriptors are accepted, and the endpoint is armed. However, no data is ever transmitted, despite data being fed into the USBD_AUDIO_MIC_Data_Transfer function. I am not entirely sure what else to do here, any guidance would be appreciated.

Thanks!

Edit #1 10:29:2026 7:31 AM - Added link to repository being used:
https://github.com/alambe94/I-CUBE-USBD-Composite

 


/* AUDIO Class Config */
#define AUDIO_MIC_CHANNELS 0x01
#define AUDIO_MIC_SMPL_FREQ 16000U
#define USBD_AUDIO_MIC_CONFIG_DESC_SIZE (116 + AUDIO_MIC_CHANNELS)



#define AUDIO_MIC_VOL_MIN 0xDBE0
#define AUDIO_MIC_VOL_RES 0x0023
#define AUDIO_MIC_VOL_MAX 0x0000
#if 0
//Original
#define AUDIO_MIC_PACKET (uint32_t)((((AUDIO_MIC_SMPL_FREQ/1000)+2)*8)*2)
#else
//Update to fit the proper number of bytes.
#define AUDIO_MIC_PACKET ((AUDIO_MIC_SMPL_FREQ/1000) * AUDIO_MIC_CHANNELS * 2)
#endif
#define AUDIO_MIC_TERMINAL_ID 1
#define AUDIO_MIC_FU_ID 2
#define AUDIO_MIC_OUT_TERMINAL_ID 3

/* Buffering state definitions */
typedef enum
{
STATE_USB_WAITING_FOR_INIT = 0,
STATE_USB_IDLE = 1,
STATE_USB_REQUESTS_STARTED = 2,
STATE_USB_BUFFER_WRITE_STARTED = 3,
} AUDIO_MIC_StatesTypeDef;

/* Number of sub-packets in the audio transfer buffer.*/
#define AUDIO_MIC_PACKET_NUM 20

#define TIMEOUT_VALUE 200

/* USB AUDIO device Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_AUDIO_MIC_CfgDesc[USBD_AUDIO_MIC_CONFIG_DESC_SIZE] __ALIGN_END =
{
/* Configuration 1 */
0x09, /* bLength */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType */
LOBYTE(USBD_AUDIO_MIC_CONFIG_DESC_SIZE), /* wTotalLength: Total size of the Config descriptor */
HIBYTE(USBD_AUDIO_MIC_CONFIG_DESC_SIZE),
0x02, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
#if (USBD_SELF_POWERED == 1U)
0xC0, /* bmAttributes: Bus Powered according to user configuration */
#else
0x80, /* bmAttributes: Bus Powered according to user configuration */
#endif
USBD_MAX_POWER, /* bMaxPower = 100 mA */
/* 09 byte*/

/******** IAD to associate the two MIC interfaces */
0x08, /* bLength */
0x0B, /* bDescriptorType */
_AUDIO_MIC_AC_ITF_NBR, /* bFirstInterface */
0x02, /* bInterfaceCount */
USB_DEVICE_CLASS_AUDIO, /* bFunctionClass */
AUDIO_SUBCLASS_AUDIOCONTROL, /* bFunctionSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bFunctionProtocol */
0x00, /* iFunction (Index of string descriptor describing this function) */
/* 17 byte*/

/* USB Microphone Standard interface descriptor */
AUDIO_INTERFACE_DESC_SIZE, /* bLength */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType */
_AUDIO_MIC_AC_ITF_NBR, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
_AUDIO_MIC_STR_DESC_IDX, /* iInterface */
/* 26 byte*/

/* USB Microphone Class-specific AC Interface Descriptor */
AUDIO_INTERFACE_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
0x00, /* 1.00 */ /* bcdADC */
0x01,
0x25 + AUDIO_MIC_CHANNELS, /* wTotalLength = 37+AUDIO_CHANNELS*/
0x00,
0x01, /* bInCollection */
_AUDIO_MIC_AS_ITF_NBR, /* baInterfaceNr */
/* 35 byte*/

/* USB Microphone Input Terminal Descriptor */
AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
AUDIO_MIC_TERMINAL_ID, /* bTerminalID */
0x01, /* wTerminalType AUDIO_TERMINAL_USB_MICROPHONE 0x0201 */
0x02,
0x00, /* bAssocTerminal */
AUDIO_MIC_CHANNELS, /* bNrChannels */
#if (AUDIO_MIC_CHANNELS == 1)
0x00, /* wChannelConfig 0x0000 Mono */
0x00,
#else
0x03, /* wChannelConfig 0x0003 Stereo */
0x00,
#endif
0x00, /* iChannelNames */
0x00, /* iTerminal */
/* 47 byte*/

/* USB Microphone Audio Feature Unit Descriptor */
0x07 + AUDIO_MIC_CHANNELS + 1, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
AUDIO_MIC_FU_ID, /* bUnitID */
0x01, /* bSourceID */
0x01, /* bControlSize */

#if (AUDIO_MIC_CHANNELS == 1)
0x02,
0x00,
#else
0x00,
0x02,
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 2)
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 3)
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 4)
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 5)
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 6)
0x02,
#endif

#if (AUDIO_MIC_CHANNELS > 7)
0x02,
#endif
0x00, /* iTerminal */
//55 + AUDIO_MIC_CHANNELS byte

/*USB Microphone Output Terminal Descriptor */
0x09, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
AUDIO_MIC_OUT_TERMINAL_ID, /* bTerminalID */
0x01, /* wTerminalType AUDIO_TERMINAL_USB_STREAMING 0x0101*/
0x01,
0x00,
0x02,
0x00,
//64 + AUDIO_MIC_CHANNELS byte

/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */
/* Interface 1, Alternate Setting 0 */
0x09, /* bLength */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType */
_AUDIO_MIC_AS_ITF_NBR, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
//73 + AUDIO_MIC_CHANNELS byte

/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Operational */
/* Interface 1, Alternate Setting 1 */
0x09, /* bLength */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType */
_AUDIO_MIC_AS_ITF_NBR, /* bInterfaceNumber */
0x01, /* bAlternateSetting */
0x01, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
//82 + AUDIO_MIC_CHANNELS byte

/* USB Microphone Audio Streaming Interface Descriptor */
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
0x03, /* bTerminalLink */
0x01, /* bDelay */
0x01, /* wFormatTag AUDIO_FORMAT_PCM 0x0001*/
0x00,
//89 + AUDIO_MIC_CHANNELS byte

/* USB Microphone Audio Type I Format Interface Descriptor */
0x0B, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
AUDIO_FORMAT_TYPE_I, /* bFormatType */
AUDIO_MIC_CHANNELS, /* bNrChannels */
0x02, /* bSubFrameSize */
16, /* bBitResolution */
0x01, /* bSamFreqType */
AUDIO_MIC_SMPL_FREQ & 0xff, /* tSamFreq 8000 = 0x1F40 */
(AUDIO_MIC_SMPL_FREQ >> 8) & 0xff,
AUDIO_MIC_SMPL_FREQ >> 16,
//100 + AUDIO_MIC_CHANNELS byte

/* Endpoint 1 - Standard Descriptor */
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
0x05, /* bDescriptorType */
_AUDIO_MIC_EP, /* bEndpointAddress 1 in endpoint*/
0x05, /* bmAttributes */
#if 0
//Original
((AUDIO_MIC_SMPL_FREQ / 1000 + 2) * AUDIO_MIC_CHANNELS * 2) & 0xFF, /* wMaxPacketSize */
((AUDIO_MIC_SMPL_FREQ / 1000 + 2) * AUDIO_MIC_CHANNELS * 2) >> 8,
#else
((AUDIO_MIC_SMPL_FREQ / 1000) * AUDIO_MIC_CHANNELS * 2) & 0xFF, /* wMaxPacketSize LSB */
((AUDIO_MIC_SMPL_FREQ / 1000) * AUDIO_MIC_CHANNELS * 2) >> 8, /* wMaxPacketSize MSN */
#endif
0x01, /* bInterval */
0x00, /* bRefresh */
0x00, /* bSynchAddress */
//109 + AUDIO_MIC_CHANNELS byte

/* Endpoint - Audio Streaming Descriptor*/
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
0x00, /* bmAttributes */
0x00, /* bLockDelayUnits */
0x00, /* wLockDelay */
0x00,
//116 + AUDIO_MIC_CHANNELS byte
};
uint8_t USBD_AUDIO_MIC_Data_Transfer(USBD_HandleTypeDef *pdev, int16_t *audioData, uint16_t PCMSamples)
{

USBD_AUDIO_MIC_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_MIC_HandleTypeDef *)pdev->pClassData_UAC_MIC;

if (haudioInstance.state == STATE_USB_WAITING_FOR_INIT)
{
return USBD_BUSY;
}
uint16_t dataAmount = PCMSamples * 2; /*Bytes*/
uint16_t true_dim = haudio->buffer_length;
uint16_t current_data_Amount = haudio->dataAmount;
uint16_t packet_dim = haudio->paketDimension;

if (haudio->state == STATE_USB_REQUESTS_STARTED || current_data_Amount != dataAmount)
{
/*USB parameters definition, based on the amount of data passed*/
haudio->dataAmount = dataAmount;
uint16_t wr_rd_offset = (AUDIO_MIC_PACKET_NUM / 2) * dataAmount / packet_dim;
haudio->wr_ptr = wr_rd_offset * packet_dim;
haudio->rd_ptr = 0;
haudio->upper_treshold = wr_rd_offset + 1;
haudio->lower_treshold = wr_rd_offset - 1;
haudio->buffer_length = (packet_dim * (dataAmount / packet_dim) * AUDIO_MIC_PACKET_NUM);

/*Memory allocation for data buffer, depending (also) on data amount passed to the transfer function*/
if (haudio->buffer != NULL)
{
USBD_free(haudio->buffer);
}
haudio->buffer = USBD_malloc(haudio->buffer_length + haudio->dataAmount);
if (haudio->buffer == NULL)
{
return USBD_FAIL;
}
memset(haudio->buffer, 0, (haudio->buffer_length + haudio->dataAmount));
haudio->state = STATE_USB_BUFFER_WRITE_STARTED;
}
else if (haudio->state == STATE_USB_BUFFER_WRITE_STARTED)
{
if (haudio->timeout++ == TIMEOUT_VALUE)
{
haudio->state = STATE_USB_IDLE;
((USBD_AUDIO_MIC_ItfTypeDef *)pdev->pUserData_UAC_MIC)->Stop();
haudio->timeout = 0;
}
memcpy((uint8_t *)&haudio->buffer[haudio->wr_ptr], (uint8_t *)(audioData), dataAmount);
haudio->wr_ptr += dataAmount;
haudio->wr_ptr = haudio->wr_ptr % (true_dim);
if ((haudio->wr_ptr - dataAmount) == 0)
{
memcpy((uint8_t *)(((uint8_t *)haudio->buffer) + true_dim), (uint8_t *)haudio->buffer, dataAmount);
}
}
return USBD_OK;
}
static uint8_t USBD_AUDIO_MIC_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_AUDIO_MIC_HandleTypeDef *haudio;
uint16_t len;
uint8_t *pbuf;
uint16_t status_info = 0U;
USBD_StatusTypeDef ret = USBD_OK;

haudio = (USBD_AUDIO_MIC_HandleTypeDef *)pdev->pClassData_UAC_MIC;

if (haudio == NULL)
{
return (uint8_t)USBD_FAIL;
}

switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS:
switch (req->bRequest)
{
case AUDIO_REQ_GET_CUR:
USBD_AUDIO_MIC_REQ_GetCurrent(pdev, req);
break;

case AUDIO_REQ_SET_CUR:
USBD_AUDIO_MIC_REQ_SetCurrent(pdev, req);
break;

case AUDIO_REQ_GET_MIN:
USBD_AUDIO_MIC_REQ_GetMinimum(pdev, req);
break;

case AUDIO_REQ_GET_MAX:
USBD_AUDIO_MIC_REQ_GetMaximum(pdev, req);
break;

case AUDIO_REQ_GET_RES:
USBD_AUDIO_MIC_REQ_GetResolution(pdev, req);
break;

default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
break;

case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
(void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;

case USB_REQ_GET_DESCRIPTOR:
if ((req->wValue >> 8) == AUDIO_DESCRIPTOR_TYPE)
{

pbuf = USBD_AUDIO_MIC_CfgDesc + 18;
len = MIN(USBD_AUDIO_MIC_CONFIG_DESC_SIZE, req->wLength);

(void)USBD_CtlSendData(pdev, pbuf, len);
}
break;

case USB_REQ_GET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
(void)USBD_CtlSendData(pdev, (uint8_t *)&haudio->alt_setting, 1U);
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;

case USB_REQ_SET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if ((uint8_t)(req->wValue) <= USBD_MAX_NUM_INTERFACES)
{
haudio->alt_setting = (uint8_t)(req->wValue);

if (haudio->alt_setting == 1)
{
// USB class internal state must be set to allow DataIn
haudioInstance.state = STATE_USB_IDLE;

// Start your audio pipeline (DMA, I2S, etc.)
((USBD_AUDIO_MIC_ItfTypeDef *)pdev->pUserData_UAC_MIC)->Record();
}
else
{
// Stop streaming
haudioInstance.state = STATE_USB_IDLE;

((USBD_AUDIO_MIC_ItfTypeDef *)pdev->pUserData_UAC_MIC)->Stop();
}
}
else
{
/* Call the error management function (command will be NAKed */
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;

case USB_REQ_CLEAR_FEATURE:
break;

default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}

return (uint8_t)ret;
}

 

#define AUDIO_FRAMES          16
#define WORDS_PER_FRAME 1
#define I2S_BUFFER_SIZE 32

void HAL_I2SEx_TxRxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s->Instance == SPI2)
{
uint32_t samples =
Audio_Convert_I2S_To_USB_PCM(
&i2s_rx_buffer[0],
usb_pcm_buffer_half,
I2S_BUFFER_SIZE / 2);

Audio_Send(usb_pcm_buffer_half, samples);
}
}

void HAL_I2SEx_TxRxCpltCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s->Instance == SPI2)
{
uint32_t samples =
Audio_Convert_I2S_To_USB_PCM(
&i2s_rx_buffer[I2S_BUFFER_SIZE / 2],
usb_pcm_buffer_full,
I2S_BUFFER_SIZE / 2);

Audio_Send(usb_pcm_buffer_full, samples);
}
}