Teensy 4 PCM5242 Audio Shield - Stereo Balanced/Single Ended DAC Module

Status
Not open for further replies.
I did have a thought experiment, wondering besides USB/ethernet what would be the most sound outputs/inputs you could put on a Teensy 4.1, while still using the SPI ports, etc. My thought is:

  • I2S1 with 5 data pins (6-9, and 32) along with the control pins (23, 21, 20);
  • I2S2 with 2 data pins (2, 5) along with the control pins (3, 4, 33);
  • S/PDIF (pins 14, 15);
  • Midi on hardware serial1 (pins 0, 1);
  • Midi on hardware serial3 (pins 14, 15) if you aren't using S/PDIF;
  • Midi on hardware serial6 (pins 24, 25);
  • Midi on hardware serial7 (pins 28, 29);
  • Midi on hardware serial8 (pins 34, 35);
  • Flash chip to hold sounds (underneath pads 49-54); (and)
  • Micro-SD card to hold sounds (built-in).

Obviously whether the Teensy could control all of those pins, both in terms of enough CPU cycles and power levels, I don't know.
 
Just play chip tunes using PWM.
Turn off interrupts and control the PWM directly for each pin, manually.
MUSIC ON ALL THE PINS!

Also, I thought S/PDIF used the same hardware as IIS, so you couldn't actually use both at the same time?
 
Just play chip tunes using PWM.
Turn off interrupts and control the PWM directly for each pin, manually.
MUSIC ON ALL THE PINS!

Also, I thought S/PDIF used the same hardware as IIS, so you couldn't actually use both at the same time?

Most pins, not all pins. It looks like on the Teensy 4.1, there are 15 pins that are not PWM capable (16, 17, 20, 21, 26, 27, 30, 31, 32, 34, 35, 38, 39, 40, and 41 in the outer row pins). In addition, there are only so many timers, so you likely couldn't use all of them for independent melodies. Obviously, they might not produce great sound compared to the other methods (I2S, S/PDIF, etc.).

There is TDM, but it looks like TDM uses the I2S hardware.

According to the latest design tool beta (https://www.pjrc.com/teensy/gui2) there are 3 S/PDIF library outputs created by FrankB:
  • SPDIF: Uses I2S1 pin 7 for output on Teensy 4.x and 22 on Teensy 3.x (i.e. you cannot use I2S1);
  • SPDIF2: Uses I2S2 pin 2 on Teensy 4.x (i.e. you cannot use I2S2); (and)
  • SPDIF3: Uses Teensy 4.x hardware for S/PDIF (pin 14) and uses neither I2S1 nor I2S2.

For S/PDIF inputs the choices are:
  • SPDIF3: Uses Teensy 4.x hardware for S/PDIF input (pin 15); (and)
  • SPDIF_async: Uses Teensy 4.x hardware for S/PDIF input (pin 15) as well.

I am only quoting the gui that Paul is working on. Obviously FrankB can weigh in on the pluses and minuses. If you go to the 1062 datasheet, it looks like the hardware stuff for S/PDIF starts on page 2021.

It looks like there is a third SAI-3 section in the hardware (SAI-1 is I2S1, SAI-2 is I2S2). I imagine there was not enough room to bring out the pins for SAI-3.

If you are just playing pre-recorded songs, another possibility is to use something like the DFPlayer that either has flash memory or a micro-SD card to play from:

A few years ago, I played around with the Adafruit Audio FX boards. They are kind of bulky, but if you wanted something that you could add buttons to play pre-defined sounds, they worked. But I likely would just go with the DFPlayer these days if I didn't want to program a Teensy.
 
Last edited:
Oh, that's sweet! I was going by the old documentation that says SPDIF shares hardware with I2S.
 
Oh, that's sweet! I was going by the old documentation that says SPDIF shares hardware with I2S.

It looks like it went into Teensydunio 1.52 that was just released. Fortunately, Paul is now working on improving the documentation, so hopefully things will be better soon.
 
mhelin,

Still not convinced that it will be helpful. But it's interesting nonetheless and was easy to add. I added 4 pins, corresponding to the 4 data lines required for clocks and data.
Is a 1 x .05 mm solder pad big enough?

Jay

Those GPIO pins can be used for other purposes as well, it depends on the software (configration). The TI solution is like the AD's miniDSP. Problem is getting the (right) PurePath software:
http://www.ti.com/tool/PUREPATHCONSOLE

You can also use the older PurePath Studio workflow if the PPC3 doesn't work for you.
See https://e2e.ti.com/support/audio/f/6/p/536470/1957035?tisearch=e2e-sitesearch&keymatch= user:151472
You can download the 5242 framework for PurePath Studio from there, there's the link to zip file.

Then you have to figure out how get the generated source and binary files into Teensy and use it to program the DSP(s). Some implementation examples for MSP430 can be found here:

https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/166/slac640.zip
Documentation (pdf) here: http://www.ti.com/lit/an/slaa605a/slaa605a.pdf?keyMatch=msp430 AIC3254&tisearch=Search-EN
 
Last edited:
Obviously for Teensy 4.0, you don't have access to OUT1B (for 1st I2S bus) and MCLK2 (for 2nd I2S bus) or to the USB host support unless you either solder wires to the pads or use one of the breakout boards.

Correct. I've left a 2.54 stack-able header compatible through-hole in my custom "Audio Footprint" that would allow the MC2 and O1B to be passed along to any sub-board. But to get it to that pin there is extra work... Soldered jumper cables, or otherwise.

Note, since you mentioned USB Host and Ethernet, you probably want to include those pins on your board, so if you stack your devices, the user can bring these pins out to the top of the stack.

I would only use a T4.1 if I wanted Ethernet.

It would be nice to your users if you also brought out the Program pin, On/Off pin, and Vbat pins, so that they can be accessed without de-stacking your boards.

I would probably just use the T4.1 and stack the audio modules underneath. Or if someone wanted to stack on top, then can also stack in a breakout board to expose that stuff in another way. I'm kinda hoping to keep my modules audio focused only.


For S/PDIF inputs the choices are:
SPDIF3: Uses Teensy 4.x hardware for S/PDIF input (pin 15); (and)
SPDIF_async: Uses Teensy 4.x hardware for S/PDIF input (pin 15) as well.

Oh yeah, I need to add that to my list. I definitely need to keep pin 15 open. I know FrankB committed SPDIF input, but if/when SPDIF Out is available it will be on Pin 14. So those two pins are also out - I would include them as a "digital audio" pin.

Maybe a MCP100-315 or -475 could handle the reset independently from the teensy...

That's a neat part. I was wondering if anything like that existed, or if the reset pin was more easily handled other than running a wire to the MCU. I guess it's not that bad to run to the MCU, easier than a circuit right? :) It's already done on my design.

I'm going to go review the datasheet now, make a quick determination if I can fit it on my board, and see if it's worth it. The board is pretty much ready to go, and I'm itching to get it working, but this is a nice idea. If I use it I'll have a jumper for it to connect to pin 22 - in case this circuit doesn't work at first go - or if it's left in the traces but and not populated in the final design.

Pin 22 is now officially the "RESET" pin for this project. Lol. Thanks for all the help!
 
Maybe a MCP100-315 or -475 could handle the reset independently from the teensy...


These parts monitor the level of the VDD (voltage source). The TLV320ADC6140 has IOVDD and AVDD power supply options. My design has options for single supply, or a separate AVDD power supply, which in some cases may increase the quality of the sound. I need to wait for both AVDD and IOVDD supplies to reach 3.3v, so there is a need for 2 supply monitors (MCP100T-315I_TT). It fit appropriately on the board, and looks neat - clean traces and shouldn't negatively impact sound. I've also installed a jumper to optionally control the SHDNZ (RESET) pin with pin 22 of the Teensy - but these reset monitors might be easier and actually better since when we add modules we will also add to potential startup times, creating timing issues (maybe).


