DUE + 9DOF stick. Values jump from 0 to 255

Hey there,

yesterday arrived my new Arduino DUE board. It´s my first Arduino/Microcontroller that I ever used so I´m not very experienced in Hardware. How ever, I also ordered a Sparkfun 9DOF sensor stick. I soldered some headers on it and connected the 3.3V sensor stick to my 3.3V , GND, SDA (20) and SCL (21) Pins on my DUE board (which also runs on 3.3V) via 30cm cables.

So I figured out how to read the values of the sensors by accessing the different registers. The problem is, that for each axis one of the two registers gives me very abrupt values. Here are some examples from my serial monitor.

!!! these are only the values from one register for each axis. The one whose bits are on the left side (not yet bit shifted).

x y z

GYRO: 254 255 0

GYRO: 255 0 255

GYRO: 255 255 255

GYRO: 3 255 255

GYRO: 0 255 252

GYRO: 254 0 1

GYRO: 250 2 251

I tried it with different data rates. The values from the right side register give me some nice heterogeneous values when I move the stick. This happens for pretty much all of the sensors on the stick. But when I add both of the register´s bits I would end up with values from 0-255 and then something around 65xxx-66xxx or something

I figured out that I could get some much better values for the accelerometer after activating the justify bit in the config register. But right now I´m not sure if these data is useful since I don´t know if this is the way to go. I mean… it´s not a default setting and it´s only available for the accelerometer.

How can this be? Is my Due maybe not suitable for this sensor? I wanted to have more calculation power for further filtering so I took the Due. Is my sensor stick maybe broken? Can this be an I2C issue?

I hope someone can help. I would be very happy!

Cheers,

Michael

It sounds like your code is not handling the recombination of the upper and lower bytes back into a single 16 bit, 2’s compliment word correctly. For small values, the lower byte will read correctly and the upper byte will be all 0’s for a positive number and all 1’s (255) for a negative number. That’s what you’re seeing.

When recombined properly the result is a 2’s compliment number ranging from decimal 32767 (= 0111111111111111b) to -32768 (= 1000000000000000b). A 1111111111111111b is 2’s compliment for a -1 (not decimal 65535). Look familiar ? So I doubt your sensor or Due is at fault. It’s how you, or your code, are interpreting the registers.

http://en.wikipedia.org/wiki/Two%27s_complement

Hey! Thanks for your reply,

I think I´m recombining them properly. But I´m not very experienced with that. So I´m going to explain what I do.

// This is the adress of the accelerometer

#define ADXL345_ADDRESS (0xA6 >> 1)

// XLSB Values start from register 0x32

#define ADXL345_REGISTER_XLSB (0x32)

//Need to set power control bit to wake up the adxl345

#define ADXL_REGISTER_PWRCTL (0x2D)

#define ADXL_PWRCTL_MEASURE (1 << 3)

Then I do the initialization, which works fine

// this is the method I´m invoking for the reading

void read_adxl345() {

byte bytes[6];

memset(bytes,0,6);

//read 6 bytes from the ADXL345

i2c_read(ADXL345_ADDRESS, ADXL345_REGISTER_XLSB, 6, bytes);

//now unpack the bytes

for (int i=0;i<3;++i) {

accelerometer_data = (int)bytes[21] + (((int)bytes[2i + 1]) << 8 ); // shift the MSB part 8 to the left, and then add the other 8 bits
}
}
// this is the method that reads the values from the I2C, pretty straight forward
void i2c_read(int address, byte reg, int count, byte* data) {
int i = 0;
// Send input register address
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
// Connect to device and request bytes
Wire.beginTransmission(address);
Wire.requestFrom(address,count);
// slave may send less than requested
while(Wire.available()) {
char c = Wire.read(); // receive a byte as character
data = c;
i++;
}
Wire.endTransmission();
}
I also looked at both register parts individually. As already mentioned, the 0x32 register gives me a wide range of values. The 0x33 register only 0 and 255. Sometimes a 1 or 254 (I guess this happens because of noise?) but nothing really inbetween.
Thanks and regards,
Michael

Update: works on an arduino uno without code changes. So the stick is fine. But what could be the problem with the due? The wire library? Can my I2C port be broken? Do I need to clock my cpu down somehow? no idea…

I suspect it’s this line, in particular the int() command. The Due is a 32 bit machine so perhaps using an int() does not extend the sign bit for the most significant byte like it does on the 8 bit Uno.

accelerometer_data _= (int)bytes[2*1] + (((int)bytes[2*i + 1]) << 8 ); // shift the MSB part 8 to the left, and then add the other 8 bits_
*```*
*I'm not sure what the answer is given this ...*
*[http://arduino.cc/en/Reference/Int](http://arduino.cc/en/Reference/Int)*
_*On the Arduino Uno (and other ATMega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).*_
_*On the Arduino Due, an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1).*_
_*int's store negative numbers with a technique called 2's complement math. The highest bit, sometimes referred to as the "sign" bit, flags the number as a negative number. The rest of the bits are inverted and 1 is added.*_
_*The Arduino takes care of dealing with negative numbers for you, so that arithmetic operations work transparently in the expected manner. There can be an unexpected complication in dealing with the bitshift right operator (>>) however.*_ 
<em>Combining 2 bytes back into a 2's compliment 16 bit (or 32 bit) "word" is a common operation. Doing this for the Due (or other ARM 32 bit MCU) will be documented somewhere in the Arduino forum. Despite the above, I'd try casting each byte into a 32 bit word using the *word()* or *long()* command in place of the *int()* command in that line of code. Also was the destination variable/array (accelerometer_data[]) declared as a 32 bit length ?</em>

Shouldn’t

(int)bytes[2*1]

be

(int)bytes[2* i]

You always use the second byte (I mean bytes[2]) as least significant byte for each axis. Something goes wrong in this indexing. And depending on how the MSB and LSB are sequenced in the 6-byte array, you may need to shift the even bytes 8 bit higher. Instead of the odd ones. I don’t know how those registers are arranged.

Wow, good catch there ! I completely did not see that.

Mee_n_Mac:
Wow, good catch there ! I completely did not see that.

It helps if you set Windows GUI scaling to 125 % DPI, and zoom in the forum another 50 % with the browser. :slight_smile: …And wear glasses, and be gifted with some autism traits.

It works now! You were right… I was declaring the accelerometerData array as int. It´s now int16_t now and the raw values look pretty good so far!

Your bill is in the mail. :mrgreen: