Teensy 4.1 I2C to Arduino Portenta

Roy86

Member
Hi, long time reader, first time poster.

I purchased a Teensy 4.1 with Audio Shield a while ago and it has been perfect. I recently set it up to accept I2C commands from an Arduino Portenta instead of Serial commands however I cannot get it to function as a slave.

Both the Arduino and the Teensy I2C are 3.3v and I use 4.7K pull ups between the connection.

I loaded the Master script on the Portenta, and the slave script on the teensy to no effect, the teensy reports via serial console that it is just "Waiting..." (see script) but reversing that, it works with the Teensy as the master and the Portenta as the slave. I am at a bit of a loss, any ideas on what I am doing wrong?

Master Script
Code:
#include <Wire.h>

int led = LED_BUILTIN;

void setup()
{
  pinMode(led, OUTPUT);
  Wire.begin();
}

byte x = 0;

void loop()
{
  digitalWrite(led, HIGH);
  Wire.beginTransmission(0x10);
  Wire.write("x is ");
  Wire.write(x);
  Wire.endTransmission();
  digitalWrite(led, LOW);

  Serial.print("x is ");
  Serial.println(x);

  x++;
  delay(500);
}

Slave Script
Code:
#include <Wire.h>

int led = LED_BUILTIN;

void setup()
{
  pinMode(led, OUTPUT);
  Wire.begin(0x10);
  Wire.onReceive(receiveEvent);
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Waiting...");
  delay(1500);
}

void receiveEvent(int howMany)
{
  digitalWrite(led, HIGH);
  while(Wire.available() > 1) {
    char c = Wire.read();
    Serial.print(c);
  }
  int x = Wire.read();
  Serial.println(x);
  digitalWrite(led, LOW);
}

Any help or thoughts are greatly appreciated
 
Last edited:
Indeed Wire in Teensyduino 1.56 only supports master mode.

Slave mode support has been added on github. If you install it, know that it also requires a core library update. Soon we'll be starting beta testing for 1.57, but until then no simple installer exists to give all the updated files easily.
 
Indeed Wire in Teensyduino 1.56 only supports master mode.

Slave mode support has been added on github. If you install it, know that it also requires a core library update. Soon we'll be starting beta testing for 1.57, but until then no simple installer exists to give all the updated files easily.

I've added the updated Wire library with the core update. It looks to be working as planned and I have not required the work around library at all :) This has made using the Audio Library now conflict free without extensive edits.
 
@PaulSoffregen I2C is running ok however I'm getting a lot of bad character read and transmission. I've isolated and tested with Teensy 4.1 and other boards in identical configuration however while all other boards get good clean read-send messages, the teensy 4.1 has a character error rate over 80% of the time.

I2C bridge is 3.3V with 50mm cable to breakout board or direct to pin. Tested with Teensy 4.1 (S), Arduino Nano (S), Uno(S), Jetson Nano (S) with the Portenta as the Master. Tests were in isolation, common bridge and chained via Sparkfun Breakout Boards in various combinations.

Code:
#include <Wire.h>

String sendCache = "QE14,0,0,1";

void setup() {
    Wire.onReceive(onI2Creceieve);
    Wire.onRequest(onI2Crequest);
    Wire.setClock(1000000);
    Wire.begin(0x18);
}

void loop() {
  // put your main code here, to run repeatedly:

}
 
void onI2Creceieve(int howmany){
  Serial.print("Receiving: ");
  while (Wire.available() > 0) 
  {
    char rc = Wire.read();
    Serial.print(rc);
  }
  Serial.println("End");
}

static void onI2Crequest(){
  Serial.println(("Sending: <" + sendCache + ">").c_str());
  byte sendlen = sendCache.length();
  Wire.write(sendlen);
  Wire.write(("<" + sendCache + ">").c_str());
  sendCache = "";
}
 
Last edited:
Could I talk you into trying with 1.57-beta1?

https://forum.pjrc.com/threads/70196-Teensyduino-1-57-Beta-1

If that doesn't solve the problem (odds are it will be exactly the same) then I'm hoping you can give me more specific info about how to set up a test here with Teensy 4.1 and Arduino Portenta?

Which program do I run on each? I see 2 programs on msg #1 and 1 on msg #6. Which do I run on Teensy and which runs on Portenta?

Could you also show me a photo of the wiring, so I connect it the same way you have? If the pullup resistors aren't clearly visible or colors aren't clear in the picture, which resistor values are used? If I dig out that Portenta board and go to the trouble of wiring it up on my workbench, please leave nothing to chance. Let me see exactly how you did it, so I don't waste a lot of time trying the different ways.

Right now this USB host test is on my workbench. If you check out that thread, you can see how sometimes just getting the test setup correct to reproduce a specific problem takes a lot of time. It wasn't until msg #36 on that thread until I was finally able to reproduce the problem. I know a photo and specif detail takes some effort to write here on this forum, but it really does save a lot of time when it comes to reproducing a problem. Just like that communication between Teensy 4.1 and Raspberry Pi Pico, I do want to look into this I2C issue. Please help me with clear & specific info so I can set it up next on my workbench... after I figure out what's going wrong with the USB enumeration on Pico while slowed down with those Adafruit Python libraries.
 
Hi Paul,

Updated to 1.57 and still no luck.

Test setup is msg#1 with the Portenta as the "Master" Script above and the teensy with "Slave" Script. i've attached an image of the teensy on the breakout board connecting to the I2C ports on the Portenta with its breakout board.
What is interesting is if you reverse it and make the Teensy the master and the portenta the slave, the success rate of transmission is much higher.

Teensy as slave: 1%-5% successful read
Portenta as slave: >99% successful read

I do notice that the I2C wires between the teensy 19/18 and the breadboard are very sensitive to possible interference where as using the same wires but on the nano setup I get no issues.
The Nano setup uses the SparkFun Qwiic shield for 3.3v compatibility which have a 4.7kohm pullup. When chaining them all together, only the teensy observes any issues.

Below is the shots of the setup, I've tried various pull ups from 4.7k, 2.2K and (in shot) 470

teensyi2c.jpg portentai2c.jpg
 
@tonton81 Switched it over and repeated the test but got the same results :(

Also I tested directly with Sparkfun I2C shield and same results. Works great as the master, horrible as the slave.

teensyi2cshield.jpg
 
Update: I think it is safe to say this is a user/hardware issue not a software/firmware issue.

I replaced the I2C cables and rewired with untwisted cables between the I2C shields and it is communicating strongly now even as part of a longer chain.

Apologies if I wasted anyones time trying to replicate this. It is all working now.
Thanks for eveyone's support, especially paul. I'm liking 1.57 alot. Keep up the great work.
 
@PaulSoffregen it's worth noting that I still get more errors than other boards but it is massively reduced when shielding the wires and removing nearby potential interference.
 
@PaulSoffregen, I'm stumped as to why this is happening. Board responds to I2C commands when the AudioOutput is PWM or others but not I2S.

On Teensy 4.1 with Audio Shield
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;
//AudioOutputI2S           i2s2;
AudioOutputPWM           i2s2;           
AudioConnection          patchCord1(playSdWav1, 0, i2s2, 0);
AudioControlSGTL5000     sgtl5000_1; 
// GUItool: end automatically generated code

int delayTimer = 0;

int led = LED_BUILTIN;

void setup()
{
  Serial.begin(9600);

  AudioMemory(24);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.6);
  
  Wire.begin(0x30);
  Wire.setClock(400000);
  Wire.onReceive(receiveEvent);
  
  pinMode(led, OUTPUT);
}

void loop()
{
  if(delayTimer<1)
    Serial.print(".");
    
  delayTimer--;
  
  delay(2000);
}

void receiveEvent(int howMany)
{
  if (!Wire.available()) return;
  
  digitalWrite(led, HIGH);
  Serial.print("I2C: ");

  int rcIndex = 0;
  char rcArray[31];
  while (Wire.available() > 0)
  {
    rcArray[rcIndex] = (byte) Wire.read();
    rcIndex++;
  };

  delayTimer = 10;

  Serial.print(rcArray);
  Serial.println(";");
  delay(50);
  digitalWrite(led, LOW);
}

Output when using programed with the PWM output, you can see via serial it is receiving the commands however when I switch to I2Soutput, it does not show the I2C but does run the loop. Board is plugged as in the picture above with the addition of the AudioShield.
 
Last edited:
I replied to your message on the 1.57-beta1 thread, and also posting a followup here.

I added a fix to the Wire library, which turns on the pin's input hysteresis.

https://github.com/PaulStoffregen/Wire/commit/8af68c996d2500c200de3d5cb46e53a27c9c66a8

I've also been doing more testing, with both libraries. Turns out the SCL pin is sensitive to picking up high frequency noise. With hysteresis and a normal I2C pullup resistor (even as high as 10K) I can't get the problem to happen. But if I use analogWriteFrequency for 12 MHz on pin 23, and then I try communication with a Teensy LC using no external pullup resistors at all, the problem returns. And they are able to communicate using only the internal pullup if I turn off the 12 MHz waveform on pin 23.

I also found adding a 22pF capacitor from SCL (pin 19) to GND also allows the 2 boards to communicate without any external pullup resistors, with pin 23 pulsing at 12 MHz. While it's probably overkill if you have a normal resistor in the 1K to 4.7K range, adding a 22pF capacitor might also be a good idea if you want highly robust communication.
 
Hi Paul,

I've completed my tests and the fixed library with the 22pF capacitor on the SCL to GND looks to have resolve that issue. Thank you for working that out! I'm getting good clear comms across the I2C backbone now.
 
Back
Top