Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

Thread: Wire on Teensy 3.1

  1. #1
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921

    Wire on Teensy 3.1

    I rewrote an Arduino sketch that used a simple I2C.h TWI library to use the Wire.h library instead. The sketch doesn't work on the Teensy 3.1 with the I2C.h library. When I tried to use it on the Arduino, the device kept cycling when it hit the wire.begin() and never got into the void loop. Does this have something to do with the 10 k pull-up resistors on the sensor breakout board I am using? I know there is some issue with Wire.h and external pullups but I really don't understand it. Should I expect the Wire.h library to work better with the Teensy 3.1? I guess I should have tried it before posting, sorry. I want to be able to run sketches both on the Arduino 3.3 V 8 MHz Pro Mini and the Teensy 3.1. Which I2C library is recommended for such compatibility? Thanks for your help!

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,837
    Wire.h works fine on my Teensy 3.0's for the devices I've tested it with (Adafruit MCP23008/MCP23017, random i2c 16x2 LCD, 0.96" Oled display, PCF8591). Note, I do have 4.7K pull-up resistors installed for both SDA (A4) and SCL (A5), as was recommended by Paul S. a year ago. With the resistors in place on the Teensy, I run the same code on my 3.3v Teensy 3.0 and my 5v Arduino Uno R3 (all of my devices work with both voltages, though for the LCD, I need to feed it 5v for the backlight).

  3. #3
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Thanks for the reply Michael. I will try Wire.h on the Teensy. It certainly must work since that is what I used to talk to the LSM9DS0. Even though I am using a 3.3V Pro Mini, do I have to disable the internal SDA and SCL pullups when using Wire.h? Do you have any idea what might be causing the repeated cycling behavior? It was almost as if the reset were being set low repeatedly. All of the sensors I2C slaves have 10k pullups on the breakout boards. Do I still need 4k7 external pullups on the I2C wires with the Teensy?

  4. #4
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,837
    On the Teensy 3.x, I don't believe there are any internal SDA/SCL pullups (that's why you need the external pullups). Various AVR processors do have the pullups, and the library enables them by default on those systems. There is an alternative i2c library for the Teensy that is faster, and allows you to have more control, but so far, I haven't really used it. IMHO, the Arduino IDE makes it hard to use separate libraries based on processor #ifdef's, as it tries to protect the user from having to learn how to properly setup forward references in C++.

  5. #5
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Thanks for your advice on the uint32_t type. That did the trick. I rewrote the I2C for Wire.h and the sketch works on both the 3.3V 8 MHz Pro Mini and the Teensy 3.1. Unfortunately on both I can no longer read from or write to the magnetometer even though I can read from its WHO_AM_I register. I set the digitalWrite(SDA, LOW) and digitalWrite(SCL, LOW) to disable internal pullups (even though the Teensy has none). Is there something about the Wire.h data speed that would prevent me reading from a slave I2C device in a bypass mode through another slave device?
    Last edited by onehorse; 04-22-2014 at 05:43 PM.

  6. #6
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    This article should answer most, if not all of your questions: http://www.gammon.com.au/forum/?id=10896

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,532
    Quote Originally Posted by onehorse View Post
    I rewrote an Arduino sketch that used a simple I2C.h TWI library to use the Wire.h library instead. The sketch doesn't work on the Teensy 3.1 with the I2C.h library.
    Can you post a link to where you downloaded this library?

    I know there are several still out there with AVR stuff hard-coded. Since Wire and i2c_t3_lib work great, fixing those lesser-used I2C libs is a lower priority. But I'll at least put it on my list of libraries to someday patch.



    Quote Originally Posted by onehorse View Post
    Unfortunately on both I can no longer read from or write to the magnetometer even though I can read from its WHO_AM_I register.
    If you can post the code, maybe someone will be able to see what's wrong?


    I set the digitalWrite(SDA, LOW) and digitalWrite(SCL, LOW) to disable internal pullups (even though the Teensy has none).
    On Teensy 3.1, the pins get configured for which thing they connect to inside the chip. When configured for I2C, the GPIO has no effect on the pins. Using digitalWrite does nothing to the pin if I2C has control of it. Using pinMode will reconfigure the pin to connect to GPIO, taking it away from the I2C port.

    If you're used to AVR, where GPIO still has some effect on the pins even when they're in use by a peripheral, this might seem strange. But pretty much all modern chips work this way, where you configure which thing inside the chip controls the pin. When the pin is connect to the I2C, it can't be accessed as GPIO.

  8. #8
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Excellent article. Thanks. I still don't know why the I2C.h library I used successfully on the Pro Mini doesn't work (won't compile) on the Teensy 3.1. I'll post a copy of it as per Paul's request.

    Also, I believe the failure to communicate with the AK8975A has to do with the lack of support in Wire.h for multiple restarts, which I really don't understand yet.

    Thanks for the replies and the help everyone!
    Last edited by onehorse; 04-22-2014 at 05:43 PM.

  9. #9
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Hi Paul,

    You can find the I2C.h library I am currently using here:

    https://github.com/kriswiner/MMA8452Q

    This is an Arduino sketch I wrote for the 3.3 V 8 MHz Pro Mini. When I use the same I2C TWI for the MPU-9150 sensor, it works fine on the Pro Mini, but the Teensy complains that IIRC TWBR is undefined in this scope. This could just mean that I need to define it as uint8_t or something. I haven't played around with it yet.

    I have run into some discussions that seem to indicate the AK8975A requires a multiple restart capability unsupported by Wire.h. I need to recheck the data sheet. Is this the reason I can't talk to this sensor with Wire.h on the Pro Mini (or Teensy) but I2C.h works just fine? Sorry for the newbie questions. If its any consolation to the valuable time you are spending to help me, I am learning a lot! Thanks again for your help.

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,532
    Yup, that i2c.h file is hard-coded for AVR chips. For example:

    Code:
    void i2cSendStop(void)
    {
    // transmit stop condition
            TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    }
    All the code in that file will need to be rewritten. That's unlikely to happen anytime soon, if ever, but I'll put this one on my list of incompatible libraries to someday look into....

    Code:
    I have run into some discussions that seem to indicate the AK8975A requires a multiple restart capability unsupported by Wire.h
    Long ago, Wire didn't support repeated start. It was added a couple years ago.

  11. #11
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Paul,

    Any idea why I can read from/write to the AK8975A in bypass mode with the I2C.h library but not with Wire.h?
    I can try another I2C library also like:

    http://forum.pjrc.com/threads/21680-...ry-for-Teensy3

    or

    http://www.dsscircuits.com/index.php...ry#comment-611

    or

    http://www.i2cdevlib.com/docs/html/_...8h_source.html

    Do you have a recommendation? I would like to maintain compatibility between Arduino and Teensy, if possible. Thanks.

  12. #12
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    Quote Originally Posted by onehorse View Post
    read from/write to the AK8975A in bypass mode
    What is bypass mode ?
    I've read many I2C spec sheets including the initial spec by Phillips. I have not come across this terminology.

  13. #13
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    The Invensense MPU-9150 (and -9250) is a 9DoF motion sensor that combines a 6 DoF gyro/accelerometer, the MPU-6050, with an Asahi Kasei AK8975A hall-sensor magnetometer into a single device. The microcontroller can access the magnetometer directly by placing the combined MPU-9150 device into a bypass mode through a CNTL register write that connects the internal AK8975A device to the MPU-9150 TWI bus. It is then directly addressed through its own 7-bit device address just like any other I2c device on the bus. This works perfectly well for the simple I2c.h and I2cdev.h TWI libraries but for some reason, when using Wire.h, the AK8975A is no longer accessible after the initial read of its WHO_AM_I register. This latter behavior is seen on both a 3.3V 8 MHz Pro Mini and on the Teensy 3.1. Does anyone have an idea what could be happening here?
    Last edited by onehorse; 04-22-2014 at 08:45 PM.

  14. #14
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    Aha. It is very device specific. Paul has mentioned an alternative I2C library specifically for Teensy3.1
    While using that library may not automatically address your concern I suggest posting your question in that libraries specific thread
    The author of that library is user nox771 and he appears to have a wealth of knowledge in respect to I2C (amongst other things). He may be able to answer your question.

  15. #15
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Thanks, I forwarded the above message to the I2c_t3 discussion thread.

  16. #16
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Just an update on Wire.h with Teensy 3.1 (and 3.3 V 8 MHz Pro Mini Arduino). I replace the multiple byte read with several single byte reads and now everything works. This is passing strange since the multiple byte read seems to be getting data from one I2C slave but not the other. I suspect it has to do with having enough delay time to get all the data but I don't understand this library wellenough to know how to test that idea. I'm hoping someone with more experience can see what the problem is now that I have a little more info.

    Here is the byte read part of the code I am using:
    Code:
      if(readByte(AK8975A_ADDRESS, AK8975A_ST1) && 0x01) { // wait for magnetometer data ready bit to be set
    //  readBytes(AK8975A_ADDRESS, AK8975A_XOUT_L, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
      rawData[0] = readByte(AK8975A_ADDRESS, AK8975A_XOUT_L);
      rawData[1] = readByte(AK8975A_ADDRESS, AK8975A_XOUT_H);
      rawData[2] = readByte(AK8975A_ADDRESS, AK8975A_YOUT_L);
      rawData[3] = readByte(AK8975A_ADDRESS, AK8975A_YOUT_H);
      rawData[4] = readByte(AK8975A_ADDRESS, AK8975A_ZOUT_L);
      rawData[5] = readByte(AK8975A_ADDRESS, AK8975A_ZOUT_H);
      destination[0] = (int16_t)((rawData[1] << 8) | rawData[0]) ;  // Turn the MSB and LSB into a signed 16-bit value
      destination[1] = (int16_t)((rawData[3] << 8) | rawData[2]) ;  
      destination[2] = (int16_t)((rawData[5] << 8) | rawData[4]) ;

    and here are the readByte calls to the Wire.h library:

    Code:
    void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
    {
    	// Begin transmission at device write address
    	Wire.beginTransmission(address);
    	Wire.write(subAddress); // Write register to be written to
    	Wire.write(data); // Transmit byte to write
    	Wire.endTransmission(); // End I2C transmission
    }
    
    uint8_t readByte(uint8_t address, uint8_t subAddress)
    {
    	uint8_t data; // `data` will store the register data
    	// Begin I2C transmission using device write address
    	Wire.beginTransmission(address); 
    	// Write the register to be read:
    	Wire.write(subAddress);	
    	// End write, but send a restart to keep connection alive:
    	Wire.endTransmission(false);
    	// Transmit device read address:
    	Wire.requestFrom(address, (uint8_t) 1);
    	while (Wire.available() < 1) // Wait until data becomes available
    		;
    	data = Wire.read(); // Read register data into `data` variable
    	Wire.endTransmission(); // End I2C transmission
    
    	return data; // Return data from register
    }
    
    void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
    {  
    	// Begin I2C transmission and send device address
    	Wire.beginTransmission(address);
    	// Next send the register to be read. OR with 0x80 to indicate multi-read.
    	Wire.write(subAddress | 0x80);
    	// End write, but send a restart to keep connection alive:
    	Wire.endTransmission(false);
    	// Request `count` bytes of data from the device
    	Wire.requestFrom(address, count);
    	// Wait until the data has been read in
    	while (Wire.available() < count)
    		;
    	// Store all `count` bytes into the given destination array.
    	for (int i=0; i<count ;i++)
    		dest[i] = Wire.read();
    	// End I2C Transmission
    	Wire.endTransmission();
    }
    Would a delay inserted into the readBytes function cure this problem?

    Thanks for your help.

    PS: This problem has been resolved. It has to do with poorly constructed Wire.h calls. See this thread if interested:

    http://forum.pjrc.com/threads/21680-...ry-for-Teensy3
    Last edited by onehorse; 04-24-2014 at 04:34 PM. Reason: problem resolved

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •