strange i2c issues with Teensy LC in single-master, multi-slave setup

Status
Not open for further replies.

even_rats

Member
I'm prototyping a MIDI controller with an ESP32 board as the main MCU, but also using a Teensy LC for its easy usbMIDI capabilities. And there's an MCP23017 i2c i/o expander that's used to control a bank of LEDs.

These 3 components talk to each other over an i2c bus, with the ESP32 board (SparkFun Thing Plus) acting as master, and the Teensy LC and MCP23017 in slave mode. The Teensy LC and MCP23017 are assigned different i2c addresses (0x33 and 0x20 respectively), and there are 3k pullup resistors to Vcc (3.3v) on each i2c line near each slave device.

i2c_q2.jpg

For current communication-testing purposes:
  • once every second, the esp32 master sends commands via i2c to the MCP23017 to blink the LEDs to count in binary. (simplest way to test because it uses a register based control scheme)
  • the esp32 master waits for a button press, and when it detects one, sends data via i2c to the Teensy LC representing a MIDI note on/note off. Each keypress is sent as a 5 byte message starting with a magic number byte (0xAA). The Teensy interprets and forwards these messages via usbMIDI.

These 2 things each work perfectly one at a time. But when I try them at the same time, they both stop working. With both communication tasks going, the LEDs blink correctly, and everything works when I push the MIDI test button once. But when I press it a second time, the LEDs stop blinking, and no further usbMIDI messages are sent.

Code running on the esp32 and teensyLC, respectively:
Code:
// esp32_i2c_test.ino
// i2c master - runs on esp32 board

#include <Bounce2.h>
#include <Wire.h>

#define TEENSYLC_ADDR     0x33
#define MCP23017_ADDR     0x20

#define MSG_SEPARATOR     0xAA
#define MIDI_TYPE_CC      0x20
#define MIDI_TYPE_PC      0x21
#define MIDI_TYPE_NOTEON  0x22
#define MIDI_TYPE_NOTEOFF 0x23

#define BUTTON_PIN  14

uint8_t counter = 0;
unsigned long start_time, current_time;

Bounce button;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  
  // setup MCP23017 as all outputs
  Wire.beginTransmission(MCP23017_ADDR);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // set all of port A to outputs
  Wire.endTransmission(); 

  Wire.beginTransmission(MCP23017_ADDR);
  Wire.write(0x01); // IODIRB register
  Wire.write(0x00); // set all of port B to outputs
  Wire.endTransmission();

  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  
  button = Bounce(BUTTON_PIN, 10);

  start_time = millis();
}

void loop() {
  // communicate with 2 different i2c slaves
  // both of the following work correctly one at a time.
  // but when I attempt both, it locks up  
  
  // blink LEDs using MCP23017 via i2c
  update_LEDs();

  // check for button press and send resulting data to Teensy LC via i2c
  check_midi_button();

}

void update_LEDs() {
  // blink LEDs using MCP23017 via i2c
  current_time = millis();
  if(current_time - start_time >= 1000) { // update LEDs once per second (1000ms)
    // a simple test that causes the connected LEDs connected to count in binary
    Wire.beginTransmission(MCP23017_ADDR);
    Wire.write(0x12); // address port A
    Wire.write(counter++);  // value to send
    Wire.endTransmission();

    start_time = current_time;
  }
}

void check_midi_button() {
  // handle button press and send resulting data to Teensy LC via i2c
  if(button.update()) {
    if(button.fallingEdge()) {
      // to test, send a middle C with velocity 100 on channel 3
      i2c_send_noteOn(3, 60, 100);
      digitalWrite(LED_BUILTIN, HIGH);
    } else if(button.risingEdge()) {
      // .. and the corresponding note off message
      i2c_send_noteOff(3, 60, 0);
      digitalWrite(LED_BUILTIN, LOW);
    }
  }
}

void i2c_send_noteOn(unsigned int channel, unsigned int note, unsigned int val) {
  Serial.print("Sending note on: ");
  Serial.println(note);
  
  Wire.beginTransmission(TEENSYLC_ADDR);
  Wire.write(MSG_SEPARATOR);
  Wire.write(MIDI_TYPE_NOTEON);
  Wire.write(channel);
  Wire.write(note);
  Wire.write(val);
  
  Wire.endTransmission();
}

