yun
yun

Reputation: 1283

USB Audio Buffer Underrun

I'm working on a USB Audio aysnchronous implementation on a microcontroller and I seem to be running into buffer underrun issues on the input side of things at 48kHz sample rate/24 bit rate (it works at 44.1kHz though).

I'm double buffering in my implementation:

(1) Codec -> DMA has a couple buffers. When one buffer is completely filled, I load this into my USB buffers.

(2) USB side has 40 buffers (basically 40ms of data). When a buffer's status is "FILLED", it is okay to send. A USB callback is done after a successful USB transfer and sends the next filled buffer.

In my implementation, I fill at least 3/4 of the buffers (30 buffers) before before USB starts transferring actual data (so in the first 30ms, it's just "silent" data). Basically, the buffer underrun happens as my codec/dma buffer is not completely filled yet and the next buffer to be read is "EMPTY". I feel like the easiest solution to this would be to have more buffers (clearly 40 buffers is not enough; approximately 11kb of data since 40 * 294 bytes = 11760 bytes), however I cannot increase it as my microcontroller has simply run out of available memory.

What are my options to solving this at this point of time? Is there a workaround to the limit of available buffers I have/available leftover memory? Or is the only way to add a SRAM on to have enough available buffers.

Thanks!

EDIT: It appears this is a bit confusing. Basically codec isn't filling fast enough; thus, there are gaps of data in USB buffers and creating an "underrun" of data.

EDIT2: I'm running an asynchronous with implicit sync endpoint; host is being read once per frame. Sorry that wasn't clear either.

Upvotes: 1

Views: 2148

Answers (1)

Martin
Martin

Reputation: 476

Your endpoint should be read by host once per frame (I assume you are constructing isochronous IN endpoint, async with implicit synchronization). If this is not true in your case, please state it clearly in your question as it would be quite strange problem.

Anyway, because of that, there is not much use for more than three buffers (two will do with bit of careful thinking too). You do not need more buffers. But your buffers should be somewhat longer than calculated nominal samples-per-frame and your endpoint's descriptor should contain this extended length.

Then, you always switch buffer being filled on and only on the start of USB frame (or on any other event synchronized with USB SOF). Regardless of the amount of data in the current buffer! When USB host wants to read from your endpoint, your device has to return as many samples as there actually is in the currently read buffer. No more, no less.

So there is no chance for underrun. You simply send lesser number of samples to the host when the buffer being read was not fully filled before and it is host's task to deal with clock drift and resampling in whichever suitable way. You could worry about overrun on the other hand. If SOF frequency would be too low compared to ADC's sample rate, you could fill whole buffer before SOF comes and end up with no place for next sample. Simple fix is to make your buffer is at least few samples longer than calculated nominal rate. You should be safe then, otherwise things are probably already broken much more elsewhere.

Last problem you could worry about is host not sending read request for your endpoint while SOFs are ticking normally. Well, in this case overwriting old buffers can not hurt much as host is obviously not interested in data in this very moment and buffering things -- thus increasing latency -- will likely do more bad than good.

Upvotes: 1

Related Questions