apparent bug in wire library (i2c_t3) with Teensy 3.5

Status
Not open for further replies.

Fenichel

Well-known member
I am trying to use a BMP085 pressure/temperature sensor with a Teensy 3.5. The BMP085 is on a Sparkfun board (their SEN-09694), connected through a level shifter (SparkFun BOB-11955). The code I'm using is from AdaFruit. To reduce complexity, I've merged the AdaFruit code into one program instead of using #includes, and I've eliminated some AdaFruit code that is not relevant.
This works perfectly when the connection is made through the default I2C lines (pins D18 & D19), but it fails when I use the I2C lines at D03 & D04. In other words, the attached code fails (it does not find the expected 0x55 in the ChipID register) when the asterisk-heavy lines in
Code:
bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode)
  {
    // Enable I2C
    Wire.setSDA(pinBMP085SDA);  // Teensy-specific ************************
    Wire.setSCL(pinBMP085SCL);  // ..              ************************
    Wire.begin();
 
    /* Mode boundary check */
    if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0))
      {   mode = BMP085_MODE_ULTRAHIGHRES;  }

    /* Make sure we have the right device */
    uint8_t id;
    read8(BMP085_REGISTER_CHIPID, &id);
    if (id != 0x55)
      {  return false;  }

    _bmp085Mode = mode;

    readCoefficients(); // coefficients need to be read once 

    return true;
  } // Adafruit_BMP085_Unified::begin(bmp085_mode_t mode)
are left in place and the BMP085 is at D03 & D04, but it works when those lines are commented out and the sensor is moved to D18 & D19. Is there a known fix?
 

Attachments

  • sensorapi.ino
    24.3 KB · Views: 62
The sparkfun library is based on Wire lib, but you have also included i2c_t3.h library which is not compatible with Wire.h -- you can't use them both in one sketch. For example, the begin() for each library differs, for i2c_t3.h, you specify alternate SDA/SCL pins in the begin() call. Read the documentation and choose one and carefully edit the sketch. I would stick with the Sparkfun default Wire lib and get rid of i2c_t3 references ... there could be other problems with your "reduced complexity"

pins 3 and 4 are on I2C2 on T3.5, so your Wire.xxxx() calls need to be Wire2.xxxx()
 
The sparkfun library is based on Wire lib, but you have also included i2c_t3.h library which is not compatible with Wire.h -- you can't use them both in one sketch. For example, the begin() for each library differs, for i2c_t3.h, you specify alternate SDA/SCL pins in the begin() call. Read the documentation and choose one and carefully edit the sketch. I would stick with the Sparkfun default Wire lib and get rid of i2c_t3 references ... there could be other problems with your "reduced complexity"

pins 3 and 4 are on I2C2 on T3.5, so your Wire.xxxx() calls need to be Wire2.xxxx()

Thanks for your quick response.

I had not run across any mention of Wire2 before, but it makes sense, analogous to Serial1, Serial2, etc. After a quick look, I don't see where any of the Wire<n> entities are declared; are they present whenever one includes the Teensy version of Wire.h?

I had had the impression that i2c_t3 was a drop-in replacement, but obviously that's not true.
 
source search shows Wire2 in these two files for current Teensy:
...\hardware\teensy\avr\libraries\Wire\WireKinetis.cpp:
...\hardware\teensy\avr\libraries\Wire\WireKinetis.h:

i2c_t3 uses the same hardware generally to the same net effect - with some alternate/added Teensy specific features.

@manitou's note was that when doing include of i2c_t3.h the include of wire.h must be removed.
 
Teensy library code providing i2c services

This situation is messier than I had thought. There are at least 3 Teensy library packages providing I2C services. The AdaFruit code to control the BMP085 makes explicit use of a Wire object, and it expects that object to have methods write(unsigned char), endTransmission(unsigned char), and requestFrom(unsigned char, unsigned char, unsigned char) (the "old methods").
  1. Wire.h/Wire.cpp is the old package. Its TwoWire class has setSDA and setSCL methods, but the implementations of those methods are empty. It defines a TwoWire instance called Wire. If my code
    • #includes Wire.h
    • adds calls to setSDA and setSCL to the AdaFruit code to control the BMP085
    then my code compiles, but because the setSDA & setSCL calls have no effect, the AdaFruit code cannot talk to any I2C device that is not connected to the default pins (on Teensy 3.5, D18 & D19).
  2. WireKinetis.h/Wirekinetis.cpp is newer. Its TwoWire class has nondegenerate setSDA and setSCL methods, and in the Teensy 3.5 environment it defines TwoWire instances called Wire, Wire1, Wire2, and Wire3. Its write, endTransmission, and requestFrom methods take uint8_t arguments instead of unsigned chars. if my code
    • #includes WireKinetis.h
    • adds calls to setSDA and setSCL to the AdaFruit code to control the BMP085
    then my code does not compile, because of the missing old methods.
  3. i2c_t3.h/i2c_t3.cpp is the new, Teensy 3.5-specific package. The i2c_t3 class has nondegenerate setSDA and setSCL methods, and it defines i2c_t3 instances called Wire, Wire1, Wire2, and Wire3.
    if my code
    • #includes i2c_t3.h
    • adds calls to setSDA and setSCL to the AdaFruit code to control the BMP085
    then my code compiles, but the setSDA and setSCL calls don't work to make the Wire object use pins other than those of Wire1.

Is there a non-ugly option? I think I may be stuck with generating
  • my own version of WireKinetis.h, to provide the old methods
  • my own version of the AdaFruit BMP085 code, replacing Wire by Wire2
Neither of those tasks will be intellectually demanding, but I'm disappointed that I can't see any better way to finish off this tiny piece of a much bigger project.
 
Last edited:
solved

A good solution turns out to be
  • to not use Wire.h
  • to not use WireKinetis.h
  • to use i2c_t3.h
  • to not use setSDA or setSCL, and
  • to revise the Adafruit BMP085 code, replacing every instance of Wire with Wire2
This solution won't allow my code to switch easily among two or more BMP085s on different I2C interfaces, but I don't anticipate that need.
 
A #define Wire Wire2 in the code/.h worked for the one I tried - when swapping in i2c_t3.h and removing the wire.h include
 
A #define Wire Wire2 in the code/.h worked for the one I tried - when swapping in i2c_t3.h and removing the wire.h include

I thought of that, but I dislike using #defines to do more than set parameters. Using them to change the meaning of code makes me nervous. It's just a matter of style.
 
Status
Not open for further replies.
Back
Top