Pages: 1 2 [3] 4 5   Go Down
Author Topic: New and growing well-documented, feature-complete I2C device library  (Read 19624 times)
0 Members and 1 Guest are viewing this topic.
Roanoke, VA
Offline Offline
Jr. Member
**
Karma: 6
Posts: 66
Creating order out of chaos!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Update on the I2C Device Library repository!

I've been hard at work on the MPU6050 library for the powerful new MEMS chip from InvenSense, and the core functionality is 99% there. I say 99% because everything looks like it should work, and the code is all there, and everything appears to do what it's supposed to and alter or return settings predictably, except...all of my sensor data reads are coming back as zero (which should never be the case, ever, since half the device is an accelerometer). I'm currently trying to nail down why that's happening, but in the mean time, I posted the rest of the code. Once I get it fixed, I'll move on to attempting to support the awesome Motion Fusion stuff that the device can also do, though that will depend on some more documentation from InvenSense.

Also, Andrew Schamp forked the project and added the beginnings of a library for the MPR121 capacitive touch sensor device, which I have just now merged into the master branch. It's not totally complete yet, but it works, and I'll round out the missing bits after I finish the MPU6050 library. Thanks, Andrew!

Back to work...

    Jeff
Logged

Roanoke, VA
Offline Offline
Jr. Member
**
Karma: 6
Posts: 66
Creating order out of chaos!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Another new device just added: the Honeywell HMC5843 3-axis magnetometer.

I had the HMC5883L already, but the HMC5843 is its predecessor and still widely used. I think it's pin-compatible, but the registers and constants are ever-so-slightly different. You could probably use the HMC5883L code with marginal success, but since they are so similar, I decided to take 20 minutes and create a perfectly accurate and specific library for the HMC5843. Main differences in functionality are:

  • 5843 has no sample averaging, while 5883L does
  • 5843 max official data rate is 50Hz, while 5883L is 75Hz
  • 5843 maximum magnetic field gain is +/- 6.8 Ga, while 5883L maximum is +/- 8.1
  • 5843 has Regulator Enabled status detection, while 5883L does not

In short, the 5883L is better all around with the exception of the Regulator Enabled status detection, but I'm not really sure why that feature would be important anyway.

Enjoy, all you HMC5843 users!

    Jeff
Logged

Roanoke, VA
Offline Offline
Jr. Member
**
Karma: 6
Posts: 66
Creating order out of chaos!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I say 99% there because everything looks like it should work, and the code is all there, and everything appears to do what it's supposed to and alter or return settings predictably, except...all of my sensor data reads are coming back as zero (which should never be the case, ever, since half the device is an accelerometer). I'm currently trying to nail down why that's happening.

Success! Thanks to a message through GitHub from someone who mentioned that the device starts up in sleep mode, I tried adding an explicit "disable sleep" call in the initialization routine. Bingo! Now it's reporting accel/gyro data. No 9-axis stuff, and none of that powerful MotionFusion yet, but the basic 6-axis raw data is there and quite functional.

MPU6050 library <- Enjoy! (partially complete)

