Understanding and Converting 2's Complement into Decimal for ITG3205 Gyroscope

I've been working on this for a couple days now and have finally been able to read values from my ITG3205 on my Arduino Uno. The problem I am having now is that, even when looking at example sketches from other individuals and reading the sensor datasheet, I do not understand how to convert the 2's complement 16-bit data into a decimal value. The most prevalent conversion code I have found is as follows:

result[0] = ((buff[2] << 8) | buff[3]) + g_offx;
result[1] = ((buff[4] << 8) | buff[5]) + g_offy;
result[2] = ((buff[6] << 8) | buff[7]) + g_offz;
result[3] = (buff[0] << 8) | buff[1]; // temperature

I have read up on 2's complement on wikipedia and several other sources, but I do not understand exactly what this code is doing. In the same order, the bytes being read refer to the following per the data sheet:

TEMP_OUT_H/L 16-bit temperature data (2’s complement format) (buff[0] and buff[1])
GYRO_XOUT_H/L 16-bit X gyro output data (2’s complement format) (buff[2] and buff[3])
GYRO_YOUT_H/L 16-bit Y gyro output data (2’s complement format) (buff[4] and buff[5])
GYRO_ZOUT_H/L 16-bit Y gyro output data (2’s complement format) (buff[6] and buff[7])

Can someone please help me understand what is happening? When I output the raw values that were read from the sensor, before any conversion, I got as follows. I would greatly appreciate some guidance.

X: 9 255
Y: 253 255
Z: 251 194 (I'm ignoring the temp data for now)

Thanks in advance!

Your description completely contradicts what the code (what there is of it) is actually doing.

TEMP_OUT_H/L 16-bit temperature data (2’s complement format) (result[0] and result[1])

Ahhh. your comment is wrong, it should say:

TEMP_OUT_H/L 16-bit temperature data (2’s complement format) (buff[0] and buff[1])

 result[0] = ((buff[2] << 8) | buff[3]) + g_offx;

The sensor values are read one byte at a time and have to be reconstructed into a 16-bit integer. result[0] is a 16-bit number which is constructed of buff[2] as its high-order byte and buff[3] as the low order byte. The result is a signed twos-complement 16-bit integer which you can print as Serial.println(result[0]).

You don't need to convert to decimal, Serial.println does that for you. Internally, Arduino's integers are 16-bit twos-complement anyway.

Pete

Sorry for my misprint, I'll fix it. Even if Serial.print() converts it into decimal for me, I will be wanting to use the values later on in the code. I am attempting to write code for a quadcopter (and happily failing miserably :D). I think I understand most of what you're saying...

But do you mean that buff[2] is simply the first 8 bits of the 16? So that concatenating the two bytes would give me the value I want? My difficulty is stemming from not understanding what this means. And in the example code, I would think that the bit-wise shift operator is only acting on 8 bits, wouldn't it therefore end up as all 0's? For example,
if I had a byte x = 00000010 and I did

result[0] = (x<< 8)

would I not end up with result[0] = 00000000? Because they were all shifted off the end of the byte as it were.

And then what exactly does ((buff[2] << 8) | buff[3]) accomplish?

But do you mean that buff[2] is simply the first 8 bits of the 16? So that concatenating the two bytes would give me the value I want?

Yes.

There is never any need to convert anything into decimal. the computer always used 2's complement numbers when it stores an int value.

And then what exactly does ((buff[2] << 8 ) | buff[3]) accomplish?

It takes the contents of buffer[2] and shifts to the left 8 times, so the bottom 8 bits become zero. Then it performs a logical OR with this number and buff[3], thus combining two 8 bit values into one 16 bit value.
With buff[2] being the upper 8 bits and buff[3] being the lower 8 bits.

Thank you, this is certainly making more sense. Another question I'm having.. When I read off the raw data as I showed earlier, my two X bytes were 9 and 255, correspondingly
00001001 and 11111111. Then per the shift, buff[2] would become
0000100100000000 and buff[3] would stay the same. Then with the (bitwise or logical?) OR, you would have

0000100100000000 | 11111111 = 0000100111111111........Right? which corresponds to 2559 in decimal. But when the program does the conversion, it gets closer to 10. Is this because the second byte is changed out of 2's complement?

Is this because the second byte is changed out of 2's complement?

No. I presume it is because adding the value of g_offx is enough to change the result significantly.

two X bytes were 9 and 255, correspondingly

Which way round are they received? If the 9 is the LOW order byte, then the result is 0xFF09 which is -247.

You need to know the value of g_offx before you can correctly interpret the result of

result[0] = ((buff[2] << 8) | buff[3]) + g_offx;

Pete

Ah. Got it. Thank you again for all of your help!