Audio Board locking up all boards on I2C

Status
Not open for further replies.

Stirrups

Member
I am seeking a solution to communicating to Teensy 3.2 and issuing a command to play a WAV file. The summary of my challenge is that as soon as Teensy gets to the playSdWav1.play("XXX.WAV"); command, everything stops for all controllers on the I2C bus. A cold boot is in order to restore the Teensy.

I see this behavior using SDA0/SCL0 on the Teensy 3.2, and SDA1/SCL1. (For the record, I was also able to repeat this behavior using my Teensy 3.6, although I did not also try SDA2/SCL2 there.)

So my question is what it is about the Audio board that, when instructed to play a WAV file, ties up the I2C bus so harshly?

To investigate I built a small proto set up and reduced my code down to the minimum, adding back a little button-driven test logic.
- I have one Arduino Pro Mini with 3 buttons and an LED attached to the I2C bus (address 99). Pushing any button with cause the local LED to light.
- I have a second Pro Mini on the I2C bus (address 33), with an LED. Pushing the first button on my primary Pro Mini will send over a command to this second Pro Mini and cause the LED to blink.
- I also have my Teensy 3.2 with Audio Board on the I2C bus (address 22) and this Teensy has an LED and an Audio board with a proven micro SD and WAV file inserted.
- Pushing the second button on the primary Pro Mini will cause the local LED on the Teensy to blink.
- Pushing the third button on the primary Pro Mini is supposed to cause the Teensy to blink the LED and play the WAV file.

The behavior I am experiencing is:
- push button 1 and the LED on the remote Pro Mini blinks and goes dark (the local LED lights up and then goes dark).
- push button 2 and the LED on the Teensy blinks and goes dark (the local LED lights up and then goes dark).
I can go back and forth between these two buttons all day just fine.
- push button 3 and the local LED lights up and stays lit. The primary Pro Mini no longer responds to any button pushing. The LED on the Teensy is not lit. No WAV file is played. This remains the state as long as I care to wait.

(Also, as soon as I disconnect Teensy from either SDA or SCL, the other controllers might resume processing, or they might remain locked up and require a warm boot. It is inconsistent.)

Here is my connection diagram:
network-diagram-2.jpg

Here is the code for my primary Pro Mini:
Code:
// I2C Teensy Audio Board Conflict Test
// Arduino Pro Mini "MASTER"
// I2C 99
// blink local LED when any button pushed
// pushing "BlinkArdy" button instructs slave Arduino to blink its local LED
// pushing "BlinkTeensy" button instructs slave Teensy to blink its local LED
// pushing "PlayTeensy" button instructs slave Teensy to play WAV file
  #include <Wire.h>
  byte SendCode = 1;
  const int BlinkArdy = 10;
  const int BlinkTeensy = 11;
  const int PlayTeensy = 12;
  const int ledPin = 3;
  int BlinkArdybuttonState = 0;
  int BlinkTeensybuttonState = 0;
  int PlayTeensybuttonState = 0;

void setup() {
  Wire.begin(99);                             // join i2c bus as 99
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(BlinkArdy, INPUT);
  pinMode(BlinkTeensy, INPUT);
  pinMode(PlayTeensy, INPUT);
}

void loop() {
  BlinkArdybuttonState = digitalRead(BlinkArdy);
  BlinkTeensybuttonState = digitalRead(BlinkTeensy);
  PlayTeensybuttonState = digitalRead(PlayTeensy);
  if (BlinkArdybuttonState == HIGH) {
    SendCode = 1;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(33);
    Wire.write(SendCode);
    Wire.endTransmission(33);
  }
  else if (BlinkTeensybuttonState == HIGH) {
    SendCode = 1;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(22);
    Wire.write(SendCode);
    Wire.endTransmission(22);
  }
  else if (PlayTeensybuttonState == HIGH) {
    SendCode = 2;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(22);
    Wire.write(SendCode);
    Wire.endTransmission(22);
  }
  else {
    digitalWrite(ledPin, LOW);
  }
  delay(100);
}

