USB Audio -> 2 * independent I2S channels

Discussions about USB Audio on XMOS devices
Jcvc
Active Member
Posts: 36
Joined: Wed May 07, 2025 11:13 pm

USB Audio -> 2 * independent I2S channels

Post by Jcvc »

Hi,

Apologies in advance as I have not yet tried this at my end, but before I give it a go, would like to understand if the current framework supports USB audio stream to two independent I2S channels.

To provide some context to my question, what I'm essentially trying to do is to communicate, using xu316, with a CODEC and another external MCU.
The audio path would look something like:
USB <-> I2S 1 <-> CODEC
USB <-> I2S 2 <-> External MCU

I2S 1 and I2S do not share the bclk nor the lrclk. Ideally not even the MCLK for the I2S is shared.

Because my CODEC and MCU may not necessarily always be at the same rates, I need to have a dedicated I2S channel for each of them (at the moment I'll probably be placing one of them in tile 0 and another one on tile 1).

Does anyone know if there is any specific limitation that would stop me from doing this? Or would it just be a matter of expanding the implementation of XUA_AudioHub() to split/mix (depending on the direction) the usb buffered data to the I2S ports?

Thank you!
User avatar
Ross
Verified
XCore Legend
Posts: 1295
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

You'll essentially be implementing two usb audio devices, or interfaces here. Typically drivers will only support one active clock source in a device/interface.

SRC with an additional I2S interface might be an easier option.
Technical Director @ XMOS. Opinions expressed are my own
Jcvc
Active Member
Posts: 36
Joined: Wed May 07, 2025 11:13 pm

Post by Jcvc »

Thanks for responding so quickly Ross :)
You'll essentially be implementing two usb audio devices, or interfaces here. Typically drivers will only support one active clock source in a device/interface.
Hmm not sure if I understand what you mean here, on why it would require two usb audio devices. If by interfaces, you're referring to I2S interfaces, then that is exactly what I'm looking for :)
I haven't started development just yet (so please a pinch of salt on my comments/analysis), but currently I don't see why this would be any different from, for example, I2S + SPDIF use-case? To avoid writing to/from data of the usb host, my thoughts below are assuming data only comming from the USB host (even though bidirectional will be needed).
  • 1- Assuming we would be happy with the data that is coming from the USB, to be the same for both I2S channels, then we could split/copy the buffered data and 'just route' each of the new buffers to the specific I2S channel. Then, because the bclk/lrclk is not guaranteed to be the same on both, a resampler would then indeed be required to avoid any sample rate mismatch between the two peripherals.

    2- Assuming we would need dedicated audio stream for each I2S channel, it would be exactly like the I2S + SPDIF use-case at the moment, I think? But instead of another SPDIF, a new I2S (with independent BCLK/LRCK lines) would need to be configured.

    3- If none of the two above are feasible, I would probably have to settle with muxing between the two, that is, only one of them is active at a time.
Would appreciate your thoughts!

Thank you!
User avatar
Ross
Verified
XCore Legend
Posts: 1295
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Jcvc wrote: Wed Oct 15, 2025 12:03 pm Hmm not sure if I understand what you mean here, on why it would require two usb audio devices. If by interfaces, you're referring to I2S interfaces, then that is exactly what I'm looking for :)
Interfaces are usb term, see here for an intro: https://www.beyondlogic.org/usbnutshell ... escriptors
Jcvc wrote: Wed Oct 15, 2025 12:03 pm I haven't started development just yet (so please a pinch of salt on my comments/analysis), but currently I don't see why this would be any different from, for example, I2S + SPDIF use-case? To avoid writing to/from data of the usb host, my thoughts below are assuming data only comming from the USB host (even though bidirectional will be needed).
The main difference is that SPDIF and I2S are always on the same clock domain in the design - using a shared master clock (when SPDIF rx is used this clock is synced to the SPDIF input stream). Essentially you will need to provide what looks like two sound cards to the host - one for each clock domain. Each with its own clock, feedback etc. You wont (on most hosts) be able to stream to both simultaneously.

You can't just simply route/split - due to the different clock domains one will be under-flowing/underflowing due to drift between the two clocks. Essentially the restriction you're working against is that the design (and most/all drivers) support only one active clock domain.

I think SRC is you best bet here:

Code: Select all

USB ----------------> I2S 0
           |
           |
           +---> SRC --> I2S 1