I still need to finish the 9-axis support and a whole lot of Doxygen comments (which are mostly not there, and the ones that are I just kept from the ITG3200 library that I copied over to get started on the MPU6050. So it isn't done by any means--keep that in mind.

    Jeff
Logged

SoCal
Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Greetings, Jeff, and all,

I've posted about a Non-Blocking version of the Wire library, here:
http://arduino.cc/forum/index.php/topic,70705.0.html

If you'd like to integrate any part of this into your own work, let me know:
Gene@Telobot.com

Thumbs Up!
Gene Knight
Logged

Thumbs Up!
Gene Knight

Worcester, MA
Offline Offline
God Member
*****
Karma: 3
Posts: 623
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think having a one second default is a better idea. It won't block unless the device doesn't respond and in that case does it matter if the error is returned in one second rather than 250ms? (in the previous code, the error condition would cause it to block indefinitely)

The advantage of a longer default time-out is that inexperienced users won't get false errors when using devices that do take longer than 250ms. Experienced users can increase or decrease the time-out if they want, but it seems more friendly to have a default that minimizes the chance that errors could be reported even when the system if functioning correctly. The longer default time-out has no impact on performance on systems where the I2C devices are responding correctly.

The I2Cdev class is ...is designed to be used by device libraries like the ADXL345 class or ITG3200 class. ...The only time anyone has to worry about specific timeout settings is if they are actually writing a new device class, in which case it seems very likely that they would know to specify an extra long timeout value in their "observeTortoiseMarathonPath()" method.

For this reason, it seems more useful overall to have a legitimate failure come back faster rather than slower. But honestly, I'm willing to change it to 1 sec if you would still recommend it in light of the viewpoint I laid out above (and maybe you clearly understood all of that before and my explanation was redundant anyway). No hard feelings in either case; I'm just trying to be diligent.

    Jeff

Certainly no hard feelings, its your library so no-one should begrudge your right to choose the default values you prefer. But I still think  a longer default timeout is better.

(Hopefully) good coders will read the datasheet and determine and set the appropriate timeout. It's the less diligent people using this code on some otherwise unsupported device that can come unstuck. And if they are not careful enough to check that the default value is set correctly they may not be diligent enough to handle the false error if it does timeout.  But go with your instinct on this, I am sure you have more important  things to do than debate this point.

Michael


Unfortunately it doesn't make a difference if you set timeout to 1 microsecond or 3 hours because Wire.requestFrom() is blocking.
Code:
    Wire.beginTransmission(devAddr);
    Wire.requestFrom(devAddr, length);

    uint32_t t1 = millis();
    for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
Logged

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

Albuquerque, NM
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Whew! Glad I found this thread. I was beginning to wonder whether I would have to write everything from scratch, as a number of my devices were not responding with conventional Wire requests. I am currently working on a large project that includes numerous sensors as well as more conventional EEPROM storage. I will be happy to contribute drivers as I can get things working.

Any chance you could take a poke at the Lascar PanelPilot meter? The I2C datasheet was rather challenging to find on their site, but it looks straightforward enough. However, I have so far been unsuccessful in getting the meter to respond.

Datasheet:
http://panelpilot.com/downloads/multi-screen_digital_meter.pdf
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Maybe download the SW and put a sniffer on the line to see what is sent?
- http://panelpilot.com/downloads/index.htm -
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Albuquerque, NM
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The software is designed solely to program the meter, and is connected via USB. You can set the meter's I2C address between 10 and EF.

I talked to one of Lascar's engineers the other day and it looks like the I2C support is rather limited, and its communications protocol is entirely found on that sheet. For the future, they plan to expand and offer additional, more advanced meters, but for now, the meter is rather basic. It is limited by its onboard memory and processing capabilities. What you see is what you get.
Logged

Roanoke, VA
Offline Offline
Jr. Member
**
Karma: 6
Posts: 66
Creating order out of chaos!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've posted about a Non-Blocking version of the Wire library, here:
http://arduino.cc/forum/index.php/topic,70705.0.html

Thanks, Gene! That is a very interesting project. The blocking reads are a bit of a problem with the current TwoWire class, as wayneft pointed out. The new Arduino 1.0 version in development is possibly supposed to address this, but from what I've seen of the code so far, it doesn't look like it does. A non-blocking library could be very useful.

I looked through the examples you wrote (good demos by the way), and I'm not sure how best to implement a fully event-driven approach with the simple I2Cdev layer with reading and writing data. I think it could be done in such a way that the event-driven style is invisible to the device libraries, which would be necessary to keep them simple. It would basically be re-implemented into a library that was blocking except for timeout support...in which case, maybe I should see if I can just do that with your code.

Obviously your name would stay on it if I implement it, but are you fine with releasing it under an MIT (or less restrictive) license? One of my goals with this whole I2Cdev library is to keep everything MIT or better ("better" meaning less restrictive).

Whew! Glad I found this thread. I was beginning to wonder whether I would have to write everything from scratch, as a number of my devices were not responding with conventional Wire requests. I am currently working on a large project that includes numerous sensors as well as more conventional EEPROM storage. I will be happy to contribute drivers as I can get things working.

Thanks! That would be awesome.

Any chance you could take a poke at the Lascar PanelPilot meter? The I2C datasheet was rather challenging to find on their site, but it looks straightforward enough. However, I have so far been unsuccessful in getting the meter to respond.
...
The software is designed solely to program the meter, and is connected via USB. You can set the meter's I2C address between 10 and EF.

That device does look pretty simple from a protocol standpoint. It appears to be write-only, which I guess is how they can get away with allowing I2C addresses all the way up to 0xEF (since typically they only go up to 0x7F, with the 0x80 bit used to indicate reads). I'll see if I can get a quick device library together for you, though it might not be until a little later this weekend.

    Jeff
Logged

SoCal
Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You're welcome to use any of my code as you wish. If there's more or different functionality that you'd like, just let me know.

Thumbs Up!
Gene Knight
Logged

Thumbs Up!
Gene Knight

Albuquerque, NM
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great! I'll be watching your github and trying to develop additional drivers. Non-blocking support would be absolutely amazing.

As I said, I am developing a project with a broad range of sensors (temp, voltage, current, light, etc.) as well as EEPROM and the panel meter mentioned above.

I'll also be happy to contribute some documentation (example code) to help people along. I strongly appreciate the fact that this code is under the MIT license. Thanks for the time and effort you are putting into this!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm thinking this library might just be the ticket as a "standard" for Project STRUIX.  For the time being, I've been focused on hardware and implementing simple examples using the Wire library.  A mid range goal for the project is to implement hardware abstraction such as this.  Great Job!

STRUIX, being an intercommunicating multiprocessor platform, needs to have a more robust I2C library to build from - so I'm definitely going to dive into this further.

Thanks,
Marko

https://sites.google.com/site/projectstruix
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just found these libraries, and they seem like a great alternative too writing my own interface for my devices. I have a Sparkfun SEN-10724 9DOF Sensor Stick with an ADXL345, ITG3200 and HMC5883L devices and will be using a Mega 2560.

My question is would I be able to use the three associated libraries sequentially [ie psuedo-code: adxl.read(), itg.read(), hmc.read()] ? Or would I need to start/stop or set normal/standby each device sequentially while reading?

More pseudo-code to illustrate my point:
Code:
#straight sequential - no start/stop / normal/standby
accelValues = adxl.read();
gyroValues = itg.read();
magValues = hmc.read();

#sequential with start/stop or normal/standby
adxl.setNormal(); //sets device active
accelValues = adxl.read();
adxl.setStandby(); // sets device in standby

itg.setNormal(); //sets device active
gyroValues = itg.read();
itg.setStandby(); // sets device in standby

hmc.setNormal(); //sets device active
magValues = hmc.read();
hmc.setStandby(); // sets device in standby

I'm very new to I2C and trying to wrap my head around things. The latter seems like the correct method, though I am not 100%

Thanks for any help
Logged

Roanoke, VA
Offline Offline
Jr. Member
**
Karma: 6
Posts: 66
Creating order out of chaos!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My question is would I be able to use the three associated libraries sequentially [ie psuedo-code: adxl.read(), itg.read(), hmc.read()] ? Or would I need to start/stop or set normal/standby each device sequentially while reading?

The libraries for all three of those devices each has a read() method (though they are called getAcceleration(), getRotation(), and getHeading() respectively) that handles the specific I2C commands to each device for you, so you don't need to worry about specifically setting normal/standby modes, so hopefully it will be pretty straightforward.

I've been meaning to create simple example sketches for each library to illustrate basic usage, but I haven't quite had time yet. I just finished exhibiting the Keyglove at Maker Faire NYC though, so maybe I'll have a bit of extra time now to finish some of the loose ends on this code. :-)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The libraries for all three of those devices each has a read() method (though they are called getAcceleration(), getRotation(), and getHeading() respectively) that handles the specific I2C commands to each device for you, so you don't need to worry about specifically setting normal/standby modes, so hopefully it will be pretty straightforward.

Were you using a modified Wire library? I'm using the recently released 0022 version and I'm getting errors when compiling about:
Code:
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp: In static member function 'static int8_t I2Cdev::readBytes(uint8_t, uint8_t, uint8_t, uint8_t*, uint16_t)':
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:176: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:183: error: 'millis' was not declared in this scope
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:188: error: 'class TwoWire' has no member named 'read'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp: In static member function 'static int8_t I2Cdev::readWords(uint8_t, uint8_t, uint8_t, uint16_t*, uint16_t)':
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:233: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:240: error: 'millis' was not declared in this scope
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:248: error: 'class TwoWire' has no member named 'read'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:255: error: 'class TwoWire' has no member named 'read'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp: In static member function 'static bool I2Cdev::writeBytes(uint8_t, uint8_t, uint8_t, uint8_t*)':
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:415: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:416: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp: In static member function 'static bool I2Cdev::writeWords(uint8_t, uint8_t, uint8_t, uint16_t*)':
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:460: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:462: error: 'class TwoWire' has no member named 'write'
C:\Users\qql714\Desktop\arduino-0022\libraries\I2Cdev\I2Cdev.cpp:464: error: 'class TwoWire' has no member named 'write'
I have included the I2Cdev.h, Wire.h, Arduino.h, arduino_1280.h, ADXL345.h, ITG3200.h, HMC5883L.h, but am trying to get a working example with the ADXL345 first. It dies at adxl.getAcceleration(accelX, accelY, accelZ); after adxl.initialize();.

Thanks again
Logged

Pages: 1 2 [3] 4 5   Go Up
Jump to: