Electronic – USB Audio Input Jitter (?)

audiomicrocontrollersignal processingusb

Hopefully this is the right sub to ask this question. Anyways, I'm working on a USB Audio device on a microcontroller and I'm having issues with getting a consistent audio input.

Some preface:

As of right now, I have connected the mcu and codec via I2S (codec is slave) with the following configurations:

MCLK = 11.2896 MHz
BCLK = 2.8224 MHz
LRCLK = 44.1 kHz
USB CLK = 12 MHz

When I do a simple DSP bypass (codec input -> mcu -> codec output), the audio is glitch free and awesome. However, when I enable USB, that's when things get weird. I'll get occasional glitches and the signal sometimes repeats itself. I'm not totally sure if this is because I'm not using enough buffers when writing to USB.

Right now my codec reads and USB writes are happening separately:

Codec Flow: Codec Input -> MCU I2S RX -> DMA Interrupt when I2S RX buffer is full 
            -> Write this buffer into USB buffers -> Calculate next input frame len

USB: USB initiates input -> Write buffer to USB endpoint -> USB Write Callback 
     called when USB transfer is complete -> Start reading next buffer

How I'm calculating my frame lengths:

#define AUDIO_POLL_INT     4
#define FRAME_BYTES        3
#define NUM_CHANNELS       STEREO

// Calculate the frame length
uint16_t frame_len = 44 (44.1kHz/1000 samples) * NUM_CHANNELS * FRAME_BYTES;
// Every 10 ms, calculate frame length with additional frame (only applies to 44.1kHz sample rate)
if (!(frame_pos % 9)) frame_len += (1 * NUM_CHANNELS * FRAME_BYTES)

// Increment frame position per usb call
frame_pos = (((frame_pos + 1) / 8) * (2 << (AUDIO_POLL_INT-1))) % 10;
frame_pos = (frame_pos + 1) % 10;

Actual Question/What I think is going wrong (?)

I'm guessing there is some jitter issues due to the codec MCLK and USB CLK rates being different (11.2896 vs 12). I'm only guessing this because the interruptions/glitches happen pretty periodically. I also have noticed that the codec buffers will "catch" up to the USB buffers every once in a while (codec buffer will overwrite a USB buffer even though the USB buffer is marked "full"). However, I'm not sure how to stop this from happening because the codec would go out of sync and I would lose audio data. I also cannot speed up the USB transfers obviously… I'm transferring a max of 270 bytes per USB write for a sample rate of 44.1 kHz.

If anyone has had experience with USB audio and synchronization, your help would be appreciated! I'm not sure how to approach the problem from here honestly. If you're wondering, USB Audio output is fine though (with the exception of some channels not being synchronized).

Best Answer

It's hard to be sure (since this is obviously not your actual code), but it appears that you have hard-coded the pattern of frame lengths on the USB side, on the assumption that the audio sample rate (i.e., the 11.2896 MHz codec clock) is strictly locked to the USB data rate (i.e., the 12.000 MHz USB clock). This would only be true if the codec clock was driven by a PLL that is referenced to the USB clock. In actual fact, they can be different by 10s or even 100s of ppm, given the usual tolerances associated with general-purpose crystals.

Instead, you should be picking the USB frame length dynamically, based on the actual amount of data you have in local buffers that you have received from the codec. If this total is above some threshold, you should send the longer USB frame; otherwise, send the shorter USB frame. This allows the average rate of the USB transfers to track the actual sample rate defined by the codec clock.