Erratic I2C Values
John Board
Posts: 371
G'day,
This is my first time coding I2C stuff, so please excuse my ignorance.
I've been writing some code for the HMC5883L Magnomometer using this arduino example code as my template:
And using the following guide to learn I2C:
http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
With my minimal I2C skills I've tried to clone it, and this is what I've come up with:
I am getting readings, however the readings are erratic, the base line values I'm getting are:
However, the values are constantly jumping to:
Every time the loop updates it switches between the two.
What am I doing wrong? Do I need to set the register pointer back to the start? It might be worth pointing out that this device automatically increments the I2C register every time I read.
The documentation for the device can be found here:
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Magneto/HMC5883L-FDS.pdf
Any help is appreciated!
Thanks,
-John
This is my first time coding I2C stuff, so please excuse my ignorance.
I've been writing some code for the HMC5883L Magnomometer using this arduino example code as my template:
/* An Arduino code example for interfacing with the HMC5883 by: Jordan McConnell SparkFun Electronics created on: 6/30/11 license: OSHW 1.0, [URL]http://freedomdefined.org/OSHW[/URL] Analog input 4 I2C SDA Analog input 5 I2C SCL */ #include <Wire.h> //I2C Arduino Library #define address 0x1E //0011110b, I2C 7bit address of HMC5883 void setup(){ //Initialize Serial and I2C communications Serial.begin(9600); Wire.begin(); //Put the HMC5883 IC into the correct operating mode Wire.beginTransmission(address); //open communication with HMC5883 Wire.send(0x02); //select mode register Wire.send(0x00); //continuous measurement mode Wire.endTransmission(); } void loop(){ int x,y,z; //triple axis data //Tell the HMC5883 where to begin reading data Wire.beginTransmission(address); Wire.send(0x03); //select register 3, X MSB register Wire.endTransmission(); //Read data from each axis, 2 registers per axis Wire.requestFrom(address, 6); if(6<=Wire.available()){ x = Wire.receive()<<8; //X msb x |= Wire.receive(); //X lsb z = Wire.receive()<<8; //Z msb z |= Wire.receive(); //Z lsb y = Wire.receive()<<8; //Y msb y |= Wire.receive(); //Y lsb } //Print out values of each axis Serial.print("x: "); Serial.print(x); Serial.print(" y: "); Serial.print(y); Serial.print(" z: "); Serial.println(z); delay(250); }
And using the following guide to learn I2C:
http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
With my minimal I2C skills I've tried to clone it, and this is what I've come up with:
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ I2C: "I2C" Serial: "FullDuplexSerial" Settings: "Settings" PUB Main Serial.start(31, 30, 0, 9600) Serial.str(string("I2C Test", 13)) i2c_init i2c_loop PUB i2c_init Serial.str(string("Initalizing Compass...", 13)) I2C.Initialize(Settings#IMU_SCL) I2C.Start(Settings#IMU_SCL) 'Send start I2C.Write(Settings#IMU_SCL, $3C) 'Write address I2C.Write(Settings#IMU_SCL, $02) 'Select mode register I2C.Write(Settings#IMU_SCL, $00) 'Set continuous measurement mode I2C.Stop(Settings#IMU_SCL) 'Send stop Serial.str(string("Initalized!", 13)) PUB i2c_loop | x, y, z Serial.str(string("Entering loop", 13)) repeat I2C.Start(Settings#IMU_SCL) 'Send start I2C.Write(Settings#IMU_SCL, $3C) 'Write address I2C.Write(Settings#IMU_SCL, $03) 'Select register 3, X MSB register I2C.Start(Settings#IMU_SCL) 'Send reset I2C.Write(Settings#IMU_SCL, $3D) 'Write address x := I2C.Read(Settings#IMU_SCL, 0) << 8 x |= I2C.Read(Settings#IMU_SCL, 0) y := I2C.Read(Settings#IMU_SCL, 0) << 8 y |= I2C.Read(Settings#IMU_SCL, 0) z := I2C.Read(Settings#IMU_SCL, 0) << 8 z |= I2C.Read(Settings#IMU_SCL, 0) I2C.Stop(Settings#IMU_SCL) Serial.tx(16) Serial.dec(x) Serial.tx(13) Serial.dec(y) Serial.tx(13) Serial.dec(z) Serial.tx(13) waitcnt(clkfreq/2+cnt)
I am getting readings, however the readings are erratic, the base line values I'm getting are:
61438 44800 2817
However, the values are constantly jumping to:
11 495 65199
Every time the loop updates it switches between the two.
What am I doing wrong? Do I need to set the register pointer back to the start? It might be worth pointing out that this device automatically increments the I2C register every time I read.
The documentation for the device can be found here:
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Magneto/HMC5883L-FDS.pdf
Any help is appreciated!
Thanks,
-John
Comments
What this means is that you need to extend the 16-bit value to a long by using the ~~ operator.
I am using the HMC5883L quite a bit and am interested in getting stable readings too.
Yes, you do have to reset the register pointer to the X register at he beginning of each read (by the way the read order is X, Z, Y for some reason).
I did not see your settings object but assume you have selected two pins other than 28 and 29 for your I2C bus: the Parallax board already has pull-ups on it. I am not sure this makes much of a difference since the I2C spec allows a range of resistor values.
I tend to see sporadic reading from these modules from time to time and am trying to figure out why. You have to be careful to keep all stray fields to a minimum (this can also mean watching out for any ferromagnetic materials around the detector).
I have some working code I can post if you are still unable to get reasonable numbers.
Regards
Thanks for the help, I'll imlement all of this in a sec!
I'd be interested to see your code. I may or may not use it, I'll try to get mine working first, but I'm still interested to see what you've come up with.
-John
I've modified my code to look like this:
I'm using ports 22-23 (SCL/SDA) of the prop. I think the values I'm getting aren't electronic related, I think it's programming related. When I tilt the robot one way, it's fine, when I tilt the other way, the readings get all funny.
Normal readings when tilting one way:
Funny readings are all over the place, but here's an example:
But its jumping all over the place. My guess is it's something to do with how the prop handles the numbers it's getting. Any ideas though? I've no clue what to do!
-John
It's working now! Thank you very much for your help in getting my first dabblings in I2C working!
-John
I don't have one of those devices, but I knocked up an object for it earlier today -- if you would, give this a whack and let me know if works (please). Note that this is just the object and I2C code; you'll need to instantiate it and call the methods from your program.
The rd_xyz() method will read all three values with one call. Spin methods can only return one long so you need to pass pointers (the address of) the variables you want to update. For example:
Of course, this assumes you've created and started an object called compass.
G'day,
Working well! Thanks! Just realized that I probably won't be using the compass though! I'm actually using the SparkFun 9DOF stick, so it has the Gyro and Accelerometer on it too, when I was working out the I2C code I figured the compass would be the easiest. Doesn't matter though, this did teach me how to use I2C, and I should be able to write the Gyro and Accel code without too much hastle.
As I said, the code you wrote is working well, and here's the code I wrote:
Thanks again for all your help!
-John
[EDIT]
Put a profiler on the rd_xyz, and it comes back at about 3ms.
I2C is awesome once you get it working. I always seem to struggle a little at first with every new device, but eventually it rocks. It doesn't help that I use multiple masters (Propeller, Arduino, mbed, etc.) with different libraries. Nothing is better than a logic analyzer when working on this stuff. Saves me *so* much time.
anyway best of luck!
Michael
I'm with you: my I2C object (provided with the HMC5883L object above) also obeys those rules.