potential bug with wire.h, or just my ignorance

matoi

Member
Hi!
Contrary to my wishes, yesterday turned into a debugday. I thought I had partially damaged my T3.6 (it's I2C comms capability).
However, the outcome of the mess was as follows:

Made up a minimalistic breadboard setup to check standard Wire.h I2C communication between Teensy3.6 OR ArduinoUno on one side and a MCP23017 on the other.
Same code (which was derived from something that perfectly worked on T3.6 for many months) worked from Uno, but didn't work from T3.6.
Played with external pull-ups, but no success in making the T3.6 talk to MCP usefully, Uno talks both with MCP powered by 5V or 3.3V, with external pullups or without them.
My reptilian brain reminded me that I've upgraded Teensyduino relatively recently to version Arduino1.8.1 + Teensyduino1.36
So running out of better ideas, this morning I tried switching the code for T3.6 from using <Wire.h> to <i2c_t3.h>,
and the communication between T3.6 and MCP started to work perfectly again, so my T3.6s seem to be in good health :)

Maybe the gurus here will immediately guess what stupid mistake I might have been making,
but if that is not the case, and if it is of any interest (I see teensyduino has further progressed to 1.37 so maybe this is irrelevant already)
I could gather and upload more details (photo of the breadboard setup, and testing code).

I think I'll have no problems with switching the main application to i2c_t3, so intend to use that as a solution for my immediate purpose.

All the best,
Mato

A little later add-it: The main project was moved to i2c_t3 in a matter of minutes and works flawlessly again.
I had to intervene into Adafruit's library for the MPR121 which I'm using too, but that was also very easy because I'm using it from the main project folder.
 
Last edited:
Made up a minimalistic breadboard setup to check standard Wire.h I2C communication between Teensy3.6 OR ArduinoUno on one side and a MCP23017 on the other.
Same code (which was derived from something that perfectly worked on T3.6 for many months) worked from Uno, but didn't work from T3.6.

I can tell you MCP23017 definitely has worked with Teensy 3.6.

In fact, here's a project we built for Maker Faire a couple months ago which used 4 MCP23017 and 4 PCA9685 chips with a Teensy 3.6.

https://www.dorkbotpdx.org/node/1274

https://oshpark.com/shared_projects/jiW2r6f5

https://github.com/PaulStoffregen/MakerFaire2017

I believe you can see in the videos and photos it is indeed able to read all those buttons via the MCP23017 chips!


I could gather and upload more details (photo of the breadboard setup, and testing code).

Yes, this is generally how things work here.

From what you've posted, the best I can say is you must have overlooked something or make some sort of mistake (which nobody can tell from only this message). MCP23017 absolutely does work with the Wire library on Teensy 3.6.
 
Yes, sorry if I wasn't clear as English is not my native language -> I was happily using MCP23017 with T3.6 since my first Teensy arrived,
but the problem may have arisen with Teensyduino upgrade to 1.36. Maybe it's cleared with 1.37, I don't know.
Generally once I'm happy with my setup I'm reluctant to upgrade software out of fear that I'll shake things up,
but I had to reinstall Teensyduino as something got messed up with the computer, and that is how I arrived to 1.36.

But if it's worth looking into this: I've repeated my experiment and cleared the code.
The testing breadboard looks like this:

testingI2C.jpg

Orange should be SCL, green SDA, the resistors are 4.7kOhm,
yellow wire is there for poking around in hope of changing the state of the GPAs...

The Wire.h version of the testing code:

Code:
// This thing is a small test for I2C communication with MCP23017, using <Wire.h>
// Main loop is going to repeatedly read MCP's port A,
// print it's state to serial monitor,
// and if it differs from 255 (which Wire.h returns if I2C comms are dead), it will
// also blink the internal LED 5 times
// Between each loop, the internal LED is blinked once, just to give us a sense of life.

#include <Wire.h>

#define redLED 13

// ################################################################### I2C MICROCHIP ADDRESSES ############
#define MCP_keyMonitor 0x20

// ########################################################### REQUIRED MCP REGISTER ADDRESSES ############
// we're using BANK ZERO addressing mode, IOCON.BANK=0, MCP23017 manual 21952b.pdf page 11
#define IODIRA  0x00
#define IOCON	0x0A
#define GPPUA	0x0C
#define IOPOLA	0x02
#define GPINTENA 0x04
#define INTCONA 0x08
#define DEFVALA 0x06
#define DEFVALB 0x07
#define INTCAPA 0x10
#define INTCAPB 0x11
#define GPIOA	0x12
#define GPIOB	0x13

// ########################################################################################################
// ########################################################################################################
// ########################################################################### M A I N L O O P ############

void loop() {
  byte mcpPortA_state = 0;
    
  mcpPortA_state = expanderRead( GPIOA );

  if( mcpPortA_state != 255 )
      redDebugBlink(5);
  
  Serial.print("GPIOA state is: ");
  Serial.println(mcpPortA_state);
  
  delay(2000);
  redDebugBlink(1);
  delay(2000);
    
}

// ##################################################################################### SETUP ############

void setup() {
  
  Serial.begin(9600);
 
  pinMode( redLED, OUTPUT );
  
  // Start up I2C communication -------------------------------------
  Wire.begin();
  Wire.setClock(400000);
    
  // MCP_keyMonitoring microchip setup -----------------
  expanderWriteBoth(IODIRA, B10111111, B11111111 );
  expanderWriteBoth(GPIOA,  B01000000, B00000000 );
  expanderWriteBoth(IOCON,  B01000000, B01000000 );
  expanderWriteBoth(GPPUA, B00001111, B00000000);
  expanderWriteBoth(IOPOLA, B00001111, B00000000 );
  expanderWriteBoth(GPINTENA, B10001111, B00000000 );
  expanderWriteBoth(INTCONA,  B10001111, B00000000 );
  expanderWriteBoth(DEFVALA,  B10000000, B00000000 );
  expanderRead( INTCAPA );
  expanderRead( INTCAPB );

  redDebugBlink(3);
 
}

// ########################################################################################################
// ################################################################ M C Ps   F U N C T I O N S ############

void expanderWriteBoth
(const byte reg, const byte dataA,
                 const byte dataB ) // set registers "reg" on expander to "data" 
{
  Wire.beginTransmission (MCP_keyMonitor);
  Wire.write (reg);    // assuming reg for portA address is received
  Wire.write (dataA);  // port A
  Wire.write (dataB);  // port B, assuming we have MCP setup into seqOp
  Wire.endTransmission ();
}

// -----------------------------------------------------------------------------

byte expanderRead (const byte reg) // read a byte from the expander
{
  Wire.beginTransmission (MCP_keyMonitor);
  Wire.write (reg);
  Wire.endTransmission ();
  Wire.requestFrom (MCP_keyMonitor, 1);
  return Wire.read();
}

// ############################################################################################ DEBUG STUFF

void redDebugBlink(int repetitions) {
  int i = 0;
  while( i < repetitions ) {
    delay(250);
    digitalWrite( redLED, HIGH );
    delay(250);
    digitalWrite( redLED, LOW ); 
    i++;
  }
}

And <i2c_t3.h> version of the code, almost identical:

Code:
// This thing is a small test for I2C communication with MCP23017, using <i2c_t3.h>
// Main loop is going to repeatedly read MCP's port A,
// print it's state to serial monitor,
// and if it differs from 255 (which indicates unsuccessfull I2C comms), it will
// also blink the internal LED 5 times
// Between each loop, the internal LED is blinked once, just to give us a sense of life.

#include <i2c_t3.h>

#define redLED 13

// ################################################################### I2C MICROCHIP ADDRESSES ############
#define MCP_keyMonitor 0x20

// ########################################################### REQUIRED MCP REGISTER ADDRESSES ############
// we're using BANK ZERO addressing mode, IOCON.BANK=0, MCP23017 manual 21952b.pdf page 11
#define IODIRA  0x00
#define IOCON	0x0A
#define GPPUA	0x0C
#define IOPOLA	0x02
#define GPINTENA 0x04
#define INTCONA 0x08
#define DEFVALA 0x06
#define DEFVALB 0x07
#define INTCAPA 0x10
#define INTCAPB 0x11
#define GPIOA	0x12
#define GPIOB	0x13

// ########################################################################################################
// ########################################################################################################
// ########################################################################### M A I N L O O P ############

void loop() {
  byte mcpPortA_state = 0;
    
  mcpPortA_state = expanderRead( GPIOA );

  if( mcpPortA_state != 255 )
      redDebugBlink(5);
  
  Serial.print("GPIOA state is: ");
  Serial.println(mcpPortA_state);
  
  delay(2000);
  redDebugBlink(1);
  delay(2000);
    
}

// ##################################################################################### SETUP ############

void setup() {
  
  Serial.begin(9600);
 
  pinMode( redLED, OUTPUT );
  
  // Start up I2C communication -------------------------------------
  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000, I2C_OP_MODE_IMM);
  Wire.setDefaultTimeout(200000); // 200ms
    
  // MCP_keyMonitoring microchip setup -----------------
  expanderWriteBoth(IODIRA, B10111111, B11111111 );
  expanderWriteBoth(GPIOA,  B01000000, B00000000 );
  expanderWriteBoth(IOCON,  B01000000, B01000000 );
  expanderWriteBoth(GPPUA, B00001111, B00000000);
  expanderWriteBoth(IOPOLA, B00001111, B00000000 );
  expanderWriteBoth(GPINTENA, B10001111, B00000000 );
  expanderWriteBoth(INTCONA,  B10001111, B00000000 );
  expanderWriteBoth(DEFVALA,  B10000000, B00000000 );
  expanderRead( INTCAPA );
  expanderRead( INTCAPB );

  redDebugBlink(3);
 
}

// ########################################################################################################
// ################################################################ M C Ps   F U N C T I O N S ############

void expanderWriteBoth
(const byte reg, const byte dataA,
                 const byte dataB ) // set registers "reg" on expander to "data" 
{
  Wire.beginTransmission (MCP_keyMonitor);
  Wire.write (reg);    // assuming reg for portA address is received
  Wire.write (dataA);  // port A
  Wire.write (dataB);  // port B, assuming we have MCP setup into seqOp
  Wire.endTransmission ();
}

// -----------------------------------------------------------------------------

byte expanderRead (const byte reg) // read a byte from the expander
{
  Wire.beginTransmission (MCP_keyMonitor);
  Wire.write (reg);
  Wire.endTransmission ();
  Wire.requestFrom (MCP_keyMonitor, 1);
  return Wire.read();
}

// ############################################################################################ DEBUG STUFF

void redDebugBlink(int repetitions) {
  int i = 0;
  while( i < repetitions ) {
    delay(250);
    digitalWrite( redLED, HIGH );
    delay(250);
    digitalWrite( redLED, LOW ); 
    i++;
  }
}

The MCP's registers are left setup as I need them for my main project, but that I guess should not be an issue,
as they are equally set in both cases.

So, without moving any hardware components (except poking the yellow wire to various GPAs and V/Gnd):

<Wire.h> version consistently prints 255 to SerialMonitor, and never blinks the internal LED 5 times

<i2c_t3.h> version blinks the LED 5 times on each loop iteration, and prints various values to SerialMonitor,
as most MCP's pins are left floating.

All the best,
m
 
Last edited:
mcp23017's work fine on teensy 3.5, they are on a shared i2c bus of 12 i2c devices, 6 of which are mcp23017's, using i2c_t3 and direct Wire.* commands, no libraries. If you have an issue, it's probably the "library". :)
 
Ok, I've upgraded to Arduino 1.8.3 + Teensyduino 1.37

The issue was the same...

until it occurred to me that there was also one little change that I made not long ago,
because of another sideproject that is heavy on maths:

I've changed the option under Tools -> Optimize from default "Faster" to "Fastest"

I've put it back now to "Faster", recompiled, uploaded and things seem to work normally with Wire.h,
if I put it again to "Fastest" (recompile and upload) the I2C communication is dead again (with Wire.h)...

So, it seems it's got something to do with that Optimize thing...

All the best,
m
 
Well, shit, no, sorry.

The issue is not gone irrespective of Optimize options.
I'm not sure if I got confused a little while ago when I thought I had it working properly,
or maybe it got correctly compiled immediately after the Teensyduino upgrade
but gets corrupted after a cycle of recompile/uploads...

So to be clear:
Even with 1.37 I can't get it to work properly using <Wire.h>,
with <i2c_t3.h> it works properly with 1.37 (just like before)

The only other I2C device I have is an Adafruit MPR121 touch sensor,
so maybe it's worth noting that I couldn't communicate with it either,
until I switched to <i2c_t3>.

(T3.6 did communicate perfectly with both MCP23017 and MPR121,
using standard <Wire.h> while I was running Teensyduino 1.35)
 
Last edited:
Further update (it seems I wasn't confused two posts above):

I restart the computer,
Open Arduino and carefully select "Faster", then
Compile and upload
-> It works!
(it's the very first compile/upload after Mac restart)

I then switch to "Fastest", compile and upload
-> Doesn't work

Switch back to "Faster", compile and upload
-> Doesn't work!

And all further cycles of Optimize options and recompile/upload attempts
produce nonfunctional version (Wire.h)
 
You really do need to post the complete code to reproduce this problem. I know you're looking to have a conversation here, and that's fine. But please know the way things work (eg, the "Forum Rule") is nobody will actually *do* much to investigate until you share a complete (and ideally minimal) program that can be copied & pasted into Arduino and uploaded to a board to reproduce the issue.
 
You really do need to post the complete code to reproduce this problem. I know you're looking to have a conversation here, and that's fine. But please know the way things work (eg, the "Forum Rule") is nobody will actually *do* much to investigate until you share a complete (and ideally minimal) program that can be copied & pasted into Arduino and uploaded to a board to reproduce the issue.

The complete code was pasted in my second post, thread post #4.
You are right that I would enjoy more conversation with people, but that was not the primary goal here as I don't understand 99% of what you guys usually talk about :)
 
I don't have MCP23017, but do have MCP23018. I ran your Wire.h sketch on T3.5 and T3.6, running IDE 1.18.1/1.36. sketch behaved the same on both. With nothing connected to A side, GPIOA state is: 0
If i jumper 3.3v to GPA7, get GPIOA state is: 128
As i move jumper down A side, i get 64, 32,16, and then 0s

Using i2c_t3.h, behavior is the same on T3.6

optimization was "Faster"

also ran simple sketch with IODIRA at 0xff, and read GPIOA as i moved jumper from 3.3v to each of GPA7 to GPA0, and got 128,64,32,16,8,4,2,1
 
Last edited:
Thanks for the effort manitou. Have you perhaps tried switching the Optimize option?
At the risk of leaving an impression of a psycho,
I've repeated the test with my setup, and everything is perfect if after a fresh restart of the computer I leave the Optimize option at "Faster".
However if I change it, something with the compile/upload gets corrupted and the gadget doesn't work any more - and quit/restart of just the ArduinoIDE doesn't resolve the issue.
I need to restart the complete computer (haven't tried just the logout/login).
So, currently it seems to me it could be either:
- a problem specific to my computer/OS setup, or
- a problem related to Optimize option which maybe goes unnoticed as probably people seldom fiddle with it...
Anyhow, I'll leave this here, if it's of any use fine if not applogies for distracting.
Love my three Teensys and the help I've received from this forum in the past,
so all the best to all...
m
 
Thanks for the effort manitou. Have you perhaps tried switching the Optimize option?

Sketch works with Faster, Fast, and smallest code, BUT fails (returns 255) for Fastest. And as you note, recompiling back to Faster, still fails with 255. However, if i just unplug T3.6 USB and plug it back in, Faster sketch will run correctly with Wire.h.

I think i2c_t3.h has a way to reset the I2C bus that Wire.h does not have. I don't know if i2c_t3 does that reset every time, if so that may be how it clears the problem caused by Fastest ....

EDIT: Fastest also fails on my simpler test sketch with Wire.h. logic analyzer does not even show CLK signal?

your sketch runs ok on i2c_t3 with Fastest

EDIT 2: i installed 1.8.3/1.37, T3.6 with Wire.h still fails with Fastest @180mhz, but now runs @120mhz

EDIT 3: I tested I2C eeprom 24LC128 with T3.6, OK with Fastest@180mhz with i2c_t3.h. Fastest fails with Wire.h @180mhz, but works @120mhz. Faster @180mhz works. So problem is not specific to MCP23017
 
Last edited:
Just to confirm, I have managed to reproduce this bug with a EEPROM chip at Teensy 3.6 with optimize set to Fastest.

I hope to have a fix soon....

DSC_0552_web.jpg

Code:
#include <Wire.h>

#define ADDR 0x50

void setup() {
  Wire.begin();
  while (!Serial) ; // wait
  /*
  Wire.beginTransmission(ADDR);
  Wire.write(0);
  Wire.write("Hello");
  Wire.endTransmission();
  */
  delay(100);
}

void loop() {
  Wire.beginTransmission(ADDR);
  Wire.write(0);
  Wire.endTransmission(false);
  int num = 6;
  Wire.requestFrom(ADDR, num);
  for (int i=0; i<num; i++) {
    Serial.print(Wire.read());
    Serial.print(" ");
  }
  Serial.println();
  delay(50);
}

file.png
 
Back
Top