2019-07-18 02:22 AM
As far as I know, STM32Cube does not offer support for creating an USB microphone (only speaker, as stated in the specification). However, I have managed to use the X-CUBE-MEMSMIC1 package to create an audio device, only replacing the usbd_audio.c and .h files.
The second problem that I have is that this package only offers support for 16-bit samples. By changing the descriptors below (in file usbd_audio_in.c), the device is recognized as a 24-bit device :
USBD_AUDIO_CfgDesc[index++] = 0x03; /* bSubFrameSize */ //For 16: 0x02
USBD_AUDIO_CfgDesc[index++] = 24; /* bBitResolution */ // For 16: 16
To send the samples, we use a function called USBD_AUDIO_Data_Transfer :
/**
* @brief USBD_AUDIO_Data_Transfer
* Fills the USB internal buffer with audio data from user
* @param pdev: device instance
* @param audioData: audio data to be sent via USB
* @param dataAmount: number of PCM samples to be copyed
* @note Depending on the calling frequency, a coherent amount of samples must be passed to
* the function. E.g.: assuming a Sampling frequency of 16 KHz and 1 channel,
* you can pass 16 PCM samples if the function is called each millisecond,
* 32 samples if called every 2 milliseconds and so on.
* @retval status
*/
uint8_t USBD_AUDIO_Data_Transfer(USBD_HandleTypeDef *pdev, int32_t * audioData, uint32_t PCMSamples)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if(haudioInstance.state==STATE_USB_WAITING_FOR_INIT){
return USBD_BUSY;
}
uint16_t dataAmount = PCMSamples * 2; /*Bytes*/ // Maybe here?
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_IN_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_IN_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 = (uint8_t *)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_ItfTypeDef *)pdev->pUserData)->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;
}
Which changes the state of the USB transfer and copies the data to the buffer. I've changed it to 32-bit input so I can use it with my 24-bit samples.
The function USBD_AUDIO_DataIn is also called and handles the low level :
/**
* @brief USBD_AUDIO_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_AUDIO_DataIn (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = pdev->pClassData;
uint32_t length_usb_pck;
uint16_t app;
uint16_t IsocInWr_app = haudio->wr_ptr;
uint16_t true_dim = haudio->buffer_length;
uint16_t packet_dim = haudio->paketDimension;
uint16_t channels = haudio->channels;
length_usb_pck = packet_dim;
haudio->timeout=0;
if (epnum == (AUDIO_IN_EP & 0x7F))
{
if (haudio->state == STATE_USB_IDLE)
{
haudio->state=STATE_USB_REQUESTS_STARTED;
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Record();
}
if (haudio->state == STATE_USB_BUFFER_WRITE_STARTED)
{
haudio->rd_ptr = haudio->rd_ptr % (true_dim);
if(IsocInWr_app<haudio->rd_ptr){
app = ((true_dim) - haudio->rd_ptr) + IsocInWr_app;
}else{
app = IsocInWr_app - haudio->rd_ptr;
}
if(app >= (packet_dim*haudio->upper_treshold)){
length_usb_pck += channels*2;
}else if(app <= (packet_dim*haudio->lower_treshold)){
length_usb_pck -= channels*2;
}
USBD_LL_Transmit (pdev,AUDIO_IN_EP,
(uint8_t*)(&haudio->buffer[haudio->rd_ptr]),
length_usb_pck);
haudio->rd_ptr += length_usb_pck;
if(app < haudio->buffer_length/10)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Stop();
haudio->state = STATE_USB_IDLE;
haudio->timeout=0;
memset(haudio->buffer,0,(haudio->buffer_length + haudio->dataAmount));
}
}
else
{
USBD_LL_Transmit (pdev,AUDIO_IN_EP,
IsocInBuffDummy,
length_usb_pck);
}
}
return USBD_OK;
}
/**
* @brief USBD_AUDIO_EP0_RxReady
* handle EP0 Rx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_AUDIO_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = pdev->pClassData;
if (haudio->control.cmd == AUDIO_REQ_SET_CUR)
{
if (haudio->control.unit == AUDIO_OUT_STREAMING_CTRL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->VolumeCtl(VOL_CUR);
haudio->control.cmd = 0;
haudio->control.len = 0;
haudio->control.unit = 0;
haudio->control.data[0]=0;
haudio->control.data[0]=0;
}
}
return USBD_OK;
}
And finally, at the initialization, we define the packet size. As I noticed by looking at the X-CUBE-USB-AUDIO package, the packet size should be multiplied by 3 instead of 2 for 24-bit instead of 16 bit :
haudioInstance.paketDimension = (samplingFrequency/1000*Channels*3); // For 16: *2
haudioInstance.frequency=samplingFrequency;
haudioInstance.buffer_length = haudioInstance.paketDimension * AUDIO_IN_PACKET_NUM;
haudioInstance.channels=Channels;
haudioInstance.upper_treshold = 5;
haudioInstance.lower_treshold = 2;
haudioInstance.state = STATE_USB_WAITING_FOR_INIT;
haudioInstance.wr_ptr = 3 * haudioInstance.paketDimension;
haudioInstance.rd_ptr = 0;
haudioInstance.dataAmount=0;
haudioInstance.buffer = 0;
But when I change this my microphone simply stops working (though it is still recognized by the host). And when I keep the same parameters as the 16-bit I do not get good results for the exit.
My best guesses are that it has something to do with the buffer size (dataAmount) or the writing pointer wr_prt.
Does anyone know how to solve this?
Regards,
Gabriel
2020-04-01 03:42 AM
Hello,
I am trying to fix this issue also.
did someone solve it already?
Avi
2020-07-24 06:52 AM
ran into the same issue... looking for a fix...
2020-07-25 11:13 PM
Hi,
I found the answer,
In the function USBD_AUDIO_DataIn()
You should change the calculation of length_usb_pck to be depended on the resolution.
if(app >= (packet_dim*haudio->upper_treshold)){
length_usb_pck += channels*3;//2;
}else if(app <= (packet_dim*haudio->lower_treshold)){
length_usb_pck -= channels*3;//2;
Avi
2021-03-27 10:53 AM
Hi
i have the same problem so please can you include all the modification needed for 24 bits audio