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

Thread: Queue Audio object and i2c issue

  1. #1
    Senior Member
    Join Date
    Oct 2016
    Posts
    206

    Queue Audio object and i2c issue

    Queue Audio object and i2c issue

    Hi, i have a stranger issue with the queue audio object and i2c components in my T4 and Audio Shield rev D project.

    When begin the queue while a i2c display (or multiplexer or anything) is working the audio stream is stopped and the queue object don't works.
    Looks like a freeze..

    In this sketch the freezing appears when I press the button and disappears when I release the button.

    If I stop the i2c stream (removing display line in loop) the queue object works fine.

    I can't understand what's happening.

    Code:
    #include <Bounce2.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <Adafruit_SSD1306.h>
    #include <Adafruit_GFX.h>
    
    AudioInputI2S            line_in;           //xy=156,246
    AudioAnalyzePeak         peak1;          //xy=590,456
    AudioRecordQueue         queue_left;         //xy=484,188
    AudioRecordQueue         queue_right;         //xy=498,241
    AudioOutputI2S           i2s2;           //xy=682,409
    AudioConnection          patchCord1(line_in, 0, queue_left, 0);
    AudioConnection          patchCord2(line_in, 1, queue_right, 0);
    AudioConnection          patchCord3(line_in, 0, peak1, 0);
    AudioConnection          patchCord4(line_in, 0, i2s2,0);
    AudioConnection          patchCord5(line_in, 0, i2s2, 1);
    AudioControlSGTL5000     sgtl5000_1;
    
    #define BOUNCE_LOCK_OUT
    Bounce button1 = Bounce(9, 5);
    
    #define OLED_RESET -1
    Adafruit_SSD1306 display(OLED_RESET);
    
    void setup() {
    
    button1.attach( 9, INPUT_PULLUP );
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    AudioMemory(60);
    sgtl5000_1.enable();
    
    }
    
    void loop() {
    display.clearDisplay();
    button1.update();
    if (button1.fell()) {queue_left.begin(); queue_right.begin();}
    if (button1.rose()) {queue_right.end(); queue_left.end();
                         queue_left.clear();queue_right.clear();}
    if (peak1.available()) {display.setCursor(35,25); display.setTextSize(2); display.setTextColor(WHITE); display.print(peak1.read());}
    display.display();
    }
    can you help me?

    Thank u

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    You aren't doing anything with the queued buffers when you press the button. You need to at least check if a buffer is available and, if so, read it (if you're going to process that data) and then free it.

    Clearing the display every time through the loop function takes up a lot of time. You should clear it once in setup and then arrange the data display so that you only overwrite the part(s) that need updating.

    Pete

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    At the very least, you need to free the buffers. Add this in the loop function:
    Code:
      if(queue_left.available() > 0) {
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.freeBuffer();
      }
    Pete

  4. #4
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    Quote Originally Posted by el_supremo View Post
    At the very least, you need to free the buffers. Add this in the loop function:
    Code:
      if(queue_left.available() > 0) {
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.freeBuffer();
      }
    Pete
    This code is only an example, my real project works fine for record and play BUT not if a i2c stream is active…
    It’s not a problem of buffer but something else..

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    I can't debug what I can't see, but at a guess I'd say you are doing the same kind of thing as in this example code. You aren't handling the display efficiently and ensuring that audio buffers are processed in a timely manner.

    Pete

  6. #6
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    The display is an example, I have the same issue with a multiplexer (instead of the display), like MCP23017.
    If a put a simply mcp.digitalRead(0) (for only one pin) the queue goest to freeze.

    I can add a lot of objects, functions, activities and all works fine but if I have a i2c stream I have a freeze when queue_left.begin().

    i can't understand why...

  7. #7
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    Quote Originally Posted by el_supremo View Post
    At the very least, you need to free the buffers. Add this in the loop function:
    Code:
      if(queue_left.available() > 0) {
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.freeBuffer();
      }
    Pete
    Added and I have the same issue

    Code:
    #include <Bounce2.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    AudioInputI2S            line_in;           //xy=156,246
    AudioAnalyzePeak         peak1;          //xy=590,456
    AudioRecordQueue         queue_left;         //xy=484,188
    AudioRecordQueue         queue_right;         //xy=498,241
    AudioOutputI2S           i2s2;           //xy=682,409
    AudioConnection          patchCord1(line_in, 0, queue_left, 0);
    AudioConnection          patchCord2(line_in, 1, queue_right, 0);
    AudioConnection          patchCord3(line_in, 0, peak1, 0);
    AudioConnection          patchCord4(line_in, 0, i2s2,0);
    AudioConnection          patchCord5(line_in, 0, i2s2, 1);
    AudioControlSGTL5000     sgtl5000_1;
    
    
    #include <Adafruit_SSD1306.h>
    #include <Adafruit_GFX.h>
    
    #define BOUNCE_LOCK_OUT
    Bounce button1 = Bounce(9, 5);
    
    #define OLED_RESET -1
    Adafruit_SSD1306 display(OLED_RESET);
    
    void setup() {
    
    button1.attach( 9, INPUT_PULLUP );
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    AudioMemory(60);
    sgtl5000_1.enable();
    
    
    }
    
    void loop() {
    
    // your suggestion
     if(queue_left.available() > 0) {
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.freeBuffer();
      }
    
    //----
    
    display.clearDisplay();
    button1.update();
    if (button1.fell()) {queue_left.begin(); queue_right.begin();}
    if (button1.rose()) {queue_right.end(); queue_left.end();
                         queue_left.clear();queue_right.clear();}
    if (peak1.available()) {display.setCursor(35,25); display.setTextSize(2); display.setTextColor(WHITE); display.print(peak1.read());}
    display.display();
    }

  8. #8
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    Try this:
    Code:
    #include <Bounce2.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    AudioInputI2S            line_in;           //xy=156,246
    AudioAnalyzePeak         peak1;          //xy=590,456
    AudioRecordQueue         queue_left;         //xy=484,188
    AudioRecordQueue         queue_right;         //xy=498,241
    AudioOutputI2S           i2s2;           //xy=682,409
    AudioConnection          patchCord1(line_in, 0, queue_left, 0);
    AudioConnection          patchCord2(line_in, 1, queue_right, 0);
    AudioConnection          patchCord3(line_in, 0, peak1, 0);
    AudioConnection          patchCord4(line_in, 0, i2s2,0);
    AudioConnection          patchCord5(line_in, 0, i2s2, 1);
    AudioControlSGTL5000     sgtl5000_1;
    
    
    #include <Adafruit_SSD1306.h>
    #include <Adafruit_GFX.h>
    
    #define BOUNCE_LOCK_OUT
    Bounce button1 = Bounce(9, 5);
    
    #define OLED_RESET -1
    Adafruit_SSD1306 display(OLED_RESET);
    
    void setup()
    {
    
      button1.attach( 9, INPUT_PULLUP );
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
      AudioMemory(60);
      sgtl5000_1.enable();
    
      display.clearDisplay();
      display.setTextSize(2);
      display.setTextColor(WHITE);
    }
    
    void loop()
    {
    // your suggestion
      while(queue_left.available() > 0) {
        queue_left.freeBuffer();
      }
      while(queue_right.available() > 0) {
        queue_right.freeBuffer();
      }
    
    //----
      button1.update();
      if (button1.fell()) {
        queue_left.begin();
        queue_right.begin();
      }
      if (button1.rose()) {
        queue_right.end(); queue_left.end();
        queue_left.clear(); queue_right.clear();
      }
      if (peak1.available()) {
        display.setCursor(35,25);
        char t_peak[16];
        sprintf("%5.3f",peak1.read);
        display.print(t_peak);
        display.display();
      }
    }
    I've changed the test for queue availability from "if" to "while" so that if there's more than one buffer available it will process them right away.
    I use sprintf to format the number the same way so that when it is displayed, it always takes up the same number of characters on the display. Then you don't need to keep erasing the whole screen - only the characters that have changed need to be rewritten.
    Also put the .display() inside the if statement - it doesn't need to be called if nothing has changed.



    Pete

  9. #9
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    Nothing... the same issue..

    The CPU is 0.12% ...is a T4, I don't think that is too busy, there is something wrong in the queue object about i2c, not what we do with queue data I think..

    Thanks Pete for your help, it's very appreciated!
    Is there anything else i can try?

  10. #10
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    If u want to try the sketch it works without a display connected, you need a button and audio in out...

  11. #11
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    This has nothing to do with I2C.
    AHA! When you enable the queue, not only must you free the buffer, but first you MUST read it even if you do nothing with the data.

    Try this in loop:
    Code:
      if(queue_left.available() > 0) {
        queue_left.readBuffer();
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.readBuffer();
        queue_right.freeBuffer();
      }
    and I should've at least compiled my code before posting it. Then I would have noticed that this sprintf will compile:
    Code:
        sprintf(t_peak,"%5.3f",peak1.read());
    Pete

  12. #12
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    Thanks Pete, now the button for queue works but only because your code don't update anything on display...

    using the readBuffer() it seems to work, I'll update you soon ..

    Thank u

  13. #13
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    With this code in loop all the data of queue are unusable so it's not a solution

    Code:
    if(queue_left.available() > 0) {
        queue_left.readBuffer();
        queue_left.freeBuffer();
      }
      if(queue_right.available() > 0) {
        queue_right.readBuffer();
        queue_right.freeBuffer();
      }
    This is what I do with the queue:

    Code:
    void startRecording(byte sel) {
      rec_target = sel;
      int16_t rec_count = 0;;
      address = (bankstart[rec_target] / 2) + foffset;
      queue_left.begin();
      queue_right.begin();
    
    }
    
    
    
    void continueRecording() {
      byte q1a = queue_left.available();
      byte q2a = queue_right.available();
    
      if (q1a == 1 && q2a == 1) {
    
        int16_t buffer_in_left[(getsize * 4) + 10];
        int16_t buffer_in_right[(getsize * 4) + 10];
        int16_t buffer_out[(getsize * 2) + 10];
    
        memcpy(buffer_in_left, queue_left.readBuffer(), getsize);
        memcpy(buffer_in_right, queue_right.readBuffer(), getsize);
    
        queue_left.freeBuffer();
        queue_right.freeBuffer();
        
        for (uint32_t i = 0; i < getsize; i ++) {
          uint16_t j = i * 2;
          buffer_out[j] = buffer_in_left[i];
          buffer_out[j + 1] = buffer_in_right[i];
        }
    
    
    void stopRecording() {
      samplelen[rec_target] = ((address) - ((bankstart[rec_target] / 2) + foffset)) / 2;
      save_sample_length(rec_target, samplelen[rec_target]);
      queue_right.end();
      queue_left.end();
    
      while (queue_left.available() > 0) {
        queue_left.freeBuffer();
        queue_left.clear();
        queue_right.freeBuffer();
        queue_right.clear();
      }
    I can't find something wrong, i'm using "read" and "free buffer" but when there is a i2c communication goes to feeze

  14. #14
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,811
    Code:
      if (q1a == 1 && q2a == 1) {
    It would be safer to do this:
    Code:
      if (q1a > 0 && q2a > 0) {
    What is the value of "getsize"? You have some inconsistent declarations involving getsize which don't make sense.

    Code:
        memcpy(buffer_in_left, queue_left.readBuffer(), getsize);
        memcpy(buffer_in_right, queue_right.readBuffer(), getsize);
    An audio buffer is 256 bytes (unless you've meddled with the audio library code) and so getsize should be 256 otherwise these copies will either not copy enough or will copy too much from the buffer.

    Code:
        int16_t buffer_in_left[(getsize * 4) + 10];
        int16_t buffer_in_right[(getsize * 4) + 10];
        int16_t buffer_out[(getsize * 2) + 10];
    This is where the inconsistency comes in. If getsize is the correct value (256) to copy the audio buffers, then these declarations will allocate much more than is required for the left and right buffers.

    I haven't used .end and .clear but I think this isn't quite right.
    Code:
      queue_right.end();
      queue_left.end();
    
      while (queue_left.available() > 0) {
        queue_left.freeBuffer();
        queue_left.clear();
        queue_right.freeBuffer();
        queue_right.clear();
      }
    The documentation of clear() implies that it empties the buffers so in stopRecording() you should only need:
    Code:
      queue_right.end();
      queue_left.end();
      queue_right.clear();
      queue_left.clear();
    But if you want to be sure the buffers are gone you can add this:
    Code:
      while (queue_left.available() > 0) {
        queue_left.readBuffer();
        queue_left.freeBuffer();
      }
      while (queue_right.available() > 0) {
        queue_right.readBuffer();
        queue_right.freeBuffer();
      }
    As far as the freezing is concerned, you must ensure that, while you are recording, you call continueRecording() at least every 2.9 milliseconds to ensure that the buffers are processed in a timely manner.

    In the continueRecording() function, once you have interleaved the left and right channel samples, what do you do with buffer_out? Write it to an SD card?

    Pete

  15. #15
    Senior Member
    Join Date
    Oct 2016
    Posts
    206
    Thanks Pete, your suggestions are very helpful... I'm solved!!!

    getsize is #define getsize AUDIO_BLOCK_SAMPLES*2
    and adding AudioMemory(256); all works fine!!

Posting Permissions

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