void i2c_send_noteOff(unsigned int channel, unsigned int note, unsigned int val) {
  Serial.print("Sending note off: ");
  Serial.println(note);
  
  Wire.beginTransmission(TEENSYLC_ADDR);
  Wire.write(MSG_SEPARATOR);
  Wire.write(MIDI_TYPE_NOTEOFF);
  Wire.write(channel);
  Wire.write(note);
  Wire.write(val);
  
  Wire.endTransmission();
}

Code:
// teensylc_i2c_test.ino
// i2c slave - runs on Teensy LC

#include <Wire.h>
#include <queue>

#define TEENSYLC_ADDR     0x33
#define MSG_SEPARATOR     0xAA
#define MIDI_TYPE_CC      0x20
#define MIDI_TYPE_PC      0x21
#define MIDI_TYPE_NOTEON  0x22
#define MIDI_TYPE_NOTEOFF 0x23

// This sketch receives messages over i2c representing MIDI data, and forwards them over usbMIDI. 
// Message structure over i2c is 5 bytes starting with message separator byte (0xAA)
// order: SEPARATOR, MIDI_MSG_TYPE, CHANNEL, VAL1, VAL2
// for example, Note On for middle C (60) at velocity 100 on channel 3 would be:
// 0xAA, 0x22, 3, 60, 100

uint8_t counter;
std::queue<byte> i2c_buffer;
byte this_byte, msg_type, channel, val1, val2;
uint8_t msg_byte_counter; // keep track of how many bytes of the current message we've received, from 0 to 5

void setup() {
  // set up i2c pins on 18 & 19
  pinMode(18, INPUT);
  pinMode(19, INPUT);
  Wire.setSDA(18);
  Wire.setSCL(19);

  // start Wire library in slave mode
  Wire.begin(TEENSYLC_ADDR);
  Wire.onReceive(read_i2c); // register receive handler
  
  Serial.begin(9600);

  // we haven't received any bytes of the first message yet
  msg_byte_counter = 0;
}

void read_i2c(int numBytes) {
  int numBytesRead = 0;
  byte tmp;
  
  Serial.printf("onReceive handler called with %d bytes\n", numBytes);

  // read as many bytes as available into queue
  while(numBytesRead < numBytes) {
    tmp = Wire.read();
    Serial.printf("\tread byte value: %d\n", tmp);
    i2c_buffer.push(tmp);
    numBytesRead++;
  }
  
  if(numBytesRead>0) {
    Serial.printf("Received %d bytes over i2c\n", numBytesRead);
  }

  // process received bytes
  // this relies on int msg_byte_counter, which keeps track of which byte we're on in current message
  while (!i2c_buffer.empty()) {
    this_byte = i2c_buffer.front();

    if(this_byte == MSG_SEPARATOR) {  // start of new message
      i2c_buffer.pop(); // discard separator
      msg_byte_counter = 1;
      
    } else if(msg_byte_counter == 0) { // no message in progress, and no separator
      i2c_buffer.pop(); // discard
    } else {
      switch(msg_byte_counter) {
        case 1: // already have separator
          msg_type = this_byte;
          msg_byte_counter++;
          break;

        case 2: // already have msg_type
          channel = this_byte;
          msg_byte_counter++;
          break;

        case 3: // already have channel
          val1 = this_byte;
          msg_byte_counter++;
          break;

        case 4: // already have val1
          val2 = this_byte;
          msg_byte_counter++;
          break;

        default: // shouldn't happen
          msg_byte_counter = 0;
          break;
      }

      i2c_buffer.pop(); // discard processed byte
    }
  }

  if(msg_byte_counter >= 5) { // we have a full message
    if(msg_type == MIDI_TYPE_CC) {
      usbMIDI.sendControlChange((uint8_t) val1, (uint8_t) val2, (uint8_t) channel);
    } else if(msg_type == MIDI_TYPE_PC) {
      usbMIDI.sendProgramChange((uint8_t) val1, (uint8_t) channel);
    } else if(msg_type == MIDI_TYPE_NOTEON) {
      usbMIDI.sendNoteOn((uint8_t) val1, (uint8_t) val2, (uint8_t) channel);
    } else if(msg_type == MIDI_TYPE_NOTEOFF) {
      usbMIDI.sendNoteOff((uint8_t) val1, (uint8_t) val2, (uint8_t) channel);
    }

    msg_byte_counter = 0; // reset byte counter
 
  }
}

void loop() {
  ;
}

If I look at the log printed to Serial from the Teensy in this failure case, it appears to be incorrectly "receiving" the same 5-byte message over and over again, and the extra incorrect messages correspond temporally to each time the LEDs are supposed to blink (once per second). But with 2 extra null bytes appended each time. (It should be noted that the i2c messages to the MCP23017 are exactly 2 bytes long... hmm) So it seems like some wires are getting crossed somewhere, such that either the message is being incorrectly concatenated and retransmitted, or not being cleared from some queue on the receiving end. But I'm not sure of how to further debug.

Here's a log from when the MIDI button is working correctly, without the LED communication going. All looks good. (170 == 0xAA which is the magic start byte, the rest correspond to the MIDI values I'm sending as a test):
Code:
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 34
	read byte value: 3
	read byte value: 60
	read byte value: 100
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 34
	read byte value: 3
	read byte value: 60
	read byte value: 100
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 34
	read byte value: 3
	read byte value: 60
	read byte value: 100
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
Received 5 bytes over i2c

And here's a log from the failure mode when it crashes with the MCP23017:
Code:
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 34
	read byte value: 3
	read byte value: 60
	read byte value: 100
Received 5 bytes over i2c
onReceive handler called with 5 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
Received 5 bytes over i2c
onReceive handler called with 7 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 7 bytes over i2c
onReceive handler called with 9 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 9 bytes over i2c
onReceive handler called with 11 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 11 bytes over i2c
onReceive handler called with 13 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 13 bytes over i2c
onReceive handler called with 15 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 15 bytes over i2c
onReceive handler called with 17 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 17 bytes over i2c
onReceive handler called with 19 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 19 bytes over i2c
onReceive handler called with 21 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 21 bytes over i2c
onReceive handler called with 23 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 23 bytes over i2c
onReceive handler called with 25 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 25 bytes over i2c
onReceive handler called with 27 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 27 bytes over i2c
onReceive handler called with 29 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 29 bytes over i2c
onReceive handler called with 31 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 31 bytes over i2c
onReceive handler called with 32 bytes
	read byte value: 170
	read byte value: 35
	read byte value: 3
	read byte value: 60
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
	read byte value: 0
Received 32 bytes over i2c

Thanks for reading. Any hints or suggestions are appreciated!
 
Last edited:
To make things easier, here's a simpler version of what's running on the Teensy LC with the message-parsing and usbMIDI stuff stripped out. This still exhibits the same bug as above.

Code:
// teensylc_i2c_test_simplified.ino
// i2c slave - runs on Teensy LC

#include <Wire.h>

#define TEENSYLC_ADDR     0x33

// This sketch receives messages over i2c representing MIDI data, and forwards them over usbMIDI. 
// Message structure over i2c is 5 bytes starting with message separator byte (0xAA)

void setup() {
  // set up i2c pins on 18 & 19
  pinMode(18, INPUT);
  pinMode(19, INPUT);
  Wire.setSDA(18);
  Wire.setSCL(19);

  // start Wire library in slave mode
  Wire.begin(TEENSYLC_ADDR);
  Wire.onReceive(read_i2c); // register receive handler
  
  Serial.begin(9600);
}

// onReceive handler for i2c
void read_i2c(int numBytes) {
  int numBytesRead = 0;
  byte tmp;
  
  Serial.printf("onReceive handler called with %d bytes\n", numBytes);

  // read as many bytes as available
  while(numBytesRead < numBytes) {
    tmp = Wire.read();
    Serial.printf("\tread byte value: %d\n", tmp);
    numBytesRead++;
  }
  
  if(numBytesRead>0) {
    Serial.printf("Received %d bytes over i2c\n\n", numBytesRead);
  }

  // process received bytes
  // ... some code goes here to interpret 5 byte message as MIDI data
  
}

void loop() {
  ;
}
 
Last edited:
And here's a simplified version of the code from the esp32 master, which just blinks the LEDs once per second and sends a 5-byte test message of 1, 2, 3, 4, 5 when the button is pressed.

Code:
// esp32_i2c_test_simplified.ino
// i2c master - runs on esp32 board

#include <Bounce2.h>
#include <Wire.h>

#define TEENSYLC_ADDR     0x33
#define MCP23017_ADDR     0x20
#define BUTTON_PIN        14

uint8_t counter = 0;
unsigned long start_time, current_time;

Bounce button;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  
  // setup MCP23017 as all outputs
  Wire.beginTransmission(MCP23017_ADDR);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // set all of port A to outputs
  Wire.endTransmission();

  pinMode(BUTTON_PIN, INPUT_PULLUP);  
  button = Bounce(BUTTON_PIN, 10);

  start_time = millis();
}

void loop() {
  // communicate with 2 different i2c slaves
  // both of the following work correctly one at a time.
  // but when I attempt both, it locks up  
  
  // blink LEDs using MCP23017 via i2c
  update_LEDs();

  // check for button press, and if so send test message to Teensy LC via i2c
  handle_test_button();
}

void update_LEDs() {
  // blink LEDs using MCP23017 via i2c
  current_time = millis();
  if(current_time - start_time >= 1000) { // update LEDs once per second (1000ms)
    // a simple test that causes the connected LEDs to count in binary
    Wire.beginTransmission(MCP23017_ADDR);
    Wire.write(0x12); // address port A
    Wire.write(counter++);  // value to send
    Wire.endTransmission();

    start_time = current_time;
  }
}

void handle_test_button() {
  // if button was pressed, send test message to Teensy LC via i2c
  if(button.update()) {
    if(button.fallingEdge()) {
      // as a simple test, send the bytes 1, 2, 3, 4, 5
      Serial.println("Sending 5 byte test message");
      
      Wire.beginTransmission(TEENSYLC_ADDR);
      Wire.write(0x01);
      Wire.write(0x02);
      Wire.write(0x03);
      Wire.write(0x04);
      Wire.write(0x05);
      Wire.endTransmission();
    }
  }
}

Running the simplified versions of master and slave code together, the problem still persists. If I press the button just once, with the simple test code, this is what happens on the Teensy serial monitor:
Code:
onReceive handler called with 5 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
Received 5 bytes over i2c

onReceive handler called with 7 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 7 bytes over i2c

onReceive handler called with 9 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 9 bytes over i2c

onReceive handler called with 11 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 11 bytes over i2c

onReceive handler called with 13 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 13 bytes over i2c

onReceive handler called with 15 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 15 bytes over i2c

onReceive handler called with 17 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 17 bytes over i2c

onReceive handler called with 19 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 19 bytes over i2c

onReceive handler called with 21 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 21 bytes over i2c

onReceive handler called with 23 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 23 bytes over i2c

onReceive handler called with 25 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 25 bytes over i2c

onReceive handler called with 27 bytes
	read byte value: 1
	read byte value: 2
	read byte value: 3
	read byte value: 4
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
	read byte value: 5
Received 27 bytes over i2c
Again, the extraneous messages appear on the Teensy monitor once per second, in sync with the messages intended for the LED controller. From this simpler 12345 test, we can see the last byte is just being repeated in the longer and longer messages. It happened to be 0x00 in my earlier test code as a coincidence of the MIDI data I was sending.

If I watch the serial monitor on the esp32 master, it correctly prints "Sending 5 byte test message" exactly once per button press. So I don't think that master code is erroneously retransmitting the test messages. But I also can't see where the slave code is going wrong.

Any ideas?
 
Last edited:
OK, I got this working! The solution was to switch to using the i2c_t3 library for the Teensy code. It appears that i2c slave mode with the better-known Wire.h is not supported on Teensy (?), although this is not documented anywhere I could find other than some forum threads.
 
Status
Not open for further replies.
Back
Top