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!
USB Audio -> 2 * independent I2S channels
-
- Active Member
- Posts: 36
- Joined: Wed May 07, 2025 11:13 pm
-
Verified
- XCore Legend
- Posts: 1295
- Joined: Thu Dec 10, 2009 9:20 pm
- Location: Bristol, UK
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.
SRC with an additional I2S interface might be an easier option.
Technical Director @ XMOS. Opinions expressed are my own
-
- Active Member
- Posts: 36
- Joined: Wed May 07, 2025 11:13 pm
Thanks for responding so quickly Ross :)
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).
Thank you!
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 :)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.
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.
Thank you!
-
Verified
- XCore Legend
- Posts: 1295
- Joined: Thu Dec 10, 2009 9:20 pm
- Location: Bristol, UK
Interfaces are usb term, see here for an intro: https://www.beyondlogic.org/usbnutshell ... escriptors
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.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).
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
-
Verified
- XCore Legend
- Posts: 1295
- Joined: Thu Dec 10, 2009 9:20 pm
- Location: Bristol, UK
Interfaces are usb term, see here for an intro: https://www.beyondlogic.org/usbnutshell ... escriptors
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.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).
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
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
-
- Active Member
- Posts: 36
- Joined: Wed May 07, 2025 11:13 pm
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
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!
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!
-
Verified
- XCore Legend
- Posts: 1295
- Joined: Thu Dec 10, 2009 9:20 pm
- Location: Bristol, UK
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.
"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
-
- Active Member
- Posts: 36
- Joined: Wed May 07, 2025 11:13 pm
I think I understand what caused so much confusion from the start. On my initial 'pseudo-diagram' I should have done something like this:
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?
Regarding you previous comment, answer below:
I hope I'm correct about where we were out of sync so that everything else makes sense xD
Code: Select all
USB ----------------> I2S 1 (or 0) <----> CODEC
|
|
+-----------> I2S 2 (or 1) <----> External MCU
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
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.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..)
I hope I'm correct about where we were out of sync so that everything else makes sense xD
-
Verified
- XCore Legend
- Posts: 1295
- Joined: Thu Dec 10, 2009 9:20 pm
- Location: Bristol, UK
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.
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
-
- Active Member
- Posts: 36
- Joined: Wed May 07, 2025 11:13 pm
Thanks Ross, I've tested the app around, that's exactly what I needed :)