Technical Director @ XMOS. Opinions expressed are my own
User avatar
Ross
Verified
XCore Legend
Posts: 1295
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Jcvc wrote: Wed Oct 15, 2025 12:03 pm Hmm not sure if I understand what you mean here, on why it would require two usb audio devices. If by interfaces, you're referring to I2S interfaces, then that is exactly what I'm looking for :)
Interfaces are usb term, see here for an intro: https://www.beyondlogic.org/usbnutshell ... escriptors
Jcvc wrote: Wed Oct 15, 2025 12:03 pm I haven't started development just yet (so please a pinch of salt on my comments/analysis), but currently I don't see why this would be any different from, for example, I2S + SPDIF use-case? To avoid writing to/from data of the usb host, my thoughts below are assuming data only comming from the USB host (even though bidirectional will be needed).
The main difference is that SPDIF and I2S are always on the same clock domain in the design - using a shared master clock (when SPDIF rx is used this clock is synced to the SPDIF input stream). Essentially you will need to provide what looks like two sound cards to the host - one for each clock domain. Each with its own clock, feedback etc. You wont (on most hosts) be able to stream to both simultaneously.

You can't just simply route/split - due to the different clock domains one will be under-flowing/underflowing due to drift between the two clocks. Essentially the restriction you're working against is that the design (and most/all drivers) support only one active clock domain.

I think SRC is you best bet here and (relatively) straight to develop, in that all the building blocks are provided.

Code: Select all

USB ----------------> I2S 0
           |
           |
           +---> SRC --> I2S 1
Start with https://github.com/xmos/sw_usb_audio/tr ... 6_extrai2s and add SRC from www.xmos.com/libraries/lib_src

One issue is that if the clocks are truly unrelated you will need to use ASRC, which is the trickiest and resource hungry variant.

Another option would be to get all clocks on one domain by using the pll (www.xmos.com/libraries/lib_sw_pll) to generate the master clock for one from the i2s clock of the other.
Technical Director @ XMOS. Opinions expressed are my own
Jcvc
Active Member
Posts: 36
Joined: Wed May 07, 2025 11:13 pm

Post by Jcvc »

Ross I need to digest a bit more your comment, but from the first read, I'm a bit confused regarding your mention of the SRC and non-sharing clocks.

With the SRC below, are you not referring to just resample the LRCLK? Because if so, I'm not quite understanding what you mean by unrelated clocks. Because in the scenario below, as I understand, the BCLK would have to be shared between I2S0 and I2S1

Code: Select all

USB ----------------> I2S 0
           |
           |
           +---> SRC --> I2S 1



I'll go in the meantime in more detail throughout the afternoon on your comment to analyse the other aspects of it.

Thank you Ross!
User avatar
Ross
Verified
XCore Legend
Posts: 1295
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Originally you said:

"I2S 1 and I2S do not share the bclk nor the lrclk. Ideally not even the MCLK for the I2S is shared."

This means there are two clock domains, one for i2s 1 and one for i2s 2 (I called them 0 and 1 earlier..)

both could be running at a nominal 48 kHz but one is actually at 48.001 and the other 48.003. This needs to be handled - through sample rate conversion or some other means.

If you can share clocks (originally you said nothing is shared) then this issue disappears.
Technical Director @ XMOS. Opinions expressed are my own
Jcvc
Active Member
Posts: 36
Joined: Wed May 07, 2025 11:13 pm

Post by Jcvc »

I think I understand what caused so much confusion from the start. On my initial 'pseudo-diagram' I should have done something like this:

Code: Select all

USB ----------------> I2S 1 (or 0)  <----> CODEC
           |
           |
           +-----------> I2S 2 (or 1) <----> External MCU
Apologies for the confusion I've caused for both of us Ross xD

If you don't mind, let me know if my comment @Post by Jcvc » Wed Oct 15, 2025 12:03 pm makes more sense now?

So, assuming that I was correct about our misunderstanding, one last question, based on your diagram below, where would you split the data before feeding into the SRC? After the endpoint buffer or at the audio driver?

Code: Select all

USB ----------------> I2S 0
           |
           |
           +---> SRC --> I2S 1
Regarding you previous comment, answer below:
Originally you said:

"I2S 1 and I2S do not share the bclk nor the lrclk. Ideally not even the MCLK for the I2S is shared."

This means there are two clock domains, one for i2s 1 and one for i2s 2 (I called them 0 and 1 earlier..)
Yes, that is correct. The BCLK & LRCLK are not to be shared. I thought the SRC on your diagram was referring to a 'normal' resampler, let's say from 16kHz to 48kHz. Assuming I understood where we were out of sync, as per my understanding now, as a SRC you're referring to a rate matching/adjust functionality, I wasn't thinking this far ahead on my original concept.


I hope I'm correct about where we were out of sync so that everything else makes sense xD
User avatar
Ross
Verified
XCore Legend
Posts: 1295
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

In my experience thinking though any clocking issues is fundamental to most audio designs and should be considered early on in the design process.

The easiest place would be to split at the audio driver - in the UserBufferManagement() function of the USB Audio design - you'll see its use in the extra i2s example I linked to earlier.
Technical Director @ XMOS. Opinions expressed are my own
Jcvc
Active Member
Posts: 36
Joined: Wed May 07, 2025 11:13 pm

Post by Jcvc »

Thanks Ross, I've tested the app around, that's exactly what I needed :)