Teensy in Raspberry I2S based digital chain.

Status
Not open for further replies.

Bart11

Member
Hello to all!
I need some help with some I2S connection problems. I am testing some DSPs by inserting them into my (digital) audio chain.

The starting point is:
Raspberry PI3+ (Master) >
Allo Isolator > (Passes Clocks according to Slave/Master direction)
Kali Recklocker (Input Slave, Output Master) >
TDA1543 based DAC

I have been able to insert a Minisharc DSP (and it worked):
Raspberry PI3+ (Master) >
Minisharc DSP > (Input Slave, Output Master)
Allo Isolator >
Kali Recklocker (Input Slave, Output Master) >
TDA1543 based DAC

I am now trying to insert a Teensy 3.6 in place of the Minisharc:
Raspberry PI3+ (Master) >
Teensy 3.6 > (Input Slave, Output Slave)
Allo Isolator >
Kali Recklocker (Input Slave, Output Master) >
TDA1543 based DAC

Due to the fact that Teensy is Input and Output Slave, both the Kali Reclocker and Teensy are sharing the Clocks coming from Raspberry.
The Teensy has been simply programmed to patch the I2S (stereo) signal through. (see picture)
The Result is that only one specific channel is playing. Always same speaker is playing whichever channel I disable with a comment.
The oscilloscope is the WCLK and BCLK Output from Raspberry: there are 32 bits per word cycle, so I would say BCLK is 1.4112 Mhz (44100*32).
My understanding is that Teensy would be compatible with this I2S format ?
Any ideas what is going on ?
Thanks :)
 

Attachments

  • 20180907_192044.jpg
    20180907_192044.jpg
    207 KB · Views: 117
  • 20180907_190216.jpg
    20180907_190216.jpg
    115.5 KB · Views: 111
  • 20180907_190206.jpg
    20180907_190206.jpg
    116.3 KB · Views: 110
Last edited:
The oscilloscope is the WCLK and BCLK Output from Raspberry: there are 32 bits per word cycle, so I would say BCLK is 1.4112 Mhz (44100*32).
My understanding is that Teensy would be compatible with this I2S format ?
Any ideas what is going on ?
Thanks :)

maybe because I2S audio library is 64 bit per word frame?
 
I2S stereo (master) does use 64 bits per frame. Long ago it was 32 bits per frame, but was changed to 64 for compatibility with the MEMS mics.

I2S quad channel (master only) is still 32 bits per frame. Someday it too will be updated to 64, but as of verson 1.43 it's still 32.

However, in slave mode, whatever device you connect to Teensy is in control of the clocks. Teensy has no choice but to (try to) work with whatever ratio it uses.
 
Hello Paul,
...so you are implying that (in slave mode) Teensy should be working correctly even with 32bits/frame and that the problem lies somwhere else ?
(I am feeding the clocks from RPI)
Thanks
B.
 
Hello Paul,
...so you are implying that (in slave mode) Teensy should be working correctly even with 32bits/frame and that the problem lies somwhere else ?
(I am feeding the clocks from RPI)
Thanks
B.

maybe by changing
Code:
	dma.TCD->SADDR = (void *)((uint32_t)&I2S0_RDR0 + 2);
to

Code:
	dma.TCD->SADDR = (void *)((uint32_t)&I2S0_RDR0);
in the "input_i2s.cpp" file of the audio library (inside void AudioInputI2Sslave::begin(void))
Teensy should work by taking the lower two bytes of the I2S port
 
Thanks for the help, I'll try it and let you know.
(The reason I am so keen to wire up the teensy is that it can only work on 44.1khz and does not perform Asynchronous Resampling. What some percieve as a limit to me is a great advantage! My experience is that ASRC degrades sound.)
 
