New I2C library for Teensy3

Hi,

I have a Teensy 3.1 and I am using this library to read gyro and accelerometer values from a MPU-9150.

I works just fine right after the code has been downloaded to the Teensy, but the values become incorrect (constant zero) if I switch to external power or unplug and reinserts the USB power. SDA and SDL signals are similar in both cases, so I suspect the issue to be timing related.

This is the code used to retrieve the 7bit value from the MPU-9150:

Code:
int16_t MPU9150_readSensor(int addrL, int addrH){
  Wire.beginTransmission(MPU9150_I2C_ADDRESS);
  
  Wire.write(addrL);
  Wire.endTransmission(I2C_NOSTOP);
  Wire.requestFrom(MPU9150_I2C_ADDRESS, 1, I2C_STOP);
  
  byte L = Wire.read();

  Wire.beginTransmission(MPU9150_I2C_ADDRESS);
  Wire.write(addrH);
  Wire.endTransmission(I2C_NOSTOP);

  Wire.requestFrom(MPU9150_I2C_ADDRESS, 1, I2C_STOP);
  while (Wire.available() < 1);
  byte H = Wire.read();
  return (H<<8)+L;
}

Do you have any idea what could be causing this issue? Or know if there is way to reset the Teensy every time is powers on?

Thanks
 
Hi,
I works just fine right after the code has been downloaded to the Teensy, but the values become incorrect (constant zero) if I switch to external power or unplug and reinserts the USB power. SDA and SDL signals are similar in both cases, so I suspect the issue to be timing related.

I'm not sure, perhaps the MPU9150 needs time to reset/restart after the power supply change. You might try dumping the status after a transfer to get more information:

Code:
[COLOR=#ff0000]void print_i2c_status(void)
{
    switch(Wire.status())
    {
    case I2C_WAITING:  Serial.print("I2C waiting, no errors\n"); break;
    case I2C_ADDR_NAK: Serial.print("Slave addr not acknowledged\n"); break;
    case I2C_DATA_NAK: Serial.print("Slave data not acknowledged\n"); break;
    case I2C_ARB_LOST: Serial.print("Bus Error: Arbitration Lost\n"); break;
    default:           Serial.print("I2C busy\n"); break;
    }
}[/COLOR]

int16_t MPU9150_readSensor(int addrL, int addrH){
  Wire.beginTransmission(MPU9150_I2C_ADDRESS);
  Wire.write(addrL);
  Wire.endTransmission(I2C_NOSTOP);
  [COLOR=#ff0000]print_i2c_status();[/COLOR]
  Wire.requestFrom(MPU9150_I2C_ADDRESS, 1, I2C_STOP);
  [COLOR=#ff0000]print_i2c_status();[/COLOR]

  byte L = Wire.read();

  Wire.beginTransmission(MPU9150_I2C_ADDRESS);
  Wire.write(addrH);
  Wire.endTransmission(I2C_NOSTOP);
  [COLOR=#ff0000]print_i2c_status();[/COLOR]

  Wire.requestFrom(MPU9150_I2C_ADDRESS, 1, I2C_STOP);
  [COLOR=#ff0000]print_i2c_status();[/COLOR]
  while (Wire.available() < 1);
  byte H = Wire.read();
  return (H<<8)+L;
}
 
Why do you read sequentially and not both data bytes with one Wire.read? This is the equivalent read I am using. It is similar but I am reading multiple bytes, up to 14, with the same read call:

Code:
        void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{  
	Wire.beginTransmission(address);   // Initialize the Tx buffer
	Wire.write(subAddress);            // Put slave register address in Tx buffer
	Wire.endTransmission(I2C_NOSTOP);  // Send the Tx buffer, but send a restart to keep connection alive
	uint8_t i = 0;
        Wire.requestFrom(address, count);  // Read bytes from slave register address 
	while (Wire.available()) {
        dest[i++] = Wire.read(); }         // Put read results in the Rx buffer
}
 
I started using the i2c_t3 wire library and everything is working well, except I am getting some compile warnings:

Code:
In file included from MPU6050IMU.ino:29:0:
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h: In function 'uint8_t readByte(uint8_t, uint8_t)':
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h:592:19: note: candidate 1: size_t i2c_t3::requestFrom(int, int)
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h:590:19: note: candidate 2: size_t i2c_t3::requestFrom(uint8_t, size_t)
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h: In function 'void readBytes(uint8_t, uint8_t, uint8_t, uint8_t*)':
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h:592:19: note: candidate 1: size_t i2c_t3::requestFrom(int, int)
C:\Documents and Settings\Kris\My Documents\Arduino\libraries\i2c_t3/i2c_t3.h:590:19: note: candidate 2: size_t i2c_t3::requestFrom(uint8_t, size_t)
Binary sketch size: 37,560 bytes (of a 262,144 byte maximum)
Estimated memory use: 5,436 bytes (of a 65,536 byte maximum)

Any idea what it is unhappy about?
 
Just answered my own question. Apparently I needed to change the uint8_t to size_t in the request from call.
 
Just answered my own question. Apparently I needed to change the uint8_t to size_t in the request from call.

Right, I use size_t for indexes to allow it to use large memory buffers. Using a uint8_t as the buffer index would limit it to 256 byte buffers.
 
I designed an add-on for Teensy 3.1 that solders onto the back surface pads. Before I soldered the first successful prototype I tested it on a breadboard using I2C pins 16&17; everything works. Then I "dry" mounted it on the back pads and rewrote the sketch I have been using to use Wire1 everywhere I had Wire and set the I2C pin designation to I2C_PINS_29_30. I could get no Serial output; usually, with a sensor attached to the Teensy or not, I expect to get a Serial message that the WHO_AM_I register is 0xFF or the correct value. I tried using a brand new Teensy and an old Teensy 3.1 workhorse, I tried both dry mounting the sensor board and using a bare Teensy all with the same null results. After I changed the settings back to Wire.begin(...I2C_PINS_16_17,..) and Wire for Wire1 everywhere, I got the Serial output I expected both with no sensor attached and with. So my question is, how well vetted is the Wire1 mode and the use of the I2C_PINS29_30? I can't seem to get it to work.
 
So my question is, how well vetted is the Wire1 mode and the use of the I2C_PINS29_30? I can't seem to get it to work.

I've used Wire1 on pins 29/30 many times. The included dual_bus_master_slave and quad_master sketches were done using it and I tested those up to max rate. I would recommend using a simple sketch like the mentioned examples to see if the pins toggle at all (ideally using a scope, analyzer, or I2C traffic analyzer). If your sketch has additional complexity it could be interfering in other ways (priority levels, etc). Make sure I2C_BUS_ENABLE is set to 2 in the i2c_t3.h header file.
 
Thanks, I'm glad it's me and not the library! I'll take your advice and try it with a simple program using the dual_bus_master_slave and quad_master sketches as a guide and report on what I find. I suspect it is this:

Make sure I2C_BUS_ENABLE is set to 2 in the i2c_t3.h header file.

that is tripping me up.
 
Last edited:
It looks like the I2C_BUS_ENABLE defaults to 2 in the v6b 12c_t3.h library so that wasn't the problem. Instead, it was that I had no external pullups on SDA/SCL even though I was asking for them in the Wire1 call. I got everything to work once I figured this out; the little sensor board is happily i2c-ing away on the back Teensy 3.1 pads! Thanks for such a great library, without it I wouldn't have been able to finish this part of the project.
 
It looks like the I2C_BUS_ENABLE defaults to 2 in the v6b 12c_t3.h library so that wasn't the problem. Instead, it was that I had no external pullups on SDA/SCL even though I was asking for them in the Wire1 call. I got everything to work once I figured this out; the little sensor board is happily i2c-ing away on the back Teensy 3.1 pads! Thanks for such a great library, without it I wouldn't have been able to finish this part of the project.
Glad you got it working. I've been soldering right angle headers to the back of the Teensy on my test boards and using the master/slave function - very useful library.
 
Agreed. I have LSM9DS0 and MPU9250 sensor read/fusion programs that run with i2c_t3 on Teensy 3.1 if you are interested. Most are on GitHub.
 
Instead, it was that I had no external pullups on SDA/SCL even though I was asking for them in the Wire1 call.

Ah, the "pullups don't materialize when I summon them" problem, I think we have all run into that bug. Good to hear you got it working.
 
Is there a repository of libraries that have been changed from using Wire to using i2c_t3?

I ask as I've been using the Adafruit FRAM board and library. Switching this from Wire to i2c_t3 and implementing multiple byte reads and writes increased the speed by a factor of 300.

So how best to share this changed code?
 
I'd say post your code on Github and provide a link to this thread in the readme and perhaps in your code as a comment.
 
Perhaps in the same way Jeff Rowberg et al. have been trying to collect sketches for various sensors using their i2cdev.h library, it would make sense to have a dedicated i2c_t3.h library repository. I have several sketches that use i2c_t3.h; they are all on github but sorted by sensor or device not library. Maybe more generally it would make sense to have a Teensy-3.1-specific repository.
 
Yes, a dedicated repository seems like the best option to me.

I personally don't have time to host that and will put my code up on my BitBucket (git does my head in), but would be keen to contribute to a repository.
 
Guys, if you can provide a link and description I can add it to the top post. Perhaps a "compatible libraries" section at the end of the post.
 
Hi Nox771,

Just wanted to thank you for your efforts. I recently switched to the new I2C library for humidity and temperature measurements (Si7021, HTU21) and everything worked as expected. No compile errors, etc. Next steps may include stepping up the bus speed to 400 to reduce the time the I2C interrogation of the sensor takes. But that presumes this non-CS grad will figure out a good non-blocking approach to extracting the info and turn off the internal heater also. Maybe use Metro as a quasi RTOS? Anyhow, that's for me to figure out.

Your efforts are super appreciated since they 'just work' and are easy to adopt.
 
Hi Nox771,

Just wanted to thank you for your efforts. I recently switched to the new I2C library for humidity and temperature measurements (Si7021, HTU21) and everything worked as expected. No compile errors, etc. Next steps may include stepping up the bus speed to 400 to reduce the time the I2C interrogation of the sensor takes. But that presumes this non-CS grad will figure out a good non-blocking approach to extracting the info and turn off the internal heater also. Maybe use Metro as a quasi RTOS? Anyhow, that's for me to figure out.

Your efforts are super appreciated since they 'just work' and are easy to adopt.

Sure, glad it works well for you. Always better to hear that than bug reports. I do have more things I want to do with the library, but recently I've been overloaded with day job stuff, so unfortunately will take longer...
 
Back
Top