Explaination of I2C?

Hello! I've just started out with arduino and nowI've come to the tricky I2C communication.
I've read several tutorials but some of them simplify it a litle too much but this one was good Live Fast - Code Young: ADXL345 accelerometer breakout board + Arduino and Processing.
I understand almost everything but got I got some questions
In the end of the tutorial we come to the Void loop() which looks like this:
Live Fast - Code Young: ADXL345 accelerometer breakout board + Arduino and Processing
what I dont understand is when he starts to convert the 10 bytes into 8? why and how does he do that?
What has the Sprintf() command to do with that?
the other question I have is, how does the buff array work? it can hold 6 values so does he pass 2 in byte per axis to it?

thanks so much for the help! I really appreciate it! :slight_smile:
/A

Here is what I understand from a quick look on the URL you provided. A byte is about 8 bits. You can treat a byte as an integer as long as you don't go beyond 255. i.e.

byte bNum = B10001000; //144 in binary
int iNum = bNum; // no worries here

However, in the compiler we're using with Arduino, an int actually takes up 2 bytes. i.e.
byte bNum = B10001000;
int iNum = bNum; //iNum is now B0000000010001000

More info on the int available here: http://arduino.cc/it/Reference/Int. I won't go into more detail about the sign bit etc.

Now, in the URL you posted, he says the data from the accelerometer is 10 bits. Since a byte is only 8 bits, you need 2 bytes to store the 10 bits. buf is an array of bytes that gets filled sequentially. So, if the accelerometer returns 2 bytes for each axis, a total of 6 bytes, all of them get stored in buf. So buf[0] gives the first 8 bits of the first axis, buf[1] gives the next 8 bits, of which we're only using 2. Here's an example for one axis:

accelerometer x-axis value = B0110001000 --> 10 bits
Gets broken up into:
buf[0] = B10001000 --> 8bits
buf[1] = B00000001 --> 8bits

(int)buf[1] << 8 will give you B00000001 00000000 --> 16bits
Doing a bit OR with buf[0] gives:
((int)buf[1] << 8 ) | buf[0] B00000001 00000000 | B00000000 10001000 = B00000001 10001000

Effectively creating an integer with 2 bytes. You can read more about bitmath over here: Arduino Playground - BitMath

Explaination of I2C? ==> Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

First of all thanks for the reply! really good!
I just wonder a few things,

plastygrove:
byte bNum = B10001000; //144 in binary
int iNum = bNum; // no worries here

the binary number 10001000 isn't it decimal number 136? It doesn't really matter but just to make sure i read binary numbers right.

.
Now, in the URL you posted, he says the data from the accelerometer is 10 bits. Since a byte is only 8 bits, you need 2 bytes to store the 10 bits. buf is an array of bytes that gets filled sequentially. So, if the accelerometer returns 2 bytes for each axis, a total of 6 bytes, all of them get stored in buf. So buf[0] gives the first 8 bits of the first axis, buf[1] gives the next 8 bits, of which we're only using 2. Here's an example for one axis:
accelerometer x-axis value = B0110001000 --> 10 bits
Gets broken up into:
buf[0] = B10001000 --> 8bits
buf[1] = B00000001 --> 8bits

So the buf array simply just cuts it of right after 8 bit and continues at the next one. So if we read them each at the time and add them together we will get the wrong number. So when adding two bytes together how do we now which one is the first and second part?

. (int)buf[1] << 8 will give you B00000001 00000000 --> 16bits

how does the bitmath works,
the (int) says that it will create and integer (2 bytes = 16 bits)? the buf[1] gives the first 8 bits ans the << 8 tells to add 8 bits with value 0? Am I right at any point? :slight_smile:
and of course what does the | Or function mean?
thanks you so much for explaining as easy as you do, very educational :slight_smile:

the binary number 10001000 isn't it decimal number 136? It doesn't really matter but just to make sure i read binary numbers right.

Ah Yes, you're right it's 136, my bad :slight_smile:

So the buf array simply just cuts it of right after 8 bit and continues at the next one. So if we read them each at the time and add them together we will get the wrong number. So when adding two bytes together how do we now which one is the first and second part?

Good question. So you come to the part of understanding how your accelerometer actually sends data. This can vary from component to component, so you will always have to read the datasheet to understand exactly how it's sent. The accelerometer in the example will send them. Take a look at page 32 in the datasheet over here. The image shows how the 10bit data is stored in two 1-byte registers on the ADXL345. The code sample requests 6 bytes starting from address 0x32 to be stored in buf. So, it just iterates along the registers and copies them into buf in order.

