AnsweredAssumed Answered

STM32F4 USB Audio Device IN endpoint circular buffer

Question asked by heyheybhey on Oct 14, 2016
Hello everyone, i'm working on an  Audio IN endpoint USB Device (a microphone). The idea is to capture audio data from a codec and send this data to a PC by USB by implementing an isochronous IN endpoint.

I want to implement an Asynchronous endpoint, this is, for each 1ms frame, I will send to the PC the amount of audio data captured by the codec. Given that the PC has a time base different from the STM32F4 timebase, packet size might change from one frame to the other. 

For example, using 48kHz sampling frequency and stereo 16 bits samples, in one frame I could send 192 bytes, on the next 200 bytes, and the next perhaps 188 bytes. All depends on the clock frequency difference that exists between the PC and the STM32F4.

I'm using the HAL library to receive data from the codec by I2S using DMA in circular buffer mode, and then sending data by using the USBD_LL_Transmit() function of the USB device library.

The problem is that the audio input buffer will be written faster or slower than the rate with which the USBD_AUDIO_DataIn() function is called. So, sometimes I will have the situation where data in the input buffer is splitted (as it is a circular buffer) and I need to pass a linear buffer to the USBD_LL_Transmit() function.

I can think of these solutions:
- Restart the DMA writing pointer everytime that USB asks for a new packet. This way data will be always arranged linearly. The problem with this approach is that for doing this I need to pause the DMA transfer causing desynchronization in the audio sampling proccess.
- Copy the splitted data to a new linear buffer and pass this as argument for the USBD_LL_Transmit() function. Problem -> not enought time if I want to keep a low latency in the interface (I want to use only two buffers, 1ms delay). Also, the code complexity increases.
- Calling the USBD_LL_Transmit() function two times by frame to send the two pieces of splitted data. I tried this with no success. The USB interface stops working.
- Pass a circular buffer as input argument for the USBD_LL_Transmit() function. Problem -> does a function like this exists? Writting this new low level function could be very difficult.

Some ideas, corrections?
Do you know how this is usually handled in comercial USB audio interfaces?

Thank you very much.