1024Fs MCLK with UAC1 on XU208

Sub forums for various specialist XMOS applications. e.g. USB audio, motor control and robotics.
Post Reply
Silas
Junior Member
Posts: 4
Joined: Wed Mar 25, 2015 2:49 pm

1024Fs MCLK with UAC1 on XU208

Post by Silas »

Distorted audio in UAC1 mode on XU208 when using 1024*MCLK with sw_usb_audio-[sw]_6.15.2rc1
The standard build 512*MCLK version works fine in both USB Audio Class 2 and Class 1.

If I instead run at 1024*MCLK audio output works fine for UAC2, but changing to UAC1 to test AUDIO_CLASS_FALLBACK the audio output is distorted.

The clocks value in buffer() seems far to high (it doesn't match the value seen when running at 512*MCLK), which is used to set both g_speed and fb_clocks. If I set the clocks value here manually for the incoming sample rate then the audio is fine, so there seems to be some issue calculating the number of MCLK ticks in the SOF period that is then used to calculate the clocks value used when sofCount == 128 in buffer().
For UAC1 I can manually put in values here for the limited sample frequency cases available for audio class fallback, but it would be nicer to have it working from the calculated value.

Any suggestions on how to fix this appreciated.


Silas
Junior Member
Posts: 4
Joined: Wed Mar 25, 2015 2:49 pm

Post by Silas »

So, in usb_buffer.xc

Code: Select all

                    /* Reset counts based on SOF counting.  Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll
                     * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */
                    if(sofCount == 128)
                    {
                        clockcounter += mod_from_last_time;
                        clocks = clockcounter / masterClockFreq;
                        mod_from_last_time = clockcounter % masterClockFreq;
                        clocks <<= 6;
seems to get the wrong value for clocks in FS mode at 1024*MCLK, but is ok for 512*MCLK

Until I can find why, I have fixed by making

Code: Select all

                        clocks = ((sampleFreq * 16384) / 1000) << 2;
for the specific case of 1024*MCLK and XUD_SPEED_FS.
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

Thanks for raising this... It may be a bug if section 5.12.4.2 of the USB spec is not being met.

I (and others) have had 1024x MCLK running fine but personally I have only had it under UAC2. UAC1 runs at full speed so the maths is different, including the representation of the fixed point feedback value. It's possible there is an overflow in the calculation in FS mode.

Your workaround will unfortunately will cause glitches - there is no accounting for the asynchronous relationship between clocks. So you will get an occasional under/overflow depending on your actual MCLK vs reported samples required.

There are going to be some large numbers in there at fullspeed USB and 49.152MHz clock but it uses long longs, so should be OK...

What values are you actually seeing? Is the calculation wrong for all sample rates at 1024x MCLK/ Full speed?
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

I had a thought..

Each SOF the code gets the port counter value and subtracts the value from last time around. However, the port counter is only 16bits. Clocking this at 49.152MHz for 1 millisecond (FS SOF period) could be problematic unless you are very careful about overflow and signs..

Would you be able to print out the variable *count* to see if your MCLK count is right? (should be about 49152)
Silas
Junior Member
Posts: 4
Joined: Wed Mar 25, 2015 2:49 pm

Post by Silas »

You are correct about it being the port counter.
Replacing

Code: Select all

                    int count = (int) ((short)(u_tmp - lastClock));
with

Code: Select all

                    unsigned count;
                    if (u_tmp < lastClock)
                        count = (unsigned) ((unsigned)(u_tmp + (unsigned)(0x10000 - lastClock)));
                    else
                        count = (unsigned) ((unsigned)(u_tmp - lastClock));
seems to work and fixes the clocks count so that the playback is no longer distorted.
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

seems to work and fixes the clocks count so that the playback is no longer distorted.
Nice work! I'll add a bug against the reference design with your fix. Thanks!
Post Reply