Highly recommend reading the datasheet for any component you use. There's a lot to learn from there.

the (int) says that it will create and integer (2 bytes = 16 bits)? the buf[1] gives the first 8 bits ans the << 8 tells to add 8 bits with value 0? Am I right at any point?

Almost right there. Just that <<8 shifts 8 bits to the left. By left, I mean towards the higher significant bits. When you shift them to the left, old bits on the left are pushed out into space and discarded and new bits on the right default to 0.

If you'd like to start getting your hands dirty on some advanced stuff on the arduino, you'll need to be good at bit math. I would strongly suggest reading the bitmath article I posted earlier. It covers all the basics that you encounter on a regular basis. I don't want to go further into bitshifting or how the OR works because it's explained very well in the article. :slight_smile:

Btw, so far, we haven't talked about I2C. For that, I would second the link given by robtillaart, very good and detailed explanation by Nick Gammon with code samples. Also, this video by Jeremy Blum[/url] is a pretty good intro to I2C

.

So the buf array simply just cuts it of right after 8 bit and continues at the next one. So if we read them each at the time and add them together we will get the wrong number. So when adding two bytes together how do we now which one is the first and second part?

Good question. So you come to the part of understanding how your accelerometer actually sends data. This can vary from component to component, so you will always have to read the datasheet to understand exactly how it's sent. The accelerometer in the example will send them. Take a look at page 32 in the datasheet over here. The image shows how the 10bit data is stored in two 1-byte registers on the ADXL345. The code sample requests 6 bytes starting from address 0x32 to be stored in buf. So, it just iterates along the registers and copies them into buf in order.

As I said before thanks for your replies! :slight_smile:
just two last question! I took a look at the datasheet, it feels like it's written in a quite complicated way but I'll try. However the register map says that two registers are assigned to the x-axis both 0x32(x data0) and 0x33(x data1). So the x data 0 holds the first 8 bits of the x axis and the x data1 holds the next two bits or do i mix it up? why would it be two x axis data then?

how does the Aaccelerometer know that it should send 5 registers data after 0x32 is it because the code request 6 bytes and then it must be one byte from 0x32 one from 0x33 and so on..?

thanks so much!

Actually, in I2C the master sends a write command to the slave, telling the slave which address to "move it's pointer to". Then the master can perform a read request. The master can then cycle the clock line to receive a byte from the slave at the pointer address that it commanded to the slave. The slave increments the internal register address automatically in case the master wants additional data. As long as the master sends an aknowlege bit during a byte transfer, it can continue to cycle the SCL to receive successive bytes.

This is the intentional design of data transfer in I2C.

Archelon:
how does the Aaccelerometer know that it should send 5 registers data after 0x32 is it because the code request 6 bytes and then it must be one byte from 0x32 one from 0x33 and so on..?

Actually, in I2C the master sends a write command to the slave, telling the slave which address to "move it's pointer to". Then the master can perform a read request. The master can then cycle the clock line to receive a byte from the slave at the pointer address that it commanded to the slave. The slave increments the internal register address automatically in case the master wants additional data. As long as the master sends an aknowlege bit during a byte transfer, it can continue to cycle the SCL to receive successive bytes.

This is the intentional design of data transfer in I2C.

I took a look at the datasheet, it feels like it's written in a quite complicated way but I'll try.

Datasheets are complicated. But keep reading datasheets for every IC or component that you come across and pretty soon, you'll learn how to screen out all the unnecessary stuff in the datasheet and just look for what you need.

So the x data 0 holds the first 8 bits of the x axis and the x data1 holds the next two bits or do i mix it up? why would it be two x axis data then?

It's not 2 x-axis data, it's just one. Again, more details are probably available in the datasheet. But the accelerometer requires 10 bits of data to correctly explain the x-axis value. Similarly for y and z-axes. 10 bits just don't fit in a byte which is 8 bits. Hence the need for 2 bytes. The remaining 6 bits in the higher byte are probably not used.

how does the Aaccelerometer know that it should send 5 registers data after 0x32 is it because the code request 6 bytes and then it must be one byte from 0x32 one from 0x33 and so on..?

It doesn't know that it should send 5 registers data. It knows that it should send 6 bytes starting with register 0x32 upto 0x37. And this has to do with the I2C implementation. You'll need to read up in depth on that, but otherwise, in the code example, the number of bytes to return is given by TO_READ.