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

Thread: 4 Channel TDM (I2S) Teensy 3.6 with Invensense ics 52000

  1. #1
    Junior Member
    Join Date
    Aug 2018
    Posts
    3

    4 Channel TDM (I2S) Teensy 3.6 with Invensense ics 52000

    Firstly apologies if in wrong part of forum, please move/advise if wrong. My first post so be gentle.

    I am working on an audio recording project looking at using the Invensense ics52000 (https://www.invensense.com/products/ics-52000/), I have bought the larger development board(to allow expansion later in project) (https://www.digikey.com/en/product-h...ray-demo-board).
    (the array board has jumper selection to allow 4,8,12,16 mics on the line, currently using only 4)

    I have followed the previous threads on here using the 4 microphone array board from notwired, and have successfully recorded sound with one microphone to sd card using the recorder example and Dreggory's final code post on another thread.(https://forum.pjrc.com/threads/48563...TDM-evaluation)

    However, my project is hoping to use 4x microphones sharing the TDM bus with potential to use 8 microphones.

    From what I've learnt from the previous code and playing with the GUI designer is that I can attach queues to the TDM input device and then read them sequentially using available() and then read() functions. I have tried expanding Dreggory's code by adding 8x queues and then writing them to Sd in the same style, but when I import these files into Matlab/Audacity the files are much shorter (4sec instead of 11sec) and often missing data. (testing by playing pure 300Hz sine wave from speaker closer to mic array)

    Sorry for the long post, I just wanted to show that I'm working through it before asking for help, so a few questions:
    -One microphone records at 44.1kHz, does this mean 4 at at 44.1k or is the frequency divided by 4?
    -Is the teensy 3.6 capable of this speeds with writing to the SD card for long period of time (end product is looking at ~10min recording time)
    - Is it possible to use the audio library for this task or will I have to 'roll my own'?

    Thanks in advance

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,498
    Quote Originally Posted by amperwest1 View Post
    -One microphone records at 44.1kHz, does this mean 4 at at 44.1k or is the frequency divided by 4?
    No. They're all at 44.1 kHz.


    -Is the teensy 3.6 capable of this speeds with writing to the SD card for long period of time (end product is looking at ~10min recording time)
    Maybe with SdFat. And with it's more complex way of writing larger blocks. And perhaps with pre-allocating the file and using the command to make sure the flash is erased. Maybe?

    But definitely not with the normal SD library.

  3. #3
    Junior Member
    Join Date
    Aug 2018
    Posts
    3
    Thanks for the quick reply.

    I shall look into the SdFat library, currently using a very cheap microSD (free with an rc toy) as my other ones are all 64gb+. I have a new one arriving hopefully tomorrow, hopefully i can inch some more speed with that.

    Is there a way to reduce the sample rate from 44.1k to 10k as the frequencies I'm concerned with are <1k, I have seen some previous posts on 'setI2Sfreq' but many are from a few years ago and I'm wondering if such a function has been implemented yet?

    Thanks again

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,498
    Quote Originally Posted by amperwest1 View Post
    Is there a way to reduce the sample rate from 44.1k to 10k as the frequencies I'm concerned with are <1k,
    Yes, there is a way, but it will require editing of the TDM configuration code in the library. If you slow down MCLK, everything else should follow. Just be sure you do *not* use any other input or output objects (like DAC, ADC, etc) which depend on the entire library running at the same speed.

  5. #5
    Junior Member
    Join Date
    Aug 2018
    Posts
    3
    Thanks for help.
    Just as a summary of what I have done, just in case anyone else is looking at using these libraries for non-pure audio recording.
    The following allowed simultaneous recording at 10kHz per channel for 4 channels.

    Adjusted the MCLK to 10kHz:
    By changing defines for the MCLK fraction and divider in output_tdm.cpp (line 141 onward)
    Teensy libs here (Win 10):C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Audio
    Looking at the datasheet (https://www.pjrc.com/teensy/K66P144M180SF5RMV2.pdf) page:2138 I worked out what the different divider values were doing.
    For TDM it needs a clock for 16 words (16*32=512), so for any sample rate (Fs) you must divide the system clock (Fcpu) down and then divide by 512 to get Fs.

    Formula for calculating this: (Fs*512)/Fcpu=(Fract/Divider)
    eg. (10000*512)/240,000,000=(8/375)
    edited code:
    Code:
    #if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
      // PLL is at 96 MHz in these modes
      #define MCLK_MULT 4
      #define MCLK_DIV  17
    #elif F_CPU == 72000000
      #define MCLK_MULT 16
      #define MCLK_DIV  51
    #elif F_CPU == 120000000
      #define MCLK_MULT 16
      #define MCLK_DIV  85
    #elif F_CPU == 144000000
      #define MCLK_MULT 8
      #define MCLK_DIV  51
    #elif F_CPU == 168000000
      #define MCLK_MULT 16
      #define MCLK_DIV  119
    #elif F_CPU == 180000000
      #define MCLK_MULT 32
      #define MCLK_DIV  255
      #define MCLK_SRC  0
    #elif F_CPU == 192000000
      #define MCLK_MULT 2
      #define MCLK_DIV  17
    #elif F_CPU == 216000000
      #define MCLK_MULT 16
      #define MCLK_DIV  153
      #define MCLK_SRC  0
    #elif F_CPU == 240000000
     //#define MCLK_MULT 8			//original for 44.1kHz
     //#define MCLK_DIV  85
      #define MCLK_MULT 8			//edit for 10kHz sample
      #define MCLK_DIV  375
    //#define MCLK_MULT 32			//edit for 8kHz sample
    //#define MCLK_DIV  1875
    //#define MCLK_MULT 4			//edit for 5kHz sample
    //#define MCLK_DIV  375
    #else
      #error "This CPU Clock Speed is not supported by the Audio library";
    #endif
    Then using Dreggory's code as a template I edited it for use with 4 microphones, here:
    Code:
    // Record TDM input sound as raw data (16ch, Signed 24-bit little-endian PCM, 44.1kHz, little-endian) to a SD card.
    // Note: Format is modified so that mics align their 24 bit data to 32 bit slots, half of the 16 bit
    // channels end up being the 8 low bits, and 8 more zeros which are discarded.
    //
    // Hardware:
    //   Mic Pin 6  (SD_O)  to Teensy Pin  13 SDATA  (Input, 11.3 Mbit/sec)
    //   Mic Pin 8  (SCK_I) to Teensy Pin  9 SCK     (Output, 11.3 MHz, Checked)
    //   Mic Pin 10 (WS_I)  to Teensy Pin  23 FS     (Output, 44100 Hz, Checked)
    //
    //   Mic GND Pins (1, 3, 5, 7 and 9) to Teensy GND
    //   Mic VDD to Teensy 3.3V
    
    //   At startup of the ICS-52000, the start of the frame sync (WS_I) signal should be delayed from the start of the serial clock (SCK_I) by at
    //   least 10 ms. This enables the microphone’s internal circuits to completely initialize before starting the synchronization sequence
    //   with other microphones in the TDM array. This delay can be implemented either by enabling the WS output (FS) on the clock master at
    //   least 10 ms after the SCK_I is enabled, or by externally controlling the signals given to the ICS-52000s.
    //
    //
    // This example code is in the public domain.
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputTDM            tdm1;           //xy=151,223
    AudioRecordQueue         queue4;         //xy=416,221
    AudioRecordQueue         queue5;         //xy=416,254
    AudioRecordQueue         queue6;         //xy=416,287
    AudioRecordQueue         queue7;         //xy=416,320
    AudioRecordQueue         queue3;         //xy=417,187
    AudioRecordQueue         queue8;         //xy=417,353
    AudioRecordQueue         queue2;         //xy=418,154
    AudioRecordQueue         queue1;         //xy=419,120
    AudioConnection          patchCord1(tdm1, 0, queue1, 0);
    AudioConnection          patchCord2(tdm1, 1, queue2, 0);
    AudioConnection          patchCord3(tdm1, 2, queue3, 0);
    AudioConnection          patchCord4(tdm1, 3, queue4, 0);
    AudioConnection          patchCord5(tdm1, 4, queue5, 0);
    AudioConnection          patchCord6(tdm1, 5, queue6, 0);
    AudioConnection          patchCord7(tdm1, 6, queue7, 0);
    AudioConnection          patchCord8(tdm1, 7, queue8, 0);
    // GUItool: end automatically generated code
    
    // GUItool: end automatically generated code
    
    // Use these with the Teensy Audio Shield
    //#define SDCARD_CS_PIN    10
    //#define SDCARD_MOSI_PIN  7
    //#define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    #define SDCARD_CS_PIN    BUILTIN_SDCARD
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors
    //#define SDCARD_CS_PIN    4
    //#define SDCARD_MOSI_PIN  11
    //#define SDCARD_SCK_PIN   13
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording
    int choice = 0;
    int sample_number = 0;
    
    unsigned int tsamplemillis = 10000;
    
    String typeofsound;
    
    int16_t* buffer1;
    int16_t* buffer2;
    int16_t* buffer3;
    int16_t* buffer4;
    int16_t* buffer5;
    int16_t* buffer6;
    int16_t* buffer7;
    int16_t* buffer8;
    
    // The file where data is recorded
    File frec;
    
    void setup() {
    
      Serial.begin(115200);
      // Audio connections require memory, and the record queue
      // uses this memory to buffer incoming audio.
      AudioMemory(512);
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      while (!Serial);
      Serial.println("Welcome to the 4-channel TDM recording test bench");
    }
    
    void loop() {
    
      if (choice == 0) {
        Serial.println("\nEnter new filename for sound archive: ");
        while (!Serial.available());
        typeofsound = Serial.readString();
        sample_number = 0;
        record(typeofsound, sample_number);
      } else if (choice == 1) {
        sample_number++;
        record(typeofsound, sample_number);
      } else {
        //Do nothing
      }
    
      Serial.print("\nEnter 1 to take another sample in this archive or 0 to enter a new file archive: ");
      while (!Serial.available());
      choice = Serial.readString().toInt();
      Serial.println(choice);
    }
    
    void record(String type, int number)
    {
      Serial.println("Recording " + type + String(number) + "...");
      String sname = type + number + ".RAW";
      String path = type + "/" + type + number + ".RAW";
      startRecording(sname, path, type);
      continueRecording();
      stopRecording();
    }
    
    void startRecording(String sname, String path, String type)
    {
      int str_len = path.length() + 1;
      char charpath[str_len];
      path.toCharArray(charpath, str_len);
    
      if (SD.exists(charpath)) {
        // The SD library writes new data to the end of the
        // file, so to start a new recording, the old file
        // must be deleted before new data is written.
        SD.remove(charpath);
      }
    
      str_len = type.length() + 1;
      char chartype[str_len];
      type.toCharArray(chartype, str_len);
    
      if (!SD.exists(chartype)) {
        SD.mkdir(chartype);
      }
    
      frec = SD.open(charpath, FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
      }
    }
    
    void continueRecording() {
      int data = 0, num = 0;
      elapsedMillis recordingTime = 0;
      queue1.begin();
      queue2.begin();
      queue3.begin();
      queue4.begin();
      queue5.begin();
      queue6.begin();
      queue7.begin();
      queue8.begin();
      mode = 1;
      while (recordingTime < tsamplemillis)
      {
        data = queue1.available();
        if (data > 0)
        {
          buffer1 = queue1.readBuffer();      //read all queue buffers in sets of 128 16bit num
          buffer2 = queue2.readBuffer();
          buffer3 = queue3.readBuffer();
          buffer4 = queue4.readBuffer();
          buffer5 = queue5.readBuffer();
          buffer6 = queue6.readBuffer();
          buffer7 = queue7.readBuffer();
          buffer8 = queue8.readBuffer();
          queue1.freeBuffer();                //free queue buffers to allow system to re issue storage
          queue2.freeBuffer();
          queue3.freeBuffer();
          queue4.freeBuffer();
          queue5.freeBuffer();
          queue6.freeBuffer();
          queue7.freeBuffer();
          queue8.freeBuffer();
          if (data > 48)        //test if queue buffers are getting too full, the serial write will probably cause a back log if it does happen.
          {
            Serial.write('.');    //dots in the serial monitor mean that the system isnt processing data fast enough
          }
          for (int i = 0; i < 128; i ++)                        //write data to sd card in 24bit signed pcm format (i think) (audacity seems to accept it)
          { //frames are built of 2 16 bit numbers where only 24 bits are useful, so only 3 bytes are saved to save space. Frames are little endian
            frec.write(highByte(buffer2[i])); // LSB            //<---------------------sample 1---------------------><---------------------sample n--------------------->
            frec.write(lowByte(buffer1[i])); // Middle Byte     //<----ch1----><----ch2----><----ch3----><----ch4----><----ch1----><----ch2----><----ch3----><----ch4---->
            frec.write(highByte(buffer1[i])); // MSB            //<LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB><LSB-MID-MSB>
            frec.write(highByte(buffer4[i])); // LSB
            frec.write(lowByte(buffer3[i])); // Middle Byte
            frec.write(highByte(buffer3[i])); // MSB
            frec.write(highByte(buffer6[i])); // LSB
            frec.write(lowByte(buffer5[i])); // Middle Byte
            frec.write(highByte(buffer5[i])); // MSB
            frec.write(highByte(buffer8[i])); // LSB
            frec.write(lowByte(buffer7[i])); // Middle Byte
            frec.write(highByte(buffer7[i])); // MSB
            num++;
          }
        }
      }
      queue1.end();     //stop the background sampling
      queue2.end();
      queue3.end();
      queue4.end();
      queue5.end();
      queue6.end();
      queue7.end();
      queue8.end();
      Serial.print("num of samples written per channel:");
      Serial.println(num);
    }
    
    
    void stopRecording() {
      Serial.println("Finished recording.");
      queue1.end();
      queue2.end();
      queue3.end();
      queue4.end();
      queue5.end();
      queue6.end();
      queue7.end();
      queue8.end();
      queue1.clear();
      queue2.clear();
      queue3.clear();
      queue4.clear();
      queue5.clear();
      queue6.clear();
      queue7.clear();;
      queue8.clear();
      frec.close();
      mode = 0;
    }
    And recorded 99968 4-channel samples in 10 seconds (i can cope with being 32 off for now)

    The result when imported into audacity using 24bit signed pcm, 4 channel, Fs=10000. The result of a recorded 300Hz sine wave looked like this:
    Click image for larger version. 

Name:	Capture.jpg 
Views:	6 
Size:	117.5 KB 
ID:	14406
    (amplitudes are very small, due to having to play sound with pc speakers quietly as its late)

    Apologies if any of the things stated aren't true, attempting to self teach myself in the early hours. Feel free to correct me or suggest improvements.

    After only having the Teensy for 2 days now, I am already very impressed. Thanks for a great product and the forum!

Tags for this Thread

Posting Permissions

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