Here is the code for my Teensy 3.2:
Code:
// I2C Teensy Audio Board Conflict Test
// Teensy 3.2 with Audio Board
// I2C 22
// blink local LED if receive char 1 via I2C
// play WAV file if receive char 2 via I2C
  #include <Wire.h>
  #include <Audio.h>
  #include <SPI.h>
  #include <SD.h>
  #include <SerialFlash.h>
  int receivedChar;
  const int ledPin =  5;

  AudioPlaySdWav           playSdWav1;     //xy=220,179
  AudioMixer4              mixer1;         //xy=664,179
  AudioOutputI2S           i2s1;           //xy=911,186
  AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
  AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
  AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
  AudioControlSGTL5000     sgtl5000_1;     //xy=911,388

  #define SDCARD_CS_PIN    10
  #define SDCARD_MOSI_PIN  7
  #define SDCARD_SCK_PIN   14

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Wire.setSCL(16);
  Wire.setSDA(17);
  Wire.begin(22);                             // join i2c bus as 22
  Wire.onReceive(receiveEvent);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany) {
  if (Wire.available() > 0) {
      receivedChar = Wire.read();
    }
    switch (receivedChar) {
      case 1:
          digitalWrite(ledPin, HIGH);
          delay(1000);
          digitalWrite(ledPin, LOW);
          delay(1000);
          break;
      case 2:
          delay(1000);                            // just give us a sec to let anything else get out of the way
          playSdWav1.play("/FX/VOLCANO.WAV");
          delay(1000);                            // and give us another sec to let the audio board do its thing
          break;
      default:
          Serial.println("Cannot decipher transmission");
          Serial.println(String(receivedChar));
          Serial.println(String(howMany));
          break;
    }
}


Here is my code for my secondary Pro Mini:
Code:
// I2C Teensy Audio Board Conflict Test
// Arduino Pro Mini "SLAVE"
// I2C 33
// blink local LED if receive char 1 via I2C
#include <Wire.h>
int receivedChar;
const int ledPin =  3;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Wire.begin(33);                             // join i2c bus as 33
  Wire.onReceive(receiveEvent);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany) {
  if (Wire.available() > 0)
    {
      receivedChar = Wire.read();
    }
    switch (receivedChar) {
      case 1:
          digitalWrite(ledPin, HIGH);
          delay(1000);
          digitalWrite(ledPin, LOW);
          delay(1000);
          break;          
      default:
          Serial.println("Cannot decipher transmission");
          Serial.println(String(receivedChar));
          Serial.println(String(howMany));
          break;
    }
}


It's not a surprise to me at all that Teensy and an Audio board communicate via I2C. What surprises me is the impact that has on other controllers on an I2C bus, especially when I go out of my way to use alternate I2C buses.


Any guidance is, as always, greatly appreciated.

- Eric
 
Code:
  Wire.setSCL(16);
  Wire.setSDA(17);
That code reassigns SCL0(19)/SDA0(18) to SCL0(16)/SDA0(17) - note that this is not SCL1/SDA1. The audio board is hardwired to use SCL0(19)/SDA0(18). I suspect that reassigning those pins causes a lot of confusion.
On the T3.2 SCL1/SDA1 are on the bottom of the board on pins 29+30. Are those the pins you used when you say you tried SCL1/SDA1 on the T3.2 (and on the T3.6)?

Pete
 
I'm following this pinout guidance.
teensy-proj-connect.jpg

Commenting out those lines does require that I move my connections back to pins 18 & 19 so that I can reach the Teensy via I2C. So I am following you. I did NOT connect to those pads beneath as I thought that I could follow the pinout diagram above. I will hit the soldering iron now and report back.


Thanks!
 
That pinout guide is for a Teensy 4.0 (it shows the 1062 processor chip).
On the T3.2, those pins you've highlighted are alternates for SDA0/SCL0

Pete
 
Thanks, Pete...RE pinout guide: Yep, I see it. I was too lazy to go out to my workshop and grab the reference card that comes with the 3.2. Lesson learned.

So now that I am pursuing the TRUE SDA1/SCL1, and I now know that the Wire.setSCL()/Wire.setSDA() command merely redirect SDA0/SCL0, would it be safe to assume that I have merged onto the pathway of renaming Wire to Wire1 and adding pullup resistors in order to fire up the SDA1/SCL1 bus?

Eric
 
Last edited:
I haven't used those pins but I believe you just need to wire your I2C device to pins 29 (SCL1) and 30 (SDA1) with a 4.7k pullup on each. The software then can refer to them as Wire1.

Pete
 
Pete...that has all been done. I have updated my circuit diagram:
network-diagram-3.jpg


And I amended my code for Wire1, also adding some troubleshooting lines to report to the serial monitor so that I can observe the Teensy:
Code:
// I2C Teensy Audio Board Conflict Test
// Teensy 3.2 with Audio Board
// I2C 22
// blink local LED if receive char 1 via I2C
// play WAV file if receive char 2 via I2C
  #include <Wire.h>
  #include <Audio.h>
  #include <SPI.h>
  #include <SD.h>
  #include <SerialFlash.h>
  int receivedChar;
  const int ledPin =  5;

  AudioPlaySdWav           playSdWav1;     //xy=220,179
  AudioMixer4              mixer1;         //xy=664,179
  AudioOutputI2S           i2s1;           //xy=911,186
  AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
  AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
  AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
  AudioControlSGTL5000     sgtl5000_1;     //xy=911,388

  #define SDCARD_CS_PIN    10
  #define SDCARD_MOSI_PIN  7
  #define SDCARD_SCK_PIN   14

void setup() {
  Serial.begin(9600);
  Serial.println("Passing through Setup");
  pinMode(ledPin, OUTPUT);
  // Wire.setSCL(16);
  // Wire.setSDA(17);
  Wire1.begin(22);                             // join i2c bus as 22
  Wire1.onReceive(receiveEvent);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany) {
  Serial.println("Incoming!");
  if (Wire1.available() > 0) {
      receivedChar = Wire1.read();
      delay(10);
      Serial.println("We see this " + receivedChar);
    }
    switch (receivedChar) {
      case 1:
          delay(10);
          Serial.println("Blink the LED");
          digitalWrite(ledPin, HIGH);
          delay(1000);
          digitalWrite(ledPin, LOW);
          delay(1000);
          Serial.println("Exit case");
          break;
      case 2:
          Serial.println("Play the WAV");
          delay(1000);                            // just give us a sec to let anything else get out of the way
          playSdWav1.play("/FX/VOLCANO.WAV");
          delay(1000);                            // and give us another sec to let the audio board do its thing
          Serial.println("Exit case");
          break;
      default:
          Serial.println("Cannot decipher transmission");
          Serial.println(String(receivedChar));
          Serial.println(String(howMany));
          break;
    }
}

At this point I believe that I am on much more solid footing for wiring and coding than I was before, for which I am very grateful.

However, in the larger picture I am right back where I started. I can communicate from Arduino to Teensy and instruct Teensy to blink the LED, and it does. And I can communicate to the Teensy and instruct Teensy to play a WAV file. Teensy sees that instruction, gets to the correct 'case' statement, most likely issues the playsdWAV1.play instruction, and locks up again requiring a cold boot. Here is a screen cap of the monitor:
serial-monitor-1.jpg
and you can see that there is no message after the .play command to "Exit case". Now, if I press a button on the Arduino, it will light it's local LED and then lock up when it attempts to access the I2C bus.

And here is where it gets more odd (although perhaps a clue to those more informed/experienced). If I unmount the Audio board and repeat the above test I get the same result. So the problem has nothing to do with anything the Audio board might be doing. It has to do with how Teensy wants to communicate to the Audio board. Something in that process is crashing into the I2C bus that I am using between controllers. And now we see that this is happening even if we force the Teensy to talk to the other controllers on the SLC1/SDA1 bus (or, at least, if I think I have forced that to happen...)

Eric
 
Have you verified that the Teensy 3.2 can play that WAV file on its own? i.e. load a sketch which only plays the WAV repeatedly without using Wire1 at all.

Pete
 
Have you verified that the Teensy 3.2 can play that WAV file on its own? i.e. load a sketch which only plays the WAV repeatedly without using Wire1 at all.

Pete

Yes and no. That is where I began.

My end goal is to launch my audio programming via WiFi, so I am working my way outwards one level at a time, proving things out as I go. My lab began just with one Teensy 3.2 and Audio board, and a series of buttons. I put all my audio on my microSd card and proved out my code logic using buttons as triggers. The Teensy and Audio board were working almost perfectly. (I say 'almost' because I could not overcome playing 2 WAV files at once cleanly. If I wish to stick with polyphonic I will have to go back and stack Audio boards or something. I could also switch to a Robertsonic Tsunami but that would entail starting all over on my testing. That's all later.)

Anyway, yes, I had my audio files playing on my 3.2/Audio board using button triggers and everything that I needed was functioning.

Then I moved to expand one step, and added this Arduino via I2C. I moved my button triggers over to the Arduino and had the Arduino forward the trigger request to Teensy. And this is where things are now, with this issue. Playing WAV files stopped working and the Arduino somehow got locked up via the I2C connection.

So I rebuilt the first lab and re-tested to confirm local button triggers were working and that Teensy/Audio board were still playing WAV files. Then I went out and grabbed a brand-new Teensy and Audio board, soldered new headers to them, stacked them, and built a second lab (net-new) for them using the Arduino. The problem remains. So, technically, I have not proven that THIS Teensy/Audio board combo has played WAV files on their own but I had proven the earlier combo was successful before adding in the Arduino, and the results are the same.

I suppose that if it is required to prove things out and enable further troubleshooting assistance I could build out both labs side by side - one using local button triggers and one using remote button triggers via Arduino over I2C. I could set them side by side and move the SAME Teensy/Audio board/microSD back and forth between them to re-confirm that the focus needs to be on something happening at the I2C level? If, logically, that is just busy work I won't bother but if there is real value to that I can get right on it. Guidance is much appreciated. (As would be, I suppose, an oscilloscope. Hoping not to have to go there.)

As always, thanks for the mental time cycles...

Eric
 
I'm not sure if that has answered my question :)
Can you load a sketch into the Teensy, shown in the diagram in Msg #7, which just plays the audio file while the other hardware shown in the diagram is connected and powered? I'm wondering if there's something preventing the WAV playing when in that circuit. If it can play the file, it'll require a lot more mental time cycles to figure out what's going on.

Pete
 
I'm not sure if that has answered my question :)
Can you load a sketch into the Teensy, shown in the diagram in Msg #7, which just plays the audio file while the other hardware shown in the diagram is connected and powered? I'm wondering if there's something preventing the WAV playing when in that circuit. If it can play the file, it'll require a lot more mental time cycles to figure out what's going on.

Pete

Ah. Ok. Sorry. I get it now. I'll hook up to that and report back.
 
Ok, here is what I did:

1. I took the microSD card back to my first gen lab setup that included the first test Teensy/Audio board and confirmed that it could play a WAV file just fine. I used my initial lab code (which is far more complex) to run the test, but instead of doing the button trigger thing (since I won't have local buttons on my second gen lab) I just inserted my SUB_Play_Playlist1() command into loop. I reloaded the code into my first test Teensy/Audio board setup and observed it playing the WAV file, counting down until complete, and then playing it over, rinse/repeat. It plays endlessly just fine. At this point I know my microSD card is good, and that I have one good Teensy/Audio board combo, and that I have one good lab. Therefore...

2. I took the microSD card and moved it to my second test Teensy/Audio board combo. I removed my first combo from my gen 1 lab and inserted my second combo. I downloaded the same code and repeated the test above. Everything worked fine. Now I know that I have a functioning new Teensy/Audio board combo as built for my second gen lab (no soldering faux pas) and a good microSD card. And I know that all these items have working code. Therefore...

3. I moved the second test Teensy/Audio board combo with the working microSD card and proven code over to my second gen lab setup. This has the proven components installed which are all using the wiring setup as laid out in message 7 above...EXCEPT...I did NOT reconnect the I2C connections. The new combo remained isolated from I2C. It only shared power and ground. I repeated the test. The new combo played the WAV file again just fine on the second gen lab. Not a big step forward, but it did insure that I had power right throughout. Therefore...

4. I reconnected I2C and repeated the test. Everything still works fine. This is another baby step forward. It only shows that electrically I don't have a short on my I2C bus between the Teensy and the Arduinos because I have no Wire1.begin(); command, and no Wire1.onReceive(receiveEvent); command from my lab 2 stripped down code (which I have been sharing here). Still no basic electrical short circuits. Therefore...

5. I inserted into the working code the command lines:
Wire1.begin();
Wire1.onReceive(receiveEvent);
I also added an empty receiveEvent() routine just to avoid compile errors. I did NOT change the existing command within loop to run the SUB_Play_Playlist1() command. The purpose of this test was just to determine what would happen if I2C was now active on Teensy using Wire1, AND we could still play the WAV file. The result is that the lab setup continued to play the WAV file just fine.

6. Still with the exact same setup as Setup (5), I pressed the button from the sending Arduino that commanded the Arduino to transmit char 1 to Teensy. The result was that immediately the WAV file continued to play, but there was a solid tone that disrupts and intermixes with the playing WAV file. The WAV file plays in a loop just fine, and the I2C comm between the two Arduinos remains unaffected. Therefore...

7. I moved the SUB_Play_Playlist1() command out of loop and into the receiveEvent() routine. My expectation is that upon cold boot the comm between Arduinos should work just fine, and that the WAV file will not auto start. And when I press button #2 on the sending Arduino the Teensy will see that with the Wire1.onReceive event, invoke the receiveEvent() routine where Teensy will see the SUB_Play_Playlist1() command, and the WAV file should start playing. The results?
  • comm between Arduinos remains fine at first
  • sending any char to the Teensy (obviously) triggers the receiveEvent() routine. If I wait about 4 seconds the WAV file plays fine. If I send not further I2C signals to the Teensy, it will play fine to conclusion.
  • while the WAV file is playing, I can communicate between Arduinos with no issue.
  • once the WAV file concludes and the Audio board is idle, I can send another char to Teensy just fine, and I can send char to the other Arduino.
  • BUT...if I fail to press the button to signal Teensy rapidly enough, the local LED on the sending Arduino will remain lit until the Teensy begins to play the WAV file. This might be a debounce issue. Seem solvable. MORE IMPORTANT, if I try to send a signal to Teensy while it is playing the WAV file, Teensy stops playing the WAV file and sends out the tone for a sustained period of time. Anywhere between 5 and 10 seconds. During that period there might (it's inconsistent) be a lock up with the sending Arduino. Eventually everything may clear. Or, we may get stuck in a condition where even though I can readily communicate between Arduinos, any further attempt to comm to Teensy will hold up the local LED on the sending Arduino high, and Teensy does not respond. A cold boot is mandatory.


Conclusion: all my wiring and all my components appear to be functional and correct. Based on this series of tests and the earlier test without the Audio board, there is definitely something occurring within Teensy when trying to play WAV files that is causing some issue with the I2C bus common between controllers. This is true even if Teensy sees that bus as Wire1. So we are back to the basis of my initial post. On the hopeful side, even though the failure results are very inconsistent, there does seem to be a potential of managing the processes around this issue by being extremely careful to control all I2C comm to Teensy. Something to the effect of limiting all comm to Teensy from one dedicated other controller that waits until Teensy sends back an all clear to it before it allows itself to send any new command to Teensy. I have to code that and test that, and it would have a significant negative impact on my project functionality so I would rather not, but it's at least something for me to play with.

So going forward, if all of this informs any insight or generates new ideas for further tests, I am wide open to suggestions and queries. My project would be MUCH more effective if I could send instructions to Teensy while it was at any playing point within any WAV file.
 
Last edited:
This only gets a single character each interrupt - how many will be present?
Code:
void receiveEvent(int howMany) {
  Serial.println("Incoming!");
  if (Wire1.available() > 0) {

Should it be checking in 'case 2:' if it is already playing before trying to play() again? Not sure how long the sample is.

The overt multiple long 1 sec delays in that 'Event' code seems problematic.
 
This only gets a single character each interrupt - how many will be present?
Code:
void receiveEvent(int howMany) {
  Serial.println("Incoming!");
  if (Wire1.available() > 0) {

Should it be checking in 'case 2:' if it is already playing before trying to play() again? Not sure how long the sample is.

The overt multiple long 1 sec delays in that 'Event' code seems problematic.

Those 1 second delays were added one at a time as I was trying to slow things down intentionally to isolate and protect communications between Teensy and the Audio Board in order to eliminate the problem. The problem was manifest without either of those. At first draft, the code looked like:

Code:
case 2:
          playSdWav1.play("/FX/VOLCANO.WAV");
          delay(10);
          break;

That's pretty standard stuff for launching a WAV file, and what is in the code I had built for production which I stripped back for gen 2 testing. So at first I simply ported over that code into this lab and crashed into my problem. Step by step I added the lines to provide status to the serial monitor and the delays to slow things down. As things stand in the test code right now, I could take out the case statements altogether because I am simply launching the WAV file as soon as we enter the receiveEvent routine. I did not post the explicit code that I ended up at last night as I did my step-by-step hardware testing, but I can do that.

Also, as evidenced by the other code I posted at first, the transmitting Arduino sends either a single char 1 or a single char 2 to Teensy when the transmitting Arduino is triggered by button. I did concede that I need to go back and cleanup the button handling to deal with some bounce junk I am witnessing that can sometimes transmit the char numerous times instead of just once.
 
I think the debouncing is part (or all) of the problem. You handle the I2C read in a callback function, which is essentially an interrupt routine. The first occurrence of the message starts the wav but within a few milliseconds, the I2C code will receive another one and try to call the callback function again while it is still sitting in a delay waiting for the WAV to start playing.
It would be worthwhile rewriting the code so that the callback function only sets a flag. The flag is then handled in the loop() function outside the interrupt context. You'll still have to fix the contact bounce in the primary Pro Mini but together they should make things work properly.
Maybe start by fixing the contact bounce in the Pro Mini since that has to be done anyway, and see if it improves, or even fixes, the problem.

Pete
 
I think the debouncing is part (or all) of the problem. You handle the I2C read in a callback function, which is essentially an interrupt routine. The first occurrence of the message starts the wav but within a few milliseconds, the I2C code will receive another one and try to call the callback function again while it is still sitting in a delay waiting for the WAV to start playing.
It would be worthwhile rewriting the code so that the callback function only sets a flag. The flag is then handled in the loop() function outside the interrupt context. You'll still have to fix the contact bounce in the primary Pro Mini but together they should make things work properly.
Maybe start by fixing the contact bounce in the Pro Mini since that has to be done anyway, and see if it improves, or even fixes, the problem.

Pete

Good plan of attack for today, modifying the code on Teensy to handle the comm better. Thanks.

I am thinking that I could also change the code on the transmitting Arduino to accept the button push (fixing debounce probs while I am at it) but holding off of the need to transmit immediately. Maybe take the button push, count down a few seconds, and then send the char. By then that should be independent of anything going on with the button, which should be all resolved and idle by then. And then, yeah, on Teensy, improve how I handle the receipt of the signal to get out of the way of interrupts.

So I will do that today, and for the sake of those who are collaborating to assist me I will post the new code so that you have current state for easier review.

Again, thanks to everyone for your time and guidance!

Eric
 
UPDATE 5/1/2020:

To catch up on where I am at, here is the network diagram for the lab I am currently working with (from above):
network-diagram-3.jpg

This is the current lab code for the sending Arduino Pro Mini, "MASTER", I2C address 99. This was modified yesterday for yesterday's testing. Note the use of bounce.h and debounce code. Pretty standard stuff, and works fine. No more bounce issues:
Code:
// I2C Teensy Audio Board Conflict Test
// Arduino Pro Mini "MASTER"
// I2C 99
// blink local LED when any button pushed
// pushing "BlinkArdy" button instructs local Arduino to send char 1 to remote Arduino to blink its local LED
// pushing "BlinkTeensy" button instructs local Arduino to send char 1 to remote Teensy to blink its local LED
// pushing "PlayTeensy" button instructs local Arduino to send char 1 to remote Teensy to play WAV file
  #include <Wire.h>
  #include <Bounce.h>

  byte SendCode = 0;
  const int ledPin = 3;
  const int BlinkArdy = 10;
  const int BlinkTeensy = 11;
  const int PlayTeensy = 12;
  Bounce BlinkArdybutton = Bounce(BlinkArdy, 15);       // send char 1 to other arduino
  Bounce BlinkTeensybutton = Bounce(BlinkTeensy, 15);   // send char 1 to teensy
  Bounce PlayTeensybutton = Bounce(PlayTeensy, 15);     // send char 2 to teensy

void setup() {
  Wire.begin(99);                                       // join i2c bus as 99
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(BlinkArdy, INPUT_PULLUP);
  pinMode(BlinkTeensy, INPUT_PULLUP);
  pinMode(PlayTeensy, INPUT_PULLUP);
}

void loop() {
  BlinkArdybutton.update();
  BlinkTeensybutton.update();
  PlayTeensybutton.update();
 
  if (BlinkArdybutton.fallingEdge()) {
    SendCode = 1;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(33);
    Wire.write(SendCode);
    Wire.endTransmission(33);
    delay(1000);
    digitalWrite(ledPin, LOW);
  }

  else if (BlinkTeensybutton.fallingEdge()) {
    SendCode = 1;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(22);
    Wire.write(SendCode);
    Wire.endTransmission(22);
    delay(1000);
    digitalWrite(ledPin, LOW);
  }

  else if (PlayTeensybutton.fallingEdge()) {
    SendCode = 2;
    digitalWrite(ledPin, HIGH);
    Wire.beginTransmission(22);
    Wire.write(SendCode);
    Wire.endTransmission(22);
  }
  else {
    //digitalWrite(ledPin, LOW);
  }
  delay(100);
}

This is the current lab code for the Teensy 3.2, "TEENSY", I2C address 22. This was also modified yesterday to move the playSdWav1.play command out of setup:
Code:
// I2C Teensy Audio Board Conflict Test
// Teensy 3.2 with Audio Board "TEENSY"
// I2C 22
// blink local LED if receive char 1 via I2C
// play WAV file if receive char 2 via I2C
  #include <Wire.h>
  #include <Audio.h>
  #include <SPI.h>
  #include <SD.h>
  #include <SerialFlash.h>
  int receivedChar;
  int WAVfileIsActive;
  uint32_t Current_Track_Length;
  uint32_t Current_Track_Position;
  uint32_t Current_Track_Time_Remaining;
  const int ledPin =  5;

  AudioPlaySdWav           playSdWav1;     //xy=220,179
  AudioMixer4              mixer1;         //xy=664,179
  AudioOutputI2S           i2s1;           //xy=911,186
  AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
  AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
  AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
  AudioControlSGTL5000     sgtl5000_1;     //xy=911,388

  #define SDCARD_CS_PIN    10
  #define SDCARD_MOSI_PIN  7
  #define SDCARD_SCK_PIN   14


void setup() {
  Serial.begin(9600);
  Serial.println("Passing through Setup");
  pinMode(ledPin, OUTPUT);
  Wire1.begin(22);                             // join i2c bus as 22
  Wire1.onReceive(receiveEvent);
}

void SUB_Play_WAV() {
  Serial.println("Play the WAV");
  WAVfileIsActive = 1;
  playSdWav1.play("0001.WAV");
  delay(100);
  Serial.println("Exit routine");
}

void loop() {
  delay(100);
}

void receiveEvent(int howMany) {
  Serial.println("Incoming!");
  if (Wire1.available() > 0) {
      receivedChar = Wire1.read();
      delay(10);
      Serial.println("We see this " + receivedChar);
    }
    switch (receivedChar) {
      case 1:
          delay(10);
          Serial.println("Blink the LED");
          digitalWrite(ledPin, HIGH);
          delay(1000);
          digitalWrite(ledPin, LOW);
          delay(1000);
          Serial.println("Exit case");
          break;
      case 2:
          SUB_Play_WAV();
          break;
      default:
          Serial.println("Cannot decipher transmission");
          Serial.println(String(receivedChar));
          Serial.println(String(howMany));
          break;
    }

    if (WAVfileIsActive == 1) {
      Current_Track_Length = playSdWav1.lengthMillis();
      Current_Track_Position = playSdWav1.positionMillis();
      Current_Track_Time_Remaining = (Current_Track_Length - Current_Track_Position);
      Serial.println("Countdown on Player_1 = " + String(Current_Track_Time_Remaining));
      if (Current_Track_Time_Remaining < 1000) {
        WAVfileIsActive = 0;
      }
    } 
}


This is the current lab code for the receiving Arduino Pro Mini, ARDY", I2C address 33. It has not changed from the beginning of my lab work:
Code:
// I2C Teensy Audio Board Conflict Test
// Arduino Pro Mini "ARDY"
// I2C 33
// blink local LED if receive char 1 via I2C
#include <Wire.h>
int receivedChar;
const int ledPin =  3;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Wire.begin(33);                             // join i2c bus as 33
  Wire.onReceive(receiveEvent);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany) {
  if (Wire.available() > 0)
    {
      receivedChar = Wire.read();
    }
    switch (receivedChar) {
      case 1:
          digitalWrite(ledPin, HIGH);
          delay(1000);
          digitalWrite(ledPin, LOW);
          break;          
      default:
          Serial.println("Cannot decipher transmission");
          Serial.println(String(receivedChar));
          Serial.println(String(howMany));
          break;
    }
}


And here is the status of everything:
For starters, it is clear that I need to learn a lot more about switch/case execution within receiveEvent with the controller logic. I have done a lot of web searching and have yet to find a switch/case example that is anything other than lighting up LEDs or posting message to the Serial monitor. I am trying to do something far more significant than that. I am trying to run controller logic far more complex than just changing some particular pin to HIGH. There may be a clue in the following:

When the sending Arduino ships a char over to Teensy to blink the Teensy local LED, the Teensy performs exactly as expected. It walks the switch/case code and turns the LED on for 1 second, then turns it back. This is NOT what happens when the same sending Arduino sends the same char to the other Arduino, which has the exact same receiveEvent and switch/code commands. With the Arduino, the result is that the LED turns back off as fast as it turned on. It's as if the 1 second delay is being ignored. Something about how the code is compiled by the IDE for the different procs is resulting in different behavior. If I was all into lighting up LEDs I would have cared more. Now I just consider this as smoke that might indicate a mysterious root cause, one that might lead to greater understanding of my REAL problem.

Because we are back to my real problem.

Remember from my last test setup I was launching my WAV file right from within setup, and then sending I2C chars to Teensy to see how it would react. We saw disruption in the form of an audio tone and a temporary halt to playback, and we saw an inconsistent outcome. Sometimes the WAV playback would resume, and other times things were locked up requiring a cold restart. In the current lab setup you can see that I am back to trying to launch the playing of the WAV file from within receiveEvent, and within my switchh/case logic. I tried to variations of this. One was to insert the playSdWav1.play("0001.WAV"); command within the case 2/break; section. The other method (the current setup) was to call a routine within the case 2/break: section and park the " playSdWav1.play("0001.WAV"); command there. This latter method is what I really want to be doing in the production code anyway.

Regardless, the result is the same. It's the original problem reported. As soon as the button is pressed on the sending Arduino which would transmit char 2 to Teensy, my lab becomes erratic.

To begin, pushing "BlinkArdy" button on "MASTER" Arduino once =
"MASTER" local LED is lit for one second and then goes back off.
"ARDY" local LED flashes once.

Pushing "BlinkTeensy" button on "MASTER" Arduino once =
"MASTER" local LED is lit for one second and then goes back off.
"TEENSY" local LED is lit for one second, and then goes off.

I can continue to push "BlinkArdy" and "BlinkTeensy" buttons forever, and in any order, and this behavior never changes.

Pushing "PlayTeensy" button on MASTER" Arduino once =
"MASTER" local LED goes solid and does not go off. This means that "MASTER" is not executing code logic beyond the Wire.endTransmission(22); command. I can put code lines to send messages to the Serial monitor after that code line and those messages do not appear on the monitor.
"TEENSY" does not play the WAV file.

The lab is now in an erratic state. It may be that any additional button pushing has zero effect on anything. It may be that I can wait out the lab, and the local LED to "MASTER" will go off and I can then communicate fine to "ARDY". In that last case, though, as soon as I attempt to communicate to Teensy again the lab will lock up hard and require a cold boot. Teensy is non-responsive as soon as I we flush the buffer on "MASTER" with the Wire.endTransmission(22); command, and Teensy cannot be made to indicate any responsiveness by injecting any code lines to send test updates to the Serial monitor, even if those code lines are BEFORE the code line to play the WAV file. Teensy definitely requires a cold boot.

The bottom line here, and the target of my troubleshooting research, has come back to where I started. When a sending controller dumps its buffer and puts a transmission to Teensy onto the I2C bus, Teensy sees and reads that transmission. As soon as Teensy reads that transmission it begins to follow any instructions within the receiveEvent function. If any of those instructions invoke the playSdWav1.play(""); code line, Teensy begins to take action on that playSdWav1.play action immediately - and apparently before any other instructions prior to that code line get to complete. And something happens next that cascades back to the I2C bus and impacts other controllers on the bus attempting to send data.

What could this possibly be?
And how could I possibly code to safely work with what is happening?
 
What are the odds of switching the library on Teensy from wire to i2c_t3 having some positive impact on this? I have never used the i2c_t3 library so I am unsure what, if any, unintended consequences I might introduce elsewhere if I just go experimenting with it blindly.
 
What are the odds of switching the library on Teensy from wire to i2c_t3 having some positive impact on this? I have never used the i2c_t3 library so I am unsure what, if any, unintended consequences I might introduce elsewhere if I just go experimenting with it blindly.

The issue is i2c_t3 is NOT compatible with Wire. To be clear, the main calls are the same, but you have to make sure that every module that you include in your program uses i2c_t3 and not Wire. In particular, you would need to clone the entire Audio library to do this.

In addition, if you ever have plans to move to Teensy 4.0 or the forthcoming Teensy 4.1, the i2c_t3 library has not been ported to the Teensy 4 environment.

These two old posts detail how you can change to use i2c_t3 from Wire in a specialized directory tree. I don't know if they still work:
 
...In particular, you would need to clone the entire Audio library to do this...

[/list]

Yeah, it's precisely this level of effort that motivates my question. It's work that requires care and may, if not done carefully, mess up other things in ways that cause their own troubleshooting efforts. I have no problem doing the library learning and then doing the work, but I won't waste the effort if the community would share a consensus that the i2C_t3 library would not have any material impact on my primary issue of Teensy not playing a WAV file via the Audio board and locking up everything after receiving a flag to do so via I2C.
 
Status
Not open for further replies.
Back
Top