Connecting Two Teensys via I2S

Status
Not open for further replies.

jkoffman

Well-known member
Starting a new thread for this. Since my experiments switching to a T4.0 went awry (posted elsewhere), while I wait for more parts to arrive I decided to experiment with connecting two Teensy 3.2 boards via I2S to transfer audio. This is with two bare boards, the sender would stream USB audio in, then send it via I2S to the receiver board, which takes in the I2S and flips it back to USB. Connections here:

Sender:
Code:
AudioInputUSB            usb1;           //xy=175,225
AudioMixer4              mixer1;         //xy=302,118
AudioOutputI2SQuad       i2s_quad1;      //xy=498,230
AudioConnection          patchCord1(usb1, 0, i2s_quad1, 0);
AudioConnection          patchCord2(usb1, 0, i2s_quad1, 2);
AudioConnection          patchCord3(usb1, 1, i2s_quad1, 1);
AudioConnection          patchCord4(usb1, 1, i2s_quad1, 3);

Receiver:
Code:
AudioInputI2Sslave       i2sslave1;      //xy=254,291
AudioMixer4              mixer1;         //xy=302,118
AudioOutputUSB           usb1;           //xy=510,297
AudioConnection          patchCord1(i2sslave1, 0, usb1, 0);
AudioConnection          patchCord2(i2sslave1, 1, usb1, 1);

There isn't much actual code, just a declaration of audio memory (went with 12), and code to blink an LED. The mixer object is in there just in case I was hitting an update issue, it isn't connected to anything.

Here's a photo of the wiring (tried for reasonably short):
IMG_9020.jpg


The good news is that this wasn't a complete failure. I was able to connect the receiver to either of the I2S outputs on the sender and it would receive. That's my ultimate goal.

The bad is that it sounds terrible. Like I've got a sample rate issue. I can make out that it isn't just noise, but it sounds fuzzy. I can post a clip if that would help. With or without MCLK connected it didn't seem to matter.

I'm not sure what to try next. I can't figure out if I've got an issue between the two Teensys, or if using i2sslave and USB together is a no no.

Any thoughts or guidance?

Thank you!
 
try with consistent I2S setups
e.g. both stereo I2S devices
Stereo I2S is 32 bit/word, and Quad I2S is still 16 bit/word. so frame size does not correspond.
 
Aha, that was it! Thank you for the help!

Unfortunately this probably means I can't use this transport. The sender Teensy will also be connected to an audio board.

I wonder if it's possible to create a 16 bit i2s_slave receiver...
 
On Teensy 4.0 and 4.1 the quad, hex and octal I2S use BCLK/LRCLK ratio of 64 (and that is why I took extra time to implement these rather than copying the approach we had on Teensy 3). Regular stereo uses ratio of 64, on all boards. Quad I2S on Teensy 3.x is the only thing left using ratio 32 (in the early days everyhing had ratio of 32).

So this probably can work if you use Teensy 4.0 or 4.1 to transmit I2S.

Though I don't quite understand why you would transmit 4 channels when the source appears to be only 2 channels over USB. Maybe you have something else planned which really does need 4 channels?
 
Hi Paul, thanks for weighing in!

Yes, ultimately there will be 4 channels transmitted, two to an audio board, two to the second Teensy.

Once I get the Teensy 4.0s I ordered, I might switch to SPDIF. That was my original plan but then I destroyed a 4.0 with bad level shifting to talk to my 5V display driver. But if I can get this I2S working, it frees me to use whatever I have on hand, two 3.2, or two 4.0.

I am digging through the audio library right now, I'm hoping I can figure out the magic to either make a i2s_slave that is set to use a ratio of 32, or an i2s_quad that is set for slave.

Any help appreciated!
 
I might have gotten it! I've been messing around with this, doing some reading of the datasheet, etc.

I started by creating copies of output_i2s and input_i2s .cpp and .h files. I modified the filenames and function names so I can have it exist peacefully with the stock library functions. I tested this by compiling them into my existing receiver project, it works fine as an i2s slave with the sender using regular i2s. I then changed the server back to i2s_quad, and we're back to the noise as expected. So far so good.

Digging into the differences between the _quad code and not, I noticed the various word size definitions. On the vanilla i2s object they're all set to 31, but on the _quad they're set to 15. So I modified my i2s_slave object so everything was 15 and....nothing. Not a peep.

Some messing around and it appears that everything should be 15 EXCEPT I2S_RCR5_FBT (First Bit Shifted). I'm not 100% sure why this works (still digging in the datasheet and learning about the module), but as of right now I am running quad output on the sender and my new i2s_slave_16 on the receiver and audio is flowing. I have not tested the slave transmit code, but I made the same changes in case I ever need to come back to it.

For those curious, my changes are here. Each time I've made a change I've left the original code commented out in the line above.

Code:
	// configure transmitter
	I2S0_TMR = 0;
	I2S0_TCR1 = I2S_TCR1_TFW(1);  // watermark at half fifo size
	I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP;

	I2S0_TCR3 = I2S_TCR3_TCE;
// 	I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(31) | I2S_TCR4_MF
// 		| I2S_TCR4_FSE | I2S_TCR4_FSP;
	I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF
		| I2S_TCR4_FSE | I2S_TCR4_FSP;

// 	I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
	I2S0_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(31);

	// configure receiver (sync'd to transmitter clocks)
	I2S0_RMR = 0;
	I2S0_RCR1 = I2S_RCR1_RFW(1);
	I2S0_RCR2 = I2S_RCR2_SYNC(1) | I2S_TCR2_BCP;

	I2S0_RCR3 = I2S_RCR3_RCE;
// 	I2S0_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(31) | I2S_RCR4_MF
// 		| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
	I2S0_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF
		| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;

// 	I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);
	I2S0_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(31);

If anyone has any insight into anything I might be forgetting or doing wrong I'd love to hear about it!
 
You could also use github to look at the code from 4-5 years ago, back when every I2S input & output used BCLK/LRCLK ratio of 32.
 
Ah, great idea. I will check that out this afternoon!

Is there a technical reason that i2s_quad hasn't gone to a ratio of 64 yet on the 3.x series? Or is it just that it's lower on the priority list. My solution works for me, so I'm just curious.

Thanks!
 
Well, I had a look. As of August 2015, all of those values were 15 in output_i2s.cpp, including I2S_RCR5_FBT. The rest of the settings appear the same I believe. I tried going back to 15 on FBT but it gives me no audio when I do.

Strange.
 
It's on my list to try. I hadn't done it since I wasn't sure if there was a technical reason Paul hadn't done it officially.
 
I'll probably back-port this to Teensy 3.x eventually. But it's a low priority, which realistically means "eventually" may be years, or never.
 
It's on my list to try. I hadn't done it since I wasn't sure if there was a technical reason Paul hadn't done it officially.
I posted code for 64 * Fs Quad I2S master and slave in my reply to your previous thread. You could use that as a starting point.
 
Status
Not open for further replies.
Back
Top