I2S library question

I'm using the arduino I2S library on a MAKERZERO project and sending the output to an MAX08357. The program is using an incremented variable "t" that increments +1 each time Loop() cycles. I need to have the counter variable increment each time I2S.write() has completed. Is there a way to check whether or not I2S.write() has completed? Even if someone can point me to a solution I'd appreciate it. I had this program working similarly on an nano by using the timers to output sound on a PWM pin. It worked fine on that but couldn't keep up with updating the display along with solving the equation that is called in the code. The MAKERZERO seemed to have the speed, but it's actually working worse with the MZ despite the faster speed. Any help would be appreciated. I'm wondering if the I2S library is the way to go.

Here's a bit of the code...

void loop(void) { 
short result = 0;
int potVals = 0;
potVals = readMux(muxIndex);
progVals(muxIndex, potVals);
synthDisplay(muxIndex);

//check or reset the muxIndex
if (muxIndex == 12) {
  muxIndex = 0;
  } else {
  muxIndex++;
  }
if (Flag == 0) {
  if (parFlag == 0) {
        myT = mEqu0();
        //Serial.println(myT);
      } else if (parFlag == 1) {
        myT = mEqu1();
      } else if (parFlag == 2) { // Get the equation done early
        myT = mEqu2();
      }  else if (parFlag == 3) {
        myT = mEqu3();
      }
result = map(myT, 0, 255, -128, 128); // Make it a playable value
result = result * 75; //set the volume
I2S.write(result);
I2S.write(result);
t++; // increment the counter
}
}

have you considered using the availableForWrite() when it returns zero

Well, you didn't both to post a complete code or provide a GitHub link to the I2S library you're using. So, I can't comment on a solution based on the library.

But, I'd consider jumpering the I2S LRCK signal to an interrupt-capable pin on the processor. Set the interrupt to fire on either falling or rising edge. Increment your variable in the ISR. This will give you one increment per Left / Right audio sample pair.

Since the I2S library is bundled with Arduino SAMD Boards, @lycosa2000 may not know the GitHub location for it, so I'll post it for them:

Thanks @pert.

So, looking in I2S.h, ones sees the function prototype:

void onTransmit(void(*)(void));

Seems like that could be a reasonable place to start.

gfvalvo:
Well, you didn't both to post a complete code or provide a GitHub link to the I2S library you're using. So, I can't comment on a solution based on the library.

But, I'd consider jumpering the I2S LRCK signal to an interrupt-capable pin on the processor. Set the interrupt to fire on either falling or rising edge. Increment your variable in the ISR. This will give you one increment per Left / Right audio sample pair.

Thank you, that sounds very much what I'm trying to do. Using the timer ISR on a nano I was able to accomplish incrementing the variable at the right time. Having an ISR would work likely work just as I need it to.

gfvalvo:
So, looking in I2S.h, ones sees the function prototype:

void onTransmit(void(*)(void));

Seems like that could be a reasonable place to start.

I had attempted to use that, but I apparently am not using it correctly and I can find little information on the internet on how to use it properly. My best guess was something like this:

I2S.write(result);
I2S.write(result);
I2S.onTransmit(myFlag);
} // end of loop

void myFlag(void) {
  t++;
  }

That doesn't work at all and I'm not finding the resources out there or examples where it's used.

lycosa2000:
I had attempted to use that, but I apparently am not using it correctly and I can find little information on the internet on how to use it properly. My best guess was something like this:

I2S.write(result);

I2S.write(result);
I2S.onTransmit(myFlag);
} // end of loop

void myFlag(void) {
  t++;
  }




That doesn't work at all and I'm not finding the resources out there or examples where it's used.

What does "doesn't work" mean? Doesn't compile? Doesn't increment the variable as you'd expect?

gfvalvo:
What does "doesn't work" mean? Doesn't compile? Doesn't increment the variable as you'd expect?

Sorry I wasn't more clear, but it doesn't increment the variable.

Serial.println(t);
I2S.write(result);
I2S.write(result);
I2S.onTransmit(myFlag);
} // end of loop

