Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: 2x PCM1808 ADCs recording LR ch. each (I2S quad input?) on T4 and also 1 DAC UDA1334

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Posts
    7

    2x PCM1808 ADCs recording LR ch. each (I2S quad input?) on T4 and also 1 DAC UDA1334

    Context:
    So for my college senior year design project I chose to make noise cancelling headphones(I bought off the shelf active noise cancelling headphones with hybrid system so 4 mics - 2 each side - 1 feed-forward outside the ear-cup and 1 feedback in side the ear-cup). I kept the mics in place but discarded the circuitry as I want to build my own. Initially went with pure analog design but didn't like the results.

    Now, after some simulations between two STM32f103c blue-pill boards, one as mic emulator(noisy audio producer) and the other as a DSP emulator (matching delay, phase, and amplitude of Feed Forward Mic with the Feed Back Mic) and using some basic algorithms of a weight-mask convoluting with the Feed Forward data buffer in 'real time' to match the feedback buffer(in simulation I delayed the feedback from feed forward by 6 samples and amplitude *=0.42); Updating the weights each iteration trying to make the error zero.

    The Meat:
    Using the T4 as DSP.
    I want to use 2x PCM1808s @48KHz and 24bits to record 4 channels - 2 per ADC (each ADC is recording 1 FF mic and 1 FB mic). Then do some basic processing on the captured samples and then replay 2 channel output @24bit 48KHz through the UDA1334A DAC by adafruit.
    All of this preferably using the built in I2S HW.
    I don't think the audio library is going to support this. All I need is some example showing me how to use the IS2 pins for input, setting the bits and ksps, working with the samples. Actually anything you guys think might be helpful is most appreciated.
    Thanks!!
    Let me know if I am not being clear enough or anything else! First time posting in any forums.

  2. #2
    Junior Member
    Join Date
    Nov 2019
    Posts
    7
    Would something like this work.. Maybe not the i2s1 output but how about having the quad channel (2 ADCs with Left and Right channels each)??

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputI2SQuad        i2s_quad1;      //xy=173,257
    AudioRecordQueue         queueLeftFeedForward;         //xy=324,135
    AudioRecordQueue         queueRightFeedForward;         //xy=359,417
    AudioRecordQueue         queueLeftFeedBack;         //xy=370,180
    AudioRecordQueue         queueRightFeedBack;         //xy=374,478
    AudioOutputI2S           i2s1;           //xy=613,264
    AudioConnection          patchCord1(i2s_quad1, 0, queueLeftFeedForward, 0);
    AudioConnection          patchCord2(i2s_quad1, 1, queueLeftFeedBack, 0);
    AudioConnection          patchCord3(i2s_quad1, 2, queueRightFeedForward, 0);
    AudioConnection          patchCord4(i2s_quad1, 3, queueRightFeedBack, 0);
    // GUItool: end automatically generated code
    like this:
    Click image for larger version. 

Name:	pjrcpost1.png 
Views:	9 
Size:	250.8 KB 
ID:	18246

    also I believe the quadi2s pinouts would have to change for the T4:
    Click image for larger version. 

