2020-07-05 11:45 AM
Hi, I am trying to get a robust isochronous transfer of audio from my STM32F072CB using the audio device class. My code is based on the code generated by STM32CubeMX for a speaker but I have changed the descriptor in order to make it an audio input. Basically all I have changed is usbd_audio.c and usbd_audio.h. I am sending 120 bytes on each DataIn interrupt (which I have confirmed occurs every millisecond) but when I record from this source, I only get 50% of the data and if I look at the USB trace using WireShark I can see that all my packets have errors and every second packet has no data! I have managed to find a few examples such as the X-CUBE-MEMSMIC1 example and as far as I can tell I am doing the same thing they are. Any help to get a reliable audio data transfer much appreciated!
static uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
//TODO: Check alternate setting
USBD_LL_Transmit(pdev, AUDIO_IN_EP, FAKEDATA, AUDIO_IN_PACKET);
return USBD_OK;
}
static uint8_t USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
return USBD_OK;
}
static uint8_t USBD_AUDIO_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_AUDIO_HandleTypeDef *haudio;
uint16_t len;
uint8_t *pbuf;
uint16_t status_info = 0U;
uint8_t ret = USBD_OK;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case AUDIO_REQ_GET_CUR:
AUDIO_REQ_GetCurrent(pdev, req);
break;
case AUDIO_REQ_SET_CUR:
AUDIO_REQ_SetCurrent(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)
{
USBD_CtlSendData(pdev, (uint8_t *)(void *)&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_CfgDesc + 18;
len = MIN(USB_AUDIO_DESC_SIZ, req->wLength);
USBD_CtlSendData(pdev, pbuf, len);
}
break;
case USB_REQ_GET_INTERFACE :
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
USBD_CtlSendData(pdev, (uint8_t *)(void *)&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 ((uint8_t)(req->wValue) == 1)
{
// Must send dummy packet to begin data in packets (not sure why?)
USBD_LL_Transmit(pdev, AUDIO_IN_EP, FAKEDATA, 0);
}
}
else
{
/* Call the error management function (command will be nacked */
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
return ret;
}
static uint8_t USBD_AUDIO_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
for(uint8_t i = 0; i < AUDIO_IN_PACKET; i+=2)
{
FAKEDATA[i+1] = i;
FAKEDATA[i] = 0;
}
USBD_AUDIO_HandleTypeDef *haudio;
/* Open EP OUT */
USBD_LL_OpenEP(pdev, AUDIO_IN_EP, USBD_EP_TYPE_ISOC, AUDIO_IN_PACKET);
pdev->ep_in[AUDIO_IN_EP & 0xFU].is_used = 1U;
/* Allocate Audio structure */
pdev->pClassData = USBD_malloc(sizeof(USBD_AUDIO_HandleTypeDef));
if (pdev->pClassData == NULL)
{
return USBD_FAIL;
}
else
{
haudio = (USBD_AUDIO_HandleTypeDef *) pdev->pClassData;
haudio->alt_setting = 0U;
haudio->offset = AUDIO_OFFSET_UNKNOWN;
haudio->wr_ptr = 0U;
haudio->rd_ptr = 0U;
haudio->rd_enable = 0U;
/* Initialize the Audio output Hardware layer */
if (((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Init(USBD_AUDIO_FREQ,
AUDIO_DEFAULT_VOLUME,
0U) != 0)
{
return USBD_FAIL;
}
}
return USBD_OK;
}