Forum Rule: Always post complete source code & details to reproduce any issue!
Page 5 of 26 FirstFirst ... 3 4 5 6 7 15 ... LastLast
Results 101 to 125 of 648

Thread: New I2C library for Teensy3

  1. #101
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Sorry but the i2c_t3 library is only for the Teensy 3.0/3.1 devices. It won't work on AVR parts at all.

    Not sure on your problem without more diagnostics of what is going on. Things that can hang the bus are if it thinks it is busy (SCL held low), or if it is blocked from sending a START/STOP (either SDA or SCL held low). This can happen if the Master/Slaves get out of sync due to missed clocks (bad wiring, bad pullups, etc).

    Another way a Slave can be made to hang the bus is if a Master reads from it, but does not end the read with a NAK. If the Slave outputs a low on SDA as its last output then the bus will hang due to inability of Master to send START/STOP. A poorly made Slave I2C could possibly be made to do this also if it were made to transmit blocks of X bytes, but the Master terminated the read after reading less than X bytes. If you have access to a logic analyzer then a capture might indicate what is going on. If not, then try testing the SDA/SCL to see if either is held low when it gets stuck.

  2. #102
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Thanks for the reply. I think I will try this library and see if I have a different result:

    http://www.dsscircuits.com/images/code/I2C_Rev5.zip

  3. #103
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    That library only works on Atmel chips so will work on a Teensy++2 but not on a Teensy 3.x. It is in fact a very nice library and I've used in previous projects. When you start running out of libraries it's time to really start analyzing the problem
    ;-)

  4. #104
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Unfortunately, I don't have a logic analyzer. Is there no I2C library common to Teensy 3.1 and AVR besides Wire.h? I was able run the LSM9DS0 sensor on both platforms with a sketch that uses the Wire.h library, which is why this glitch on the AK8975A is so frustrating. I'll keep poking around with Wire.h and trying to get it to work. Thanks for your generous help!

  5. #105
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Quote Originally Posted by onehorse View Post
    Unfortunately, I don't have a logic analyzer.
    Do you happen to have a spare Teensy3.1 in addition to your project components? I have an unfinished project which might be able to solve that problem for I2C.

  6. #106
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Yes, I have three Teensy 3.1s. What did you have in mind?

  7. #107
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Ok, I'll PM you the details (it is both unfinished and off-topic for this thread).

  8. #108
    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.

  9. #109
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    I think your problem has to do with whoever named the original Wire library function calls so poorly. The problem you are having may be related to the endTransmission() call depending on how the library functions internally. If it does not clear the Tx buffer after a send, or maintain the Tx buffer index across calls then if you call endTransmission() twice it will send the Tx buffer twice.

    Let me explain the function calls more plainly:
    • beginTransmission() - means initialize the Tx buffer
    • write() - means fill up the Tx buffer with stuff
    • endTransmission() - means send the Tx buffer (note what it does NOT mean - anything to do with Rx)
    • requestFrom() - read stuff from a slave and fill a Rx buffer with it

    This is quite common, people setup Rx functions and then end it with endTransmission(), but it's wrong, Rx functions do not use endTransmission(). It's not your fault, I blame this entirely on the poor naming of the function call.

    Looking at your functions below, try removing the red sections. What may be happening is that the Tx buffer is getting re-sent and that is causing device confusion in your Slaves.

    Quote Originally Posted by onehorse View Post
    Code:
    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  <-- remove this
    
        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();  <-- remove this
    }
    Also, the green sections are wrong for a few reasons:
    • The requestFrom() is a blocking call, it will either fill a Rx buffer or it won't (if it errors out). There is no need to wait by looping on Wire.available().
    • Also in the multi-byte read, this code assumes that the full count was received, but that may not occur:

    Code:
    while (Wire.available() < count);
    if it does not occur it will hang forever waiting for Wire.available() to be equal to count.

    • In both routines, the subsequent code after requestFrom() assumes the Rx buffer was filled, and then stuffs whatever was in it into the return value (or array). If the call errors out the Rx buffer could be partially filled or not filled at all. How this is dealt with varies from program to program, but at minimum what you should do is only fill the return value with whatever was received and do not block waiting for a full return, something like this:

    Code:
        int i=0;    
        Wire.requestFrom(address, count);
        while(Wire.available());
            dest[i++] = Wire.read();  // note this makes the assumption dest[] size is always greater than or equal to count, or it could buffer overrun

  10. #110
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    Thank you for a very clear explanation. I took these functions from Jim Lindblom's LSM9DS0 sketch which works well on both the Arduino and Teensy platforms. That device, like the MPU-9150, has two slaves embedded in one sensor but it must rely on different protocols since it seems to run fine with this coding. I will try your suggestions and let you know how it works. Thank you very much for your help!

  11. #111
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    I changed the Wire.h routines to the following at your suggestion:

    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);
    	data = Wire.read(); // Read register data into `data` variable
    	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
    	int i=0;
            Wire.requestFrom(address, count);
    	while (Wire.available()) {
            dest[i++] = Wire.read(); }
    	// End I2C Transmission
    }
    The accelerometer and gyro readBytes work fine as before, but I am still not able to read the magnetometer without single readByte calls. Did I mis-interpret your suggestions? Thanks again for the help.

  12. #112
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Perhaps I'm missing something here, I pulled a datasheet for a AK8975, and I found the following section on multi-byte I2C (click to expand):

    Click image for larger version. 

Name:	screenshot.322.jpg 
Views:	344 
Size:	150.0 KB 
ID:	1870

    Click image for larger version. 

Name:	screenshot.323.jpg 
Views:	176 
Size:	221.5 KB 
ID:	1871

    Is this the right part? I don't see anything about the 0x80 address modification below. Where is that coming from?

    Quote Originally Posted by onehorse View Post
    Code:
    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
        int i=0;
            Wire.requestFrom(address, count);
        while (Wire.available()) {
            dest[i++] = Wire.read(); }
        // End I2C Transmission
    }
    The way these things usually go, is that if the low-level routines work (as demonstrated by talking to the other components), then there is some higher level comm problem (eg. reading 1 byte of a 3-byte register, parsing multi-byte data backwards out of the buffer, etc). If the 0x80 address modification is necessary can you supply a link to a datasheet showing that? I don't think I've ever seen a part that worked that way.

  13. #113
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    921
    I just blindly (an dumbly, it turns out) copied the wire routines from the LSM9DS0 sketch (https://github.com/sparkfun/LSM9DS0_...FE_LSM9DS0.cpp). In that device's data sheet (https://cdn.sparkfun.com/assets/f/6/1/f/0/LSM9DS0.pdf) we find:

    6.1.1 I
    2
    C operation
    The transaction on the bus is started through a START (ST) signal. A START condition is
    defined as a HIGH to LOW transition on the data line while the SCL line is held HIGH. After
    this has been transmitted by the master, the bus is considered busy. The next byte of data
    transmitted after the start condition contains the address of the slave in the first 7 bits and
    the eighth bit tells whether the master is receiving data from the slave or transmitting data to
    the slave. When an address is sent, each device in the system compares the first seven bits
    after a start condition with its own address. If they match, the device considers itself
    addressed by the master.
    Data transfer with acknowledge is mandatory. The transmitter must release the SDA line
    during the acknowledge pulse. The receiver must then pull the data line LOW so that it
    remains stable low during the HIGH period of the acknowledge clock pulse. A receiver
    which has been addressed is obliged to generate an acknowledge after each byte of data
    received.
    The I
    2
    C embedded inside the LSM9DS0 behaves like a slave device and the following
    protocol must be adhered to. After the start condition (ST) a slave address is sent, once a
    slave acknowledge (SAK) has been returned, an 8-bit sub-address (SUB) will be
    transmitted: the 7 LSb represents the actual register address while the MSB enables the
    address auto increment. If the MSb of the SUB field is ‘1’, the SUB (register address) will be
    automatically increased to allow multiple data read/writes.
    I removed the 0x08 OR and, of course, the multiple byte read now works. Thank you very much for the education. I have usually gotten away with copying commo routines; in the future I will pay more attention to the details, which apparently, and no surprise, matter!

    I would still like to try your logic analyzer if you are still interested.

  14. #114
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    Quote Originally Posted by onehorse View Post

    I would still like to try your logic analyzer if you are still interested.

    +1 That sounds very intriguing

  15. #115
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Quote Originally Posted by Headroom View Post
    +1 That sounds very intriguing
    Yeah I shouldn't have mentioned it. I have a prototype which can do I2C traffic sniffing, but it is part of a larger project which isn't finished. When I get something which is presentable I'll start a new thread on it.

  16. #116
    Senior Member jimmayhugh's Avatar
    Join Date
    Nov 2012
    Posts
    168
    Quote Originally Posted by t3andy View Post
    Good library!
    For a better name that users can relate to "FastWire.h" After all, you did increase the bit-rate up pass the normal bit-rate values.
    Definitely prefer "FastWire" for the library name. Am currently using this library in my TeensyNet Project, and will be using "FastWire" for my library. Already tested both I2C channels with 24LC512s and MCP23017s.

  17. #117
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,059
    if you name it "WireFast" or some other name where the first 4 characters are "Wire", then it'll show up next to Wire in the File > Examples menu, and in alphabetically ordered lists on websites. Seems like that might help people see there's an alternative.

  18. #118
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    This is like the topic that won't die. Ok fine, I really don't have a strong opinion on the name (you guys do realize this only affects one #include line right? Usage is still Wire/Wire1).

    I'll roll in wireFast on the next update, which will come out as soon as I figure out all the priority stuff.

  19. #119
    I am using this library to talk with a IR sensor. Everything does work fine on the standard I2C pins 18 + 19.
    However, if I want to use pin 29 & 30 on my teensy 3.1 instead (SDA to 30, SCL to 29), the sensor is not responding any more.
    What I did on software side is to switch pin mode inside the constructor from "I2C_PINS_18_19" to " I2C_PINS_29_30" and change "Wire" against "Wire1".
    Have I missed something, like altering pin registers anywhere else in order two activate I2C on 29 & 30 ?

  20. #120

    I2C on pins 29 & 30

    I am using this library to talk with a IR sensor. Everything does work fine on the standard I2C pins 18 + 19.
    However, if I want to use pin 29 & 30 on my teensy 3.1 instead (SDA to 30, SCL to 29), the sensor is not responding any more.
    What I did on software side is to switch pin mode inside the constructor from "I2C_PINS_18_19" to " I2C_PINS_29_30" and change "Wire" against "Wire1".
    Have I missed something, like altering pin registers anywhere else in order two activate I2C on 29 & 30 ?

  21. #121
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Quote Originally Posted by maxbot View Post
    I am using this library to talk with a IR sensor. Everything does work fine on the standard I2C pins 18 + 19.
    However, if I want to use pin 29 & 30 on my teensy 3.1 instead (SDA to 30, SCL to 29), the sensor is not responding any more.
    What I did on software side is to switch pin mode inside the constructor from "I2C_PINS_18_19" to " I2C_PINS_29_30" and change "Wire" against "Wire1".
    Have I missed something, like altering pin registers anywhere else in order two activate I2C on 29 & 30 ?
    I would check the following:


    • Since Wire1 uses the SMT pads on the back, make sure the electrical connection to the pads is good. The SMT pads are easy to damage, so make sure not to twist or pull the wires.
    • If you are using external pullups, make sure they are connected to pins 29/30 also. It will not work without pullups. Make sure the pullup voltage is correct.
    • Make sure to change all Wire to Wire1, including Wire1.begin(), and all later function calls. If you are using both Wire and Wire1, make sure they both have setup(), and double check the function calls.
    • Use a voltmeter to verify pullup voltages on pins 29/30. If you have a logic analyzer or scope, use it to verify traffic on pins 29/30.
    • This is obvious, but make sure it is not a Teensy 3.0 (it does not have a Wire1 interface).
    • Check the error results of the function calls. If the connection is electrically bad the functions will error out or hang (the bus can hang if the pullups are missing).
    • If the calls appear to work, it could be that the slave is NAK'ing, or otherwise non-responsive. If the code is not setup to detect bad responses (eg. assumes all responses are correct), then it won't be immediately obvious. Again, check error results and verify response lengths from the Slaves.


    If the code changes are correct then there is likely some electrical connection problem.

  22. #122
    Just saw this and is soooo nice

    Is it Still up? I got the 6b version that seems like the latest and I'm gonna try it out now. Amazing! Why you didn't host it on google code?

  23. #123
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Yes the download links should work. In the next round of updates I might put it on github, but at the moment it is only hosted on the forum. Version 6b is currently the latest. I have some updates planned, but nothing newer is ready just yet.

  24. #124
    Your library Solved all My troubles with I2c and Teensy 3.1.

    http://forum.pjrc.com/threads/25844-...ained-Attiny85

    THANK YOUUUUUU

  25. #125
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    415
    Great, good to hear that it worked for you.

Posting Permissions

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