Name:	pjrcquad pinout post2.png 
Views:	1 
Size:	60.6 KB 
ID:	18247

  3. #3
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,368
    I've not used the quad channel stuff. Note, you would have to change the I2S pins from the Teensy 3.x pinout to the Teensy 4.0 pinout. I.e.
    • Instead of pin 9 for BCLK use pin 21/A7;
    • Instead of pin 11 for MCLK use pin 23/A9;
    • Instead of pin 13 for RX use pin 8;
    • Instead of pin 22/A8 for TX use pin 7;
    • Instead of pin 23/A9 for LRCLK use pin 20/A6.


    Note, you will need to do a deep dive into the imxrt 1062 datasheet, but the first I2S channel actually has 5 pins that can be used for inputs and outputs. Paul has labeled them:
    • Pin 6 is OUT1D;
    • Pin 7 is OUT1A;
    • Pin 8 is IN1;
    • Pin 9 is OUT1C;
    • Pin 32 on a solder pad under the Teensy is OUT1B.


    The datasheets for all of the PJRC products are in:


    In the I.MX RT1060 Processor reference, I2S documentation is in section 37.2 which starts on page 2071 and goes through page 2112. While the i.MXrt 1062 has 3 I2S interfaces, evidently only two are brought out to the available pins.

    In addition, the Teensy has a second I2S system:
    • Pin 2 is OUT2;
    • Pin 3 is LRCLK2;
    • Pin 4 is BCLK2;
    • Pin 5 is IN2;
    • Pin 33 on a solder pad under the Teensy is MCLK2.


    That means in theory you could have up to 7 pairs of L/R channels.

    So rather than using the quad channel stuff for the Teensy 3.x, you could use I2S1 and I2S2. Note, the audio tool has not yet caught up with the new features of the Teensy 4, but if you add I2S1 with the tool and change the I2S1 in the code to I2S2 it should work.

    Obviously as you discover useful stuff, please post it.

    Here is a real simple example using tone sweep on I2S2 for output. I was using an I2S board that didn't need MCLK2 connected. But if you need MCLK2 there are various ways to get access to the solder pads under the Teensy (look for the threads discussing breakout boards in the General Discussion sub-forum):

    Code:
    /*
      Demo of the audio sweep function.
      The user specifies the amplitude,
      start and end frequencies (which can sweep up or down)
      and the length of time of the sweep.
    
      Modified to eliminate the audio shield, and use the second I2S output on the
      Teensy 4.0.
    
      You can use the Max98357A mono I2S chip.
      https://smile.amazon.com/gp/product/B07PS653CD/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
    
      Pins:		Teensy 4.0
    
      LRCLK:	Pin 3
      BCLK:		Pin 4
      DIN:		Pin 2
      Gain:		see below
      Shutdown:	N/C
      Ground:	Ground
      VIN:		5v
    
      Other I2S2 pins not used by the Max98357A device:
    
      MCLK		Pin 33
      VOUT		Pin 6
    
      Gain setting:
    
      15dB	if a 100K resistor is connected between GAIN and GND
      12dB	if GAIN is connected directly to GND
       9dB	if GAIN is not connected to anything (this is the default)
       6dB	if GAIN is conneted directly to Vin
       3dB	if a 100K resistor is connected between GAIN and Vin.
    
      SD setting (documentation from the Adafruit board)
    
      This pin is used for shutdown mode but is also used for setting which channel
      is output. It's a little confusing but essentially:
    
      * If SD is connected to ground directly (voltage is under 0.16V) then the amp
        is shut down
    
      * If the voltage on SD is between 0.16V and 0.77V then the output is (Left +
        Right)/2, that is the stereo average.
    
      * If the voltage on SD is between 0.77V and 1.4V then the output is just the
        Right channel
    
      * If the voltage on SD is higher than 1.4V then the output is the Left
        channel.
    
        This is compounded by an internal 100K pulldown resistor on SD so you need
        to use a pullup resistor on SD to balance out the 100K internal pulldown.
    
      Or alternatively, use the HiLetgo PCM5102 I2S IIS Lossless Digital Audio DAC
      Decoder which provides stereo output:
      https://smile.amazon.com/gp/product/B07Q9K5MT8/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
      */
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioSynthToneSweep	tonesweep;		//xy=99,198
    AudioMixer4		mixer2;			//xy=280,253
    AudioMixer4		mixer1;			//xy=280,175
    AudioOutputI2S2		i2s2;			//xy=452,189
    
    AudioConnection		patchCord1(tonesweep, 0, mixer1, 0);
    AudioConnection		patchCord2(tonesweep, 0, mixer2, 0);
    AudioConnection		patchCord3(mixer2, 0, i2s2, 1);
    AudioConnection		patchCord4(mixer1, 0, i2s2, 0);
    // GUItool: end automatically generated code
    
    const float	t_ampx	= 0.8;
    const int	t_lox	= 10;
    const int	t_hix	= 22000;
    const float	t_timex	= 10;		// Length of time for the sweep in seconds
    
    // Do a sweep in both directions, enabling or disabling the left/right speakers
    void do_sweep (int i)
    {
      int do_left  = (i & 1) != 0;
      int do_right = (i & 2) != 0;
      float gain   = (do_left && do_right) ? 0.5f : 1.0f;
    
      Serial.printf ("Sweep up,   left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      mixer1.gain (0, do_left  ? gain : 0.0f);
      mixer2.gain (0, do_right ? gain : 0.0f);
    
      if (!tonesweep.play (t_ampx, t_lox, t_hix, t_timex)) {
        Serial.println ("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep.isPlaying ())
        ;
    
      // and now reverse the sweep
      Serial.printf ("Sweep down, left = %c, right = %c\n",
    		 (do_left)  ? 'Y' : 'N',
    		 (do_right) ? 'Y' : 'N');
    
      if (!tonesweep.play (t_ampx, t_hix, t_lox, t_timex)) {
        Serial.println("ToneSweep - play failed");
        while (1)
          ;
      }
    
      // wait for the sweep to end
      while (tonesweep.isPlaying ())
        ;
    
      Serial.println ("Sweep done");
    }
    
    void setup(void)
    {
      // Wait for at least 3 seconds for the USB serial connection
      Serial.begin (9600);
      while (!Serial && millis () < 3000)
        ;
    
      AudioMemory (8);
      Serial.println ("setup done");
    
      for (int i = 1; i <= 3; i++)
        do_sweep (i);
    
      Serial.println ("Done");
    }
    
    void loop (void)
    {
    }
    Last edited by MichaelMeissner; 11-23-2019 at 04:20 PM.

  4. #4
    Junior Member
    Join Date
    Nov 2019
    Posts
    7
    Thanks so much! I'll update as I progress. I am thinking of using the I2S1 and I2S2 audioinput instances with an external 12.288MHz clock for a common MCLK... so I think the ADCs will be in Master Mode, I dont know how well the T4 handles async sampling (dropped frames and stuff?!) Now I just need to figure out ways of controlling the resolution and sample rate to 24bits@48KHz but I read somewhere that working with anything over 16bits is a whole different story, the T4 processes in 16bit chunks and it will get very slow. Lets see how it goes. Thanks again.

  5. #5
    Junior Member
    Join Date
    Nov 2019
    Posts
    7
    So I'm having a couple of thoughts...

    Here I am testing instances of AudioInputI2S and AudioInputI2S2 for capturing samples in a queue and printing them(mostly copy code from recording example). But this is all gonna take place at 16bit @44.1KHz while I want 24bit@48KHz So...
    Code:
    #include <Audio.h>
    
    AudioInputI2S             i2s1;
    AudioInputI2S2            i2s2;
    AudioRecordQueue          queue1;
    AudioRecordQueue          queue2;
    AudioConnection           patchCord1(i2s1, 0, queue1, 0);
    AudioConnection           patchCord2(i2s2, 0, queue2, 0);
    
    void setup() {
      Serial.begin(115200);
      AudioMemory(60);
      queue1.begin();
      queue2.begin();
    }
    
    void loop() {
      byte buffer1[512];
      byte buffer2[512];
    
      memcpy(buffer1, queue1.readBuffer(), 256);
      queue1.freeBuffer();
      memcpy(buffer1 + 256, queue1.readBuffer(), 256);
      queue1.freeBuffer();
      memcpy(buffer2, queue2.readBuffer(), 256);
      queue2.freeBuffer();
      memcpy(buffer2 + 256, queue2.readBuffer(), 256);
      queue2.freeBuffer();
      for (int i = 0; i < 512; i++)
      {
        Serial.println(buffer1[i]);
      }
      for (int i = 0; i < 512; i++)
      {
        Serial.println(buffer2[i]);
      }
    }
    I think what I might do is inside the "audio_block_struct" in AudioStream.h,
    Click image for larger version. 

Name:	audiostream.png 
Views:	5 
Size:	93.3 KB 
ID:	18260
    change the data[AUDIO_BLOCK_SAMPLES] data type from int16_t to int32_t and change the
    #define AUDIO_SAMPLE_RATE_EXACT 44100.0f
    to
    #define AUDIO_SAMPLE_RATE_EXACT 48000.0f

    I don't know how deep the implications of this might be.
    What do you folks think?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •