isn't sample rate supposed to change when locked to SPDIF?

If you have a simple question and just want an answer.
User avatar
bowerymarc
Active Member
Posts: 40
Joined: Mon Dec 30, 2013 7:29 am

isn't sample rate supposed to change when locked to SPDIF?

Post by bowerymarc »

I'm using the slicekit with app_usb_aud_skc_u16_audio8 project from USB-Audio-2.0-Device-Software_6.12.6 set to target 2io_spdifout_spdifin, connected to a powerbook, OSX Yosemite 10.10.5.

When I select SPDIF In as the clock source, the sample rate doesn't change. E.g. I'll set internal sample rate 88.2K, and have a 48K spdif input, and select SPDIF clock, and the sample rate doesn't change to 48K. Also the output sample rate of the board doesn't change. The clock stays on SPDIF input in the Mac's AudioMIDI control panel - if I unplug the spdif cable, it reverts to internal. So it seems the board's happy with the input stream.

I figured there was only one clock domain at a time and it should update to the SPDIF sample rate... what am I missing?
xmos spdif clock.jpg
You do not have the required permissions to view the files attached to this post.


User avatar
Ross
XCore Expert
Posts: 966
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Hi,

No, it doesn't by default - that was a design decision based on customer feedback in the musical instrument space where having the device rate change without user interaction is seen as a bad thing.

You could modify the code, but note, this is just a notification that something has changed, the host most query as to the reason and perform any appropriate action. The device must continue to operate at its original sample rate until the host instructs otherwise - failing to do so is going to cause problems with the async clocking scheme and the host driver.
User avatar
bowerymarc
Active Member
Posts: 40
Joined: Mon Dec 30, 2013 7:29 am

Post by bowerymarc »

OK... now I'm really confused.