void myFlag(void) {
  t++;
  }

When outputting the value to Serial Monitor, 't' remains 0.

lycosa2000:
Sorry I wasn't more clear, but it doesn't increment the variable.

Serial.println(t);

I2S.write(result);
I2S.write(result);
I2S.onTransmit(myFlag);
} // end of loop

void myFlag(void) {
 t++;
 }




When outputting the value to Serial Monitor, 't' remains 0.

Post your complete code that doesn't work. From that snippet it looks like you're doing it wrong.

gfvalvo:
Post your complete code that doesn't work. From that snippet it looks like you're doing it wrong.

Here's a scaled down version of the whole program.

#include <I2S.h>
volatile static unsigned long t = 0;
const int sampleRate = 7350; // sample rate in Hz
byte myb = 0;
short sample = 0; // current sample value
short result = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("I2S simple tone");

  // start I2S at the sample rate with 16-bits per sample
  if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
    Serial.println("Failed to initialize I2S!");
    while (1); // do nothing
  }
}

void loop() {
  sample = t; //Use the counter value and wrap it into a byte. This is where the equation goes for making weird sounds...
  myb = sample;
  result = map(myb, 0, 255, -128, 128); //Make the value friendly for the MAX08357
  result = result * 50; //Adjust the volume
  
  // write the same sample twice, once for left and once for the right channel
  I2S.write(result);
  I2S.write(result);

            
  // increment the counter for the next sample
  t++;
  Serial.println(myb); //plotting this makes a saw wave at 7350/256 = 28.71Hz
}

So there's something I realized that I suppose I didn't know about I2C. It seems that when using I2C, the main loop is running at the samplerate. When plotting this simple example and watching the values of the variable 'myb', the counter is incrementing perfectly with the write() function. I would expect that if the processor was running at 85Mhz and the samplerate was set to 7350Hz, that the counter variable 't' would increment much faster than the write function would be triggered. If it's true that the main loop is running in lockstep with the I2S samplerate, I don't think I2C would be the way to go since I have a lot more to be processed in real-time. I'm guessing there's a way to make it run in the background on these boards...unfortunately, I don't have enough experience to understand fully what's going on with it. The arduino online documentation for the I2S library isn't as detailed as I'd hoped, or at least not that I've found so far. Thank you for taking the time to help!

Actually, I wanted to see your code using the 'onTransmit()' function because that's what you said wasn't working.

The way you're using the library is probably causing it to block until the write is done, thus making the whole code run synchronous with the sample rate. I’m sure there's a way around that. Taking a quick look in the source code, it seems to support DMA. That would be the way I'd go. You'll need to dig through the code in detail to figure out how to do that.

As a less sophisticated approach, you might try calling 'availableForWrite()' in your loop and only call the write function when it returns a number greater than or equal to the number of bytes you want to write.

EDIT:
Thinking about it some more, you're really going to have to go through the library's source code and sort out how it works. Read the SAMD datasheet too. I'm only well-versed with I2S on the Teensey 3.2/5/6 family of boards. There's a way to do what you want, but it will require use of DMA and/or interrupts.

gfvalvo:
EDIT:
Thinking about it some more, you're really going to have to go through the library's source code and sort out how it works. Read the SAMD datasheet too. I'm only well-versed with I2S on the Teensey 3.2/5/6 family of boards. There's a way to do what you want, but it will require use of DMA and/or interrupts.

I agree completely. It seems that I'm trying to run before I ever learned to walk. I found DMA examples and the code is a bit foreign to me at this point. I don't really want to copy/paste code without understanding it so I've decided to go back to using an arduino nano to accomplish the same goal. At least I've spent enough time learning the timers associated with the nano/uno that I'm getting comfortable with it. I've decided to learn the ATtiny85 completely as well as learning assembly (I signed up for a class). I figure it would be better to fully understand the datasheets when they are only 200+ pages long as compared to the SAMD's datasheet which I believe to be over 1000 pages. Thank you for helping me out. When I search for answers on this forum, I always see your name in there somewhere. Thanks for taking that time. It didn't go unnoticed or unappreciated.