jpk, Have you used these before? My question is this. If I connect the two RST pins to the ADC "SHDNZ" (aka RESET) pin, will it work? The ADC will be enabled only when both monitors pull high ("active low"). Do I need a pull-up resistor anywhere?

MCP100T-315I-TT_SCHEAMTIC2.png
 
My question is this. If I connect the two RST pins to the ADC "SHDNZ" (aka RESET) pin, will it work? The ADC will be enabled only when both monitors pull high ("active low"). Do I need a pull-up resistor anywhere?

I found my answer in TI's documentation called Voltage Supervisor and Reset ICs: Tips, Tricks and Basics. In order to have an "AND" operation with two supervisors I needed to have an "open drain" style device. I found the cheapest one I could find, that should do the trick just fine.

I chose a TLV803SDBZR . It looks like this.

TLV803SDBZR_Scheamtic.png

It monitors for 2.93V with a Fixed Delay Time of 200 ms. The TLV320ADC6140 datasheet shows the minimum operating voltage when running on a 3.3v rail to be 3.0v. Since my Reset Power Supervisor circuit runs on 2.93v, I think I need to install a resistor between VDD and the input of the Supervisor chip. I have to calculate what value the resistor should be to make the input pin < 2.93 when VDD > 3.0v. Or I just rely on the fact that 200 ms is plenty of time to get from 2.93 to 3.0 v.

While this reset circuitry does make a much more robust circuit, MCU control over pin 22 definitely would have been easier. It's more robust because if there were many of these on a project (8 boards for 32 inputs) i can see it taking different times to power all 8 boards up. At the same time, I suppose just putting a long delay on the reset pin at startup (600ms?) would also solve the issue. After working through all of this, wondering if it's worth it. :) Wondering if it stays in, or comes out. :)
 
)jpk, Have you used these before?

Yes, it helps me saving pins and code. I reset a DOGM204 display with it (through a voltage divider) and also Teensies 3.5/3.6 powered from DC-DC supplies. Without the MCP100s I couldn't get them boot up from those supplies...
 
Hello Teensy Friends,

I have a question regarding the Teensy Audio Library and the mixer gain structure. In pro-audio gain structure is of high importance. The right gain structure will result in higher quality sound, and less feedback from the microphones.