What actually does the clock source select box do in the firmware? (from trying to trace through the source, it seems like it's actually changing the clock source to the digital input)

Which sample clock is the hardware/firmware following when you select SPDIF in clock?

If the hardware/firmware is tracking the external digital in's sample clock, then which sample rate is the USB driver (host) following?

Thanks
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

OK... now I'm really confused.

What actually does the clock source select box do in the firmware? (from trying to trace through the source, it seems like it's actually changing the clock source to the digital input)
It selects the reference for the PLL to be either a fixed square wave generated by a timer off the local processor clock or a toggle signal derived from SPDIF receive.
Which sample clock is the hardware/firmware following when you select SPDIF in clock?
The one generated by receiving SPDIF frames by the code in clockgen.xc.
i.e. use the clock recovered from SPDIF rx
If the hardware/firmware is tracking the external digital in's sample clock, then which sample rate is the USB driver (host) following?
The one selected by the host. So the user needs to ensure fs spdif = fs host else you will get lots of noise

Edit... The host sample rate tracks the device sample rate because we use asynchronous USB audio where the device provides feedback about the local mclk to the host. However the nominal sample rate (fs) must be correctly selected so that the clock calculation on the host is correct.
User avatar
bowerymarc
Active Member
Posts: 40
Joined: Mon Dec 30, 2013 7:29 am

Post by bowerymarc »

Thanks for the reply!
infiniteimprobability wrote:
OK... now I'm really confused.

What actually does the clock source select box do in the firmware? (from trying to trace through the source, it seems like it's actually changing the clock source to the digital input)
It selects the reference for the PLL to be either a fixed square wave generated by a timer off the local processor clock or a toggle signal derived from SPDIF receive.
It ultimately calls AudioHwConfig() in audiohw.xc to change the clock source, correct?
infiniteimprobability wrote:
If the hardware/firmware is tracking the external digital in's sample clock, then which sample rate is the USB driver (host) following?
The one selected by the host. So the user needs to ensure fs spdif = fs host else you will get lots of noise

Edit... The host sample rate tracks the device sample rate because we use asynchronous USB audio where the device provides feedback about the local mclk to the host. However the nominal sample rate (fs) must be correctly selected so that the clock calculation on the host is correct.
So how can the xmos firmware force a sample rate change on the host (assume CoreAudio here where there's no ability to alter the drivers) so everything's peachy without explicit user intervention?
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

It ultimately calls AudioHwConfig() in audiohw.xc to change the clock source, correct?
No - audiohw.xc handles the user part of setting up the audio hardware on a sample rate or stream format change initiated by the host.

clockgen.xc handles the audio clock selection.
So how can the xmos firmware force a sample rate change on the host (assume CoreAudio here where there's no ability to alter the drivers) so everything's peachy without explicit user intervention?
I haven't done it so cannot say for sure, but here are some pointers / ideas / things to try.

You need to get the host to recognise that something has changed and for it to change the sample rate (everything in USB is host initiated, even interrupts which are just a regular poll really).

The interrupt mechanism is already in the firmware and are certainly in the UAC2 spec "..inform the host about dynamic changes that occur on the different addressable Entities"

I couldn't see mention of an interrupt for the Clock entity however section 6.2 states "Any Control within an addressable Entity of the audio function can be the source of an interrupt. The interrupt message contains enough information to determine exactly which Control caused the interrupt. The Host can then issue the normal Control requests to further qualify the cause of the interrupt."

The question is, will the host driver see this and then do something? I can't see what it could do exactly because how would it know which sample rate to choose from the list? - What should it do precisely? Perhaps you could restrict the range reported...or maybe have multiple clock sources (each being an entity) and use the clock selector to switch between them using an interrupt. I am not sure without some investigation work...

What I'd recommend to do next is have a play with generating an interrupt from the following code (which sends the entity ID across to usb_buffer.xc to report the interrupt to the host).

See what actually happens from the host side. It looks like this code is sending an interrupt message which is the entity ID of the relevant clock source.

Code: Select all

static int clockFreq[NUM_CLOCKS];                           /* Store current clock freq for each clock unit */
static int clockValid[NUM_CLOCKS];                          /* Store current validity of each clock unit */
static int clockInt[NUM_CLOCKS];                            /* Interupt flag for clocks */
static int clockId[NUM_CLOCKS];

Code: Select all

#if defined(SPDIF_RX) || defined(ADAT_RX)
static inline void setClockValidity(chanend c_interruptControl, int clkIndex, int valid, int currentClkMode)
{
    if (clockValid[clkIndex] != valid)
    {
        clockValid[clkIndex] = valid;
        outInterrupt(c_interruptControl, clockId[clkIndex]);

#ifdef CLOCK_VALIDITY_CALL
#ifdef ADAT_RX
        if (currentClkMode == CLOCK_ADAT && clkIndex == CLOCK_ADAT_INDEX)
        {
            VendorClockValidity(valid);
        }
#endif
#ifdef SPDIF_RX
        if (currentClkMode == CLOCK_SPDIF && clkIndex == CLOCK_SPDIF_INDEX)
        {
            VendorClockValidity(valid);
        }
#endif
#endif
    }
}

There is also an interesting section in the spec worth reading: 5.2.6.1.1 Active Alternate Setting Control
"This Control is used to inform Host software which Alternate Setting of an AudioStreaming interface is currently active. The main purpose of this Control is to notify the Host (through an interrupt) that the last selected Alternate Setting is no longer valid. There can be a variety of reasons why this could happen. For instance, increasing the sampling frequency of a Clock Source Entity might render the current Alternate Setting of an interface connected to that Clock Source invalid because more bandwidth is now needed than is available in the current Alternate Setting."

Again, I am not sure if the driver in OSX supports this..

Edit.
One further thought, and something I would try first in your shoes... the current code reports the following after a clock interupt:

Code: Select all

                                    case ID_CLKSRC_INT:
                                        /* Always report our current operating frequency */
                                        (buffer, unsigned[])[0] = g_curSamFreq;
                                        return XUD_DoGetRequest(ep0_out, ep0_in, buffer, 4, sp.wLength );
                                        break;
I wonder what would happen if g_curSamFreq was replaced by the new samp freq that you wanted to switch to, when issuing an interrupt from entity ID_CLKSRC_INT?
You can issue an interrupt request in clockgen by running the helper

Code: Select all

outInterrupt(chanend c_interruptControl, int value)
User avatar
bowerymarc
Active Member
Posts: 40
Joined: Mon Dec 30, 2013 7:29 am

Post by bowerymarc »

infiniteimprobability wrote:
It ultimately calls AudioHwConfig() in audiohw.xc to change the clock source, correct?
No - audiohw.xc handles the user part of setting up the audio hardware on a sample rate or stream format change initiated by the host.

clockgen.xc handles the audio clock selection.
After spending quite some time with clockgen.xc I still can't figure out where that is happening.... I get that clockGen() has some token streams to select the clock that come from endpoint0, but I don't get how it's actually changing the clock source. (I need to select from a variety of hardware clocks and inputs when this happens, eventually)
infiniteimprobability wrote:
So how can the xmos firmware force a sample rate change on the host (assume CoreAudio here where there's no ability to alter the drivers) so everything's peachy without explicit user intervention?
I haven't done it so cannot say for sure, but here are some pointers / ideas / things to try.
Those look like good avenues for exploration, and I appreciate the thought that went into them, and I'll bookmark this page, but honestly, I can't get into fixing what in my opinion, as a long time designer of digital pro audio gear, is a wrong design choice in this firmware. We'll see if the users agree with the decision if I don't have time to fix it before it ships. I can't really afford to go down the rabbit hole at the moment. I think xmos should look at this again, and at the very least provide an option to do it either way.
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

I think xmos should look at this again, and at the very least provide an option to do it either way.
I hear you and I can see the point - I'm an apps engineer so don't make the resource/project decisions so will pass on your comments to the product guys. As ever, it helps to have an idea about opportunity size to help them make the priority calls. Feel free to PM me with these so I can pass them on.
User avatar
bowerymarc
Active Member
Posts: 40
Joined: Mon Dec 30, 2013 7:29 am

Post by bowerymarc »

infiniteimprobability wrote: I hear you and I can see the point - I'm an apps engineer so don't make the resource/project decisions so will pass on your comments to the product guys. As ever, it helps to have an idea about opportunity size to help them make the priority calls. Feel free to PM me with these so I can pass them on.
Thanks I will. They seemed to like my SMUX standard, as it's in the driver... I came up with that a long time ago while at Sonorus.

Any clue about my clocking question above? Or should I start another thread for that?
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Do you mean
I don't get how it's actually changing the clock source.
?

In clockgen, the reference for the CS2100 is driven by port p. So whereever you see

Code: Select all

p <: pinVal;
or similar, it's sending an edge for the ref clock.

The code sending the edges is guarded by

Code: Select all

clkMode
or the timer comparing against timeNextEdge. If the clock is recovered, timeNextEdge is set far enough in the future that it doesn't fire

This is all controlled via endpoint zero which handles the USB audio control entities.