Thanks for the help, I'll try it and let you know.
(The reason I am so keen to wire up the teensy is that it can only work on 44.1khz and does not perform Asynchronous Resampling. What some percieve as a limit to me is a great advantage! My experience is that ASRC degrades sound.)
You may know, that it is (relatively) easy to modify the audio functionality to work with any sampling frequency you want by adding some functions to your sketch (i.e. without touching the audio library.
 
Ps at this point I will really look into this. The I2S protocol should work even if there is a different word length between transimtter and receiver. If I am transmitting 16 bits, the receiver should be able to handle this even if it is expecting 32 bits. Maybe I wired wrongly. Will re-check everything and come back.
 
maybe by changing
Code:
	dma.TCD->SADDR = (void *)((uint32_t)&I2S0_RDR0 + 2);
to

Code:
	dma.TCD->SADDR = (void *)((uint32_t)&I2S0_RDR0);
in the "input_i2s.cpp" file of the audio library (inside void AudioInputI2Sslave::begin(void))
Teensy should work by taking the lower two bytes of the I2S port

Hello !
I have repeated the experiment by placing the Teensy between Kali reclocker and the TDA1543 chip.
I have modified the "input_i2s.cpp" as per your instructions.
Still, only one channel is playing: the output Data line is active only when WCLK is LOW.
There is something interesting going on though ! If I comment (disable) one of the two AudioConnectios, only half of the samples (of the Single playing channel) appear in the output.
If I reverse the comments, data appears on the complementary half (of the playing channel). (Please note the pictures)
I would guess this has to do with the output_i2s part of the equation. The Teensy is definitely providing Left and Right Input channel data to the Left Output channel.
 

Attachments

  • 20180909_175735.jpg
    20180909_175735.jpg
    71.6 KB · Views: 111
  • 20180909_181602.jpg
    20180909_181602.jpg
    65.5 KB · Views: 106
  • 20180909_181705.jpg
    20180909_181705.jpg
    67.2 KB · Views: 106
I2S stereo (master) does use 64 bits per frame. Long ago it was 32 bits per frame, but was changed to 64 for compatibility with the MEMS mics.

I2S quad channel (master only) is still 32 bits per frame. Someday it too will be updated to 64, but as of verson 1.43 it's still 32.

However, in slave mode, whatever device you connect to Teensy is in control of the clocks. Teensy has no choice but to (try to) work with whatever ratio it uses.

Hello !

I have checked what I2S bus specifications states about different word length compatibility. In theory I2S should work whatever the word length:

3.1 Serial Data
Serial data is transmitted in two’s complement with the MSB first.
The MSB is transmitted first because the transmitter and receiver
may have different word lengths. It isn’t necessary for the transmitter
to know how many bits the receiver can handle, nor does the
receiver need to know how many bits are being transmitted.
When the system word length is greater than the transmitter word
length, the word is truncated (least significant data bits are set to ‘0’)
for data transmission. If the receiver is sent more bits than its word
length, the bits after the LSB are ignored. On the other hand, if the
receiver is sent fewer bits than its word length, the missing bits are
set to zero internally. And so, the MSB has a fixed position, whereas
the position of the LSB depends on the word length. The transmitter
always sends the MSB of the next word one clock period after the
WS changes.


https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf
 
You may know, that it is (relatively) easy to modify the audio functionality to work with any sampling frequency you want by adding some functions to your sketch (i.e. without touching the audio library.

WMXZ - do you have any links or details as to how to do this (change audio lib sampling frequency), thanks
 
Sorry, I was on travel,
Have a look in https://github.com/WMXZ-EU/microSoundRecorder how to mix up basic audio-library functionality and own modification
(OK, there is much more in it, but maybe it helps as starting point)

Walter - microSoundRecorder looks great - your coding ability and understanding of Teensy surpasses mine by a mile or 10 (just graduating from Arduino to VSCode).

I very roughly follow what you are doing to change the sample rates with the PDB timer and then matching I2S.

For my immediate needs (slowing down audio sampling for an effect) I've ended up just matching successive samples to simulate a lower sampling rate.

I will definitely come back microSoundRecorder when I get a bit of time to look at how to do it properly - thanks for the point in the right direction.
 
I have repeated the experiment by placing the Teensy between Kali reclocker and the TDA1543 chip.
I have modified the "input_i2s.cpp" as per your instructions.
Still, only one channel is playing: the output Data line is active only when WCLK is LOW.
There is something interesting going on though ! If I comment (disable) one of the two AudioConnectios, only half of the samples (of the Single playing channel) appear in the output.
If I reverse the comments, data appears on the complementary half (of the playing channel). (Please note the pictures)
I would guess this has to do with the output_i2s part of the equation. The Teensy is definitely providing Left and Right Input channel data to the Left Output channel.

I'm trying to understand what I should do here to reproduce this problem.

As I understand, you've got a non-Teensy I2S master sending data with BCLK/LRCLR ratio of 32. Is the Teensy 3.6 running just a simple program with I2S slave input & output connected to each other, so the output should be the same as the input (but slightly delayed)? Or is something more complex running on the Teensy? Are these scope pictures just watching Teensy's I2S TX pin and the BCLK signal arriving from other hardware? Or something else?

Really, my main question is what should I wiring up here on my workbench to try to recreate this problem?

The quad channel I2S still uses BCLK/LRCLK ratio of 32. Maybe I could use another Teensy running quad channel output in master mode as a stand-in for the non-Teensy hardware?
 
I'm trying to understand what I should do here to reproduce this problem.

As I understand, you've got a non-Teensy I2S master sending data with BCLK/LRCLR ratio of 32. Is the Teensy 3.6 running just a simple program with I2S slave input & output connected to each other, so the output should be the same as the input (but slightly delayed)? Or is something more complex running on the Teensy? Are these scope pictures just watching Teensy's I2S TX pin and the BCLK signal arriving from other hardware? Or something else?

Really, my main question is what should I wiring up here on my workbench to try to recreate this problem?

The quad channel I2S still uses BCLK/LRCLK ratio of 32. Maybe I could use another Teensy running quad channel output in master mode as a stand-in for the non-Teensy hardware?


Hello Paul,
thanks for your reply. Your assumptions are all correct.
* Yes, the Raspberry RPI3 was master sending data with BCLK/LRCLK ratio of 32. (i.e. two words, each word containing 16 bits). I have Volumio installed and playing music 44.1Khz WAV files (CD Red Book).
* Yes, the Teensy was running ONLY the code I listed above. It was just a test to see if I can get data thorugh the Teensy without any changes whatsoever. Output should be same as Input.
* Yes BCLK and LRCLK are coming from the Raspberry, while the output is Teensy's TX pin. I can take another picture comparing TX and RX if you wish.
My setup was:
RPI pin 35 to Teensy pin 23 LRCLK
RPI pin 12 to Teensy pin 9 BCLK
RPI pin 40 DOUT to Teensy pin 13 RX
RPI pin 39 to Teensy GND
You would be measuring Teensy pin 22 TX
Regarding the use of the quad channel, it is not exactly clear to me how it transmits data. If the BCLK/LRCLK ratio is 32, I would assume it uses two LRCLK cycles to transmit all four channels in one tap. I... don't think we could test it that way.
I can do more experiments if you wish. Today I was trying to connect another player with BCLK/LRCLK = 64 but I did not get any signal out.
 
32 bit words

This would be the input from a Player with BCLK/LRCLK ratio of 64. No signal on Teensy's TX at the moment. Will repeat.
In the photo It is nicely visible that only 16 bits of the 32 available are transmitted.
(LRCLK and RX)
 

Attachments

  • 20180923_173930.jpg
    20180923_173930.jpg
    55.2 KB · Views: 103
To reproduce the problem using two Teensies, I would do the following:
Teensy1 transmits whatever WAV using I2S master mode as output. Teensy2 would have I2S Input slave and I2S Ouput slave (the code I've listed above)
Connect pins 9 together.
Connect pins 23 together.
Teensy1 pin 22 goes to Teensy2 pin 13
Connect GNDs together.
On Teensy2 pin 22 (TX) you should have the same output (delayed) as from Teensy1 pin 22 (TX)
Teensy2 should be transparent :) with Teensy1 acting as master.
I cannot try this because I only own 1 Teensy :)
 
This would be the input from a Player with BCLK/LRCLK ratio of 64. No signal on Teensy's TX at the moment.

Did you undo the edit (msg #7) to the I2S code for this test? If you have that change in the code, then Teensy will be retransmitting the low 16 bits.
 
I've got it wired up on my desk right now, with BCLK/LRCLK ratio of 64. It seems to be working. I can't reproduce the no-data-output problem.

Here's the hardware, using a Teensy 3.2 as I2S master transmitting to a Teensy 3.6 as I2S slave. The connections are exactly as you described in msg #20.

DSC_0220_web.jpg

DSC_0222_web.jpg

Here is what I see on my oscilloscope. The green trace is the data from Teensy 3.2 (pin 22) to Teensy 3.6 (pin 13) and the red trace is the output from Teensy 3.6 (pin 22). I match wire colors to the oscilloscope prode & trace colors, so hopefully it's easy to see.

file.png

This is the code I ran on the Teensy 3.2 to transmit data as I2S master on only the left channel.

Code:
#include <Audio.h>

AudioSynthWaveformSine   sine1;          //xy=119,137
AudioOutputI2S           i2s1;           //xy=280,136
AudioConnection          patchCord1(sine1, 0, i2s1, 0);

void setup() {
  AudioMemory(10);
  sine1.frequency(440);
  sine1.amplitude(0.9);
}

void loop() {
}

This is the code I ran on the Teensy 3.6, to receive and retransmit the data in I2S slave mode.

Code:
#include <Audio.h>

AudioInputI2Sslave       i2sslave1;      //xy=129,136
AudioOutputI2Sslave      i2sslave2;      //xy=311,136
AudioConnection          patchCord1(i2sslave1, 0, i2sslave2, 0);
AudioConnection          patchCord2(i2sslave1, 1, i2sslave2, 1);

void setup() {
  AudioMemory(10);
}

void loop() {
}
 
I changed the Teensy 3.2 to transmit with BCLK/LRCLK ratio of only 32, by using the quad channel output. This is with Teensyduino 1.44 on Arduino 1.8.7 (at some point in the future quad I2S will become a ratio of 64 like stereo is, but for 1.44 it's still a ratio of 32).

This is the code I ran on the Teensy 3.2. I only changed "AudioOutputI2S" to "AudioOutputI2SQuad".

Code:
#include <Audio.h>

AudioSynthWaveformSine   sine1;          //xy=119,137
AudioOutputI2SQuad       i2s1;           //xy=280,136
AudioConnection          patchCord1(sine1, 0, i2s1, 0);

void setup() {
  AudioMemory(10);
  sine1.frequency(440);
  sine1.amplitude(0.9);
}

void loop() {
}

The Teensy 3.6 is running the same code, copying I2S input to output using slave mode.

Here's what I see on my oscilloscope.

file.png

I can't seem to reproduce the problem of the left channel appearing on every other output cycle.
 
Hello Paul,
that was great help. At this point I really wonder where the problem might lie. I will try to repeat this setup and see what comes out.
Thanks for now !
B.
 
Status
Not open for further replies.
Back
Top