Long story short is that I have a working prototype on my desk. Yup! I have my PCM5242 and TLV320ADC6140 (actually it's a 5140) working, playing, sounding great overall. More on this soon enough, but first back to my gain structure questions.

TEENSY_AUDIO_MIXER_PROTOTYPE.jpg

The Teensy "mixer" creates clipping if all the inputs add up to greater than 1. So if you want to have 16 microphone inputs coming out of the TDM input and flowing through to the output, you need to use 5 mixers to sum them all together. 4 mixers will sum up all the 16 inputs. Then the last one will sum together the 4 mixers to create 1 audio stream.

MIXER_ADC.png

So in code we have this for the audio tool.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputTDM            tdm2;           //xy=88,184
AudioMixer4              mixADC_a2;         //xy=302,173
AudioMixer4              mixADC_a1;         //xy=306,99
AudioMixer4              mixADC_a3;         //xy=306,246
AudioMixer4              mixADC_a4;         //xy=310,330
AudioInputUSB            usb1;           //xy=529,276
AudioMixer4              mixADC_a;         //xy=537,149
AudioMixer4              mixLeft1;         //xy=755,171
AudioMixer4              mixRight1;         //xy=757,286
AudioOutputTDM           tdm1;           //xy=1024,206
AudioConnection          patchCord1(tdm2, 0, mixADC_a1, 0);
AudioConnection          patchCord2(tdm2, 1, mixADC_a1, 1);
AudioConnection          patchCord3(tdm2, 2, mixADC_a1, 2);
AudioConnection          patchCord4(tdm2, 3, mixADC_a1, 3);
AudioConnection          patchCord5(tdm2, 4, mixADC_a2, 0);
AudioConnection          patchCord6(tdm2, 5, mixADC_a2, 1);
AudioConnection          patchCord7(tdm2, 6, mixADC_a2, 2);
AudioConnection          patchCord8(tdm2, 7, mixADC_a2, 3);
AudioConnection          patchCord9(tdm2, 8, mixADC_a3, 0);
AudioConnection          patchCord10(tdm2, 9, mixADC_a3, 1);
AudioConnection          patchCord11(tdm2, 10, mixADC_a3, 2);
AudioConnection          patchCord12(tdm2, 11, mixADC_a3, 3);
AudioConnection          patchCord13(tdm2, 12, mixADC_a4, 0);
AudioConnection          patchCord14(tdm2, 13, mixADC_a4, 1);
AudioConnection          patchCord15(tdm2, 14, mixADC_a4, 2);
AudioConnection          patchCord16(tdm2, 15, mixADC_a4, 3);
AudioConnection          patchCord17(mixADC_a2, 0, mixADC_a, 1);
AudioConnection          patchCord18(mixADC_a1, 0, mixADC_a, 0);
AudioConnection          patchCord19(mixADC_a3, 0, mixADC_a, 2);
AudioConnection          patchCord20(mixADC_a4, 0, mixADC_a, 3);
AudioConnection          patchCord21(usb1, 0, mixLeft1, 3);
AudioConnection          patchCord22(usb1, 1, mixRight1, 3);
AudioConnection          patchCord23(mixADC_a, 0, mixLeft1, 0);
AudioConnection          patchCord24(mixADC_a, 0, mixRight1, 0);
AudioConnection          patchCord25(mixLeft1, 0, tdm1, 0);
AudioConnection          patchCord26(mixRight1, 0, tdm1, 1);
// GUItool: end automatically generated code


Then in my setup code I would have something like this.

Code:
mixADC_a1.gain(0, 0.25);
mixADC_a1.gain(1, 0.25);
mixADC_a1.gain(2, 0.25);
mixADC_a1.gain(3, 0.25);
mixADC_a2.gain(0, 0.25);
mixADC_a2.gain(1, 0.25);
mixADC_a2.gain(2, 0.25);
mixADC_a2.gain(3, 0.25);
mixADC_a3.gain(0, 0.25);
mixADC_a3.gain(1, 0.25);
mixADC_a3.gain(2, 0.25);
mixADC_a3.gain(3, 0.25);
mixADC_a4.gain(0, 0.25);
mixADC_a4.gain(1, 0.25);
mixADC_a4.gain(2, 0.25);
mixADC_a4.gain(3, 0.25);
mixADC_a.gain(0, 0.25);
mixADC_a.gain(1, 0.25);
mixADC_a.gain(2, 0.25);
mixADC_a.gain(3, 0.25);
mixLeft1.gain(0, 0.5);
mixRight1.gain(4, 0.5);

It works, but my gain structure isn't quite right yet. I have a lot of moving parts on this device. The ADC has gain, volume, filters, etc. So I'm testing different configurations to see what works best. But so far I'm getting sound that is either too low (not enough), or too high (clipping). From what I know about professional audio, most of the gain should be applied at the first stage of the audio path. So setting the gain to the right setting on the ADC is ideal. Then each mixer should ultimately push through "unity gain".

But assuming that not all sets will have a microphone or line source going into each ADC input, how can I set my mixers? I don't want to loose signal integrity along the way, and it appears that I might be losing integrity because each ADC channel is being digitally attenuated (???). Once on mixADC_a1, then again on mixADC_a, then again on the mixLeft1. So it's being cut and sliced.

Then what happens if the other three channels of mixADC_a1 aren't producing any sound? Is line 1 getting attenuated for no reason? If line 2 then gets connected, will line 1 get lower in volume? I'm sorry for this "newbie" type question, I'm just not 100% familiar with this part yet. Clearly I'm just trying to learn this and understand it correctly. Does anyone have any input for me? Is there any ideas/concepts/plans for a mixer that just sums up all the inputs and sends a "unity gain" output to the next mixer/block? Would my concept of applying 0.25 gain to each input channel do this? Would this just send a unity gain to the next block? Or only when there are 4 things playing sound?

Thanks for the advice! More info coming soon.
 
TLDR: How do we do a simple pass through mix? How can we mix multiple channels without adding or removing gain resulting in clipping?


In a normal mixer every channel gets a volume, and this doesn't matter. It's not a sum of all channels, it's all channels mixed together without any gain added...

What's the strategy here?
 
From what I know about professional audio, most of the gain should be applied at the first stage of the audio path.

This is certainly true when working to analog signals. You want the best low-noise preamp to get the signal up to a normal level, since pretty much anything else you do analog will add noise. Larger signal and same noise is better signal to noise ratio.

When working with digital data, perhaps you could consider numerical round off to be noise, but it's really not the sort of issue as with traditional analog signals where resistors, transistors, and pretty much anything adds noise and/or distortion.


What's the strategy here?

I do not believe there is a single one-size-fits-all strategy to mixing audio. If there were, you wouldn't see professional mixing boards with a sea of knobs & sliders! Usually choices about mixing levels are more art than science. If you go with a pure science approach that mixing N signals requires attenuating than all with 1/N gain, you can indeed get a result that is guaranteed to never clip. But it's probably not going to be very interesting or pleasing either.
 
Great, thanks guys. I'll keep working on it and will look at your links.

Quick question, which may get to my point faster.

The following is the signal path of channel 1, a microphone with 32dB of gain via the preamp on the TLV320ADCx140. Let's assume all the lines are hooked up in my project, but there is nothing playing through channel 2, 3, or 4 of the ADC.

  1. mixADC_a1.gain(0, 0.25);
  2. mixADC_a.gain(0, 0.25);
  3. mixLeft1.gain(0, 0.5);


Does that mean that channel 1 is being attenuated down 25%, then 25%, then 50%?
 
When the gain is 0.25, I believe the proper English description would be "attenuated down 75%". The word "attenuated" generally means how much something is reduced. Think of it like a sale. If you're shopping and you see a bright red sign that says a $50 product is 25% off, you would expect to pay $37.50.

But if you were to say "attenuated to" or "attenuated, resulting in" or some other way of mentioning the final outcome rather than the process of reduction, then 25% would probably be correct. English language is tricky like that.

To specifically address your question, a signal passing through 3 mixers with gain 0.25, 0.25 and 0.5 would be reduced to only 0.03125 times (1/32nd of) its original amplitude. That's still quite audible if other louder sounds don't overwhelm it, but a pretty low amplitude.
 
I believe the proper English description would be "attenuated down 75%".

You got me! Yes that's what I meant.

reduced to only 0.03125 times (1/32nd of) its original amplitude

Yup, that's what I'm experiencing. That's way too low.


That's a great discussion. In that thread there is a user endolith who discuses headroom. And the importance of higher bit-rates to expand the available headroom.

In analog hardware, the headroom is maybe 20 dB. In a hardware DSP, fixed-point is often used, with a fixed headroom; AD's SigmaDSP, for instance, has 24 dB of headroom. In computer software, the audio processing is usually performed in 32 bit floating point, so the headroom is enormous.

So with 16-bit processing I wonder what type of headroom I have? There are some mixing capabilities inside the ADC too that I might want to dig deeper into. My personal needs are relatively limited. I need USB, Bluetooth, and 2 microphones for a minimum viable product. Although I would strive for more. But the 32 channel digital audio mixer idea doesn't sound promising at the moment.


Understood! :) Anyhow, I'll figure something out with the headroom I have to work with!
 
After further review I'm realizing my clipping issues are not related to limitations of 16 bits (at least partially not).

I'm noticing the the AudioInputUSB object behaves differently when in I2S mode than when in TDM mode. The USB object is TDM compatible right?

PassThroughUSB_I2S.ino

Code:
#include "control_PCM5242.h"
#include "control_tlv320adc6140.h"
#include "control_i2c_menu.h"
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>



// GUItool: begin automatically generated code
AudioInputUSB            usb1;           //xy=309,334
AudioOutputI2S           i2s1;           //xy=621,293
AudioAnalyzePeak         peak1;          //xy=737,380
AudioConnection          patchCord1(usb1, 0, i2s1, 0);
AudioConnection          patchCord2(usb1, 0, peak1, 0);
AudioConnection          patchCord3(usb1, 1, i2s1, 1);
// GUItool: end automatically generated code



// declare the AudioOutput PCM5242. 
AudioControltlv320adc6140    AudioInput;
AudioControlpcm5242         AudioOutput;
i2c_menu         i2c_menu1;

void setup() {  
    Wire.begin();
  delay(50); // wait for steady I2C line    
  // enable the PCM5242
   AudioOutput.enablePCM5242 (B, I2S); // Set Device B to I2S mode
  float vol = .8;
  AudioOutput.volumePCM5242(B,.5); // Set Device B to volume of 50%
  //AudioOutput.dspProgramPCM5242(B);
  //AudioOutput.analogGainPCM5242(B);

             
   AudioMemory(100);
//  sgtl5000_1.enable();
//  sgtl5000_1.volume(0.6);
}

void loop() {
  // read the PC's volume setting
 float vol = usb1.volume();

   // scale to a nice range (not too loud)
  // and adjust the audio shield output volume
  if (vol > 0) {
    // scale 0 = 1.0 range to:
    //  0.3 = almost silent
    //  0.8 = really loud
    vol = 0.3 + vol * 0.5;
  }
  
  // use the scaled volume setting.  Delete this for fixed volume.
  AudioOutput.volumePCM5242(B,vol);
  // Print the volume. 
  Serial.print(vol);
  Serial.println();

  // find the peak and print it to serial. 
  int monoPeak = peak1.read() *10;
  Serial.print(monoPeak);
  Serial.println();
  
  delay(100);
  
// i2c_menu1.menu();
}

// Teensyduino 1.35 & earlier had a problem with USB audio on Macintosh
// computers.  For more info and a workaround:
// https://forum.pjrc.com/threads/34855-Distorted-audio-when-using-USB-input-on-Teensy-3-1?p=110392&viewfull=1#post110392

The volume sounds great in this above I2S mode. We get a peak reading of somewhere around 7, but it doesn't clip.

But when I run in TDM mode the USB object is sending a louder signal for some reason, which results in clipping/distortion. I can pull the volume back on the audio playing from the computer through the USB (turn down the volume on spotify, not the digital volume of the DAC).

PassThroughUSB_TDM.ino

Code:
#include "control_PCM5242.h"
#include "control_tlv320adc6140.h"
#include "control_i2c_menu.h"
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>



// GUItool: begin automatically generated code
AudioInputUSB            usb1;           //xy=193,420
AudioInputTDM            tdm2;           //xy=218,697
AudioAmplifier           amp1;           //xy=320,348
AudioMixer4              mixer1;         //xy=442,540
AudioAnalyzePeak         peak1;          //xy=542,661
AudioOutputTDM           tdm1;           //xy=654,521
AudioAnalyzePeak         peak2;          //xy=1013,532
AudioConnection          patchCord1(usb1, 0, mixer1, 0);
AudioConnection          patchCord2(usb1, 0, peak1, 0);
AudioConnection          patchCord3(usb1, 1, mixer1, 1);
//AudioConnection          patchCord4(tdm2, 0, mixer1, 2);
//AudioConnection          patchCord5(tdm2, 2, mixer1, 3);
AudioConnection          patchCord6(mixer1, 0, tdm1, 0);
AudioConnection          patchCord7(mixer1, 0, tdm1, 1);
AudioConnection          patchCord8(mixer1, peak2);
// GUItool: end automatically generated code

// declare the AudioOutput PCM5242. 
AudioControltlv320adc6140    AudioInput;
AudioControlpcm5242         AudioOutput;
i2c_menu         i2c_menu1;

void setup() {  
    Wire.begin();
  delay(50); // wait for steady I2C line    
  // enable the PCM5242
  float vol = .5; // A low starting volume
  // enable the PCM5242
  AudioOutput.enablePCM5242 (B, TDM); // 
  AudioOutput.volumePCM5242(B,vol);
  //AudioOutput.dspProgramPCM5242(B);
  //AudioOutput.analogGainPCM5242(B);
  

             
   AudioMemory(100);
//  sgtl5000_1.enable();
//  sgtl5000_1.volume(0.6);
}

void loop() {
  // read the PC's volume setting
 float vol = usb1.volume();

    // scale to a nice range (not too loud)
  // and adjust the audio shield output volume
  if (vol > 0) {
    // scale 0 = 1.0 range to:
    //  0.3 = almost silent
    //  0.8 = really loud
    vol = 0.3 + vol * 0.5;
  }
  
  // use the scaled volume setting.  Delete this for fixed volume.
  AudioOutput.volumePCM5242(B,vol);
  // Print the volume. 
  Serial.print(vol);
  Serial.println();

  // find the peak and print it to serial. 
  int monoPeak = peak1.read() *10;
  Serial.print(monoPeak);
  Serial.println();
  
  delay(100);

  
// i2c_menu1.menu();
}

// Teensyduino 1.35 & earlier had a problem with USB audio on Macintosh
// computers.  For more info and a workaround:
// https://forum.pjrc.com/threads/34855-Distorted-audio-when-using-USB-input-on-Teensy-3-1?p=110392&viewfull=1#post110392


It seems that the USBInputObject is just too loud when in TDM mode. Turning it down helps to make it reasonable to listen to, but it still is clipping even at lower levels, it hurts your ears. The I2S mode is clean and clear. I think this is ultimately negatively impacting my ADC mixers because the USB is screaming and creating bad sound in itself...

Here is the initialization code:

Code:
bool AudioControlpcm5242::enablePCM5242(device dev, AudioMode mode)
{
  // wake up device
  switch (mode)
  {
    
    case I2S:
        writeRegister(dev, Page_00, 0x02, 0b00010000);  // Standby Mode | 0b00010000 | 0x10
                delay(5);   
        writeRegister(dev, Page_00, 0x01, 0b00010000);  // Reset Module | 0b00010001 | 0x11
        writeRegister(dev, Page_00, REG_I2S_CONFIGURATION_1,  0b00000000);   //Page 00 Register 40 | 0b00000000 | 0x00 | I2S/16-BIT  
        writeRegister(dev, Page_00, 0x02, 0b00000000);  // Standby Mode Off | 0b00000000 | 0x00

      break;
    case TDM:

        writeRegister(dev, Page_00, REG_STANDBY_POWERDOWN_REQ, 0x10);      // Standby Mode On
        delay(5);                                                         // wait for device to initialize
        writeRegister(dev, Page_00, 0x01, 0b00010001);  // Reset Module | 0b00010001 | 0x11
        writeRegister(dev, Page_00, REG_I2S_CONFIGURATION_1,  0b00010000);   //Page 00 Register 40 | 0b00010000 | 0x10 | I2S/16-BIT    
        writeRegister(dev, Page_00, REG_I2S_CONFIGURATION_2,  0x04);      // Page 00 Register 41 | I2S SHIFT: 4 BITS
        writeRegister(dev, Page_00, REG_STANDBY_POWERDOWN_REQ, 0x00);     // Standby Mode Off
      break;
  }
  return true;
}


I know you don't know my particular hardware, but to just describe what is happening here. When in I2S mode the PCM5242 initializes automatically. So we just need to "reset module" and "reset registers" and it works out of the box. When in TDM mode, I'm changing the I2S configuration to TDM mode with 16 bits, and then I have to shift the I2S 4 bits to the right... This part is weird, but if I don't do it the sound is super distorted. By shifting it over it sounds OK, but the USB audio is super loud. Does that sound right? Why do I need to shift 4 bits?

Page 0 / Register 41
I2S Shift
These bits control the offset of audio data in the audio frame for both input and output. The offset is defined as
the number of BCK from the starting (MSB) of audio frame to the starting of the desired audio sample.
Default value: 00000000
00000000: offset = 0 BCK (no offset)
00000001: ofsset = 1 BCK
00000010: offset = 2 BCKs
. . .
11111111: offset = 256 BCKs

Here is a video of the demo. WARNING: TURN YOUR SPEAKERS DOWN.
https://photos.app.goo.gl/Ueqs2J2usXfEHH8Y9

Any ideas what I could be doing wrong with USB Audio in TDM mode?
 
*ignore differences with // GUItool: begin automatically generated code... That was a typo on the previous post. The following is the GUItool code I'm using for TDM.

Code:
// GUItool: begin automatically generated code
AudioInputUSB            usb1;           //xy=309,334
AudioAnalyzePeak         peak1;          //xy=737,380
AudioOutputTDM           tdm1;           //xy=862,249
AudioConnection          patchCord1(usb1, 0, peak1, 0);
AudioConnection          patchCord2(usb1, 0, tdm1, 0);
AudioConnection          patchCord3(usb1, 1, tdm1, 1);
// GUItool: end automatically generated code

Also, it's worth mentioning that the peak1 doesn't seem to be much different for I2S or TDM modes. There is something else I'm missing (obviously).
 
Hello,

I've done a lot more work over the past few days on the drivers. I have an example for PassthroughUSB_I2S, PassthroughUSB_TDM, PassthroughADC_I2S, PassthroughADC_TDM. There are some very strange things that I notice between the I2S and TDM examples.

1. Left and Right are reversed between TDM and I2S. When I toggle between TDM and I2S the input channels reverse. I assume on the DAC side...

2. When in I2S mode the passthrough goes just fine. The inputs or USB can be turned all the way up, no clipping. When in TDM mode the passthrough is plagued with clipping. The inputs or the USB must be turned down in order to avoid the clipping. I can turn down the levels of the input (ADC) or USB and you can hear decent quality sound with the TDM, but it's overall quieter because the inputs are attenuated.

3. The PCM5242 must be shifted +4 bits from 0 in TDM mode. So each stereo pair is located at the following.
// device 1 shift 4 | device 2 shift 20 | device 3 shift 36 | device 4 shift 52

4. I wonder if #3 is causing #2, maybe? Maybe the PCM5242 isn't configured correctly, but it's the only way I can get sound to play. It's almost like maybe I'm shifting 4 bits and loosing those 4 bits off the other end... Maybe I need to study the polarity of the BCLK to see if the polarity is correct. Maybe it's off 4 bits because maybe the polarity is reversed. Hmm.

Edit: I tried reversing the BCLK polarity, didn't work. Removed the shift, didn't work. Reset the BCLK polarity to normal.


I shall keep learning! Any pointers would be very much appreciated! Has anyone ever tried to toggle between I2S and TDM modes before? Does the CS42448 work in I2S (2 channel) mode? I'd be curious to see if other hardware will produce the same results (reversing channels 0/1, and responding to signals differently, as described above).

Jay
 
I got it.

TDM for PCM5242 has an offset of 1... As described in Figure 22. TDM/DSP 2 Audio Data Format of the PCM5242 datasheet.

// 16 Bit Mode: device 1 shift 1 | device 2 shift 33 | device 3 shift 65 | device 4 shift 97

This is the clock/data format that is working - no more clipping issues.

PCM5242_TDM_DSP2_AUDIO_DATA_FORMAT.png

Awesome! Next step is to finish up the driver and then I want to see how many DAC/ADC units I can get operational at the same time (without clock issues). I will report back!
 
great work! keep us updated : ) I am really keen to be able to run more than stereo audio track into a Teensy via the usb.
A.
 
Status
Not open for further replies.
Back
Top