ADXL345 I2C communication

Hello everyone,

I’m currently working with a 9DOF Razor IMU (https://www.sparkfun.com/products/10736).

On this board an ADXL345 is connected to an Atmega328. The two units communicate through I2C protocol.

The problem is, when I read the content of a register, say (0x00 = device ID), I get 4 bytes returned instead of one.

The ID of the ADXL345 is defined in the datasheet: ID_ADXL:1110 0101

When I read the register I get;

ID_ADXL: 1111 1111 1111 1111 1111 1111 1110 0101

This is how I read the register;

char id_adxl=0;
  id_adxl = i2cRead(adxlAddress, 0x00);
  Serial.print("ID_ADXL: ");
  Serial.println(id_adxl, BIN);

And this is how i2cRead() is defined;

unsigned char i2cRead(char address, char registerAddress)
{
  //This variable will hold the contents read from the i2c device.
  unsigned char data=0;
  
  //Send the register address to be read.
  Wire.beginTransmission(address);
  //Send the Register Address
  Wire.write(registerAddress);
  //End the communication sequence.
  Wire.endTransmission();
  
  //Ask the I2C device for data
  Wire.beginTransmission(address);
  Wire.requestFrom(address, 1);
  
  //Wait for a response from the I2C device
  if(Wire.available()){
    //Save the data sent from the I2C device
    data = Wire.read();
  }
  
  //End the communication sequence.
  Wire.endTransmission();
  
  //Return the data read during the operation
  return data;
}

I don’t understand how these 3 additional bytes are being read in the register?

The ADXL345 supports fast data transfer mode (400kHz) but my arduino Wire.h library is programmed for normal data transfer (100kHz). I thought this could be the reason.

I tried adding:

Wire.begin();
TWBR = 12;

to enable fast transfer mode, but the error remains.

Any idea what I could be doing wrong?

Thank you for reading this.

Vink:
Hello everyone,

I’m currently working with a 9DOF Razor IMU (https://www.sparkfun.com/products/10736).

On this board an ADXL345 is connected to an Atmega328. The two units communicate through I2C protocol.

Thank you for reading this.

You have mis-understood the I2C Wire library.

to send data to an I2C device use :

Wire.beginTransmission(i2cAddr);
Wire.write(byteValue);
Wire.endTransmission(sendStop); //Actually send the buffered data to the Slave. 32 byte limit

   // some devices need a repeated-start between
  // setting the register pointer and the read operation.

To receive data from an I2C device use:

Wire.requestFrom(i2cAddr,numberOfBytes); //actually transfer data from Slave 32byte limit

uint8_t myBuffer[numberOfBytes];
for(uint8_t i=0;i<numberOfBytes;i++){
  myBuffer[i] = Wire.read(); // transfer from internal Wire buffer to my buffer.
  }

when you coded

/Ask the I2C device for data

Wire.beginTransmission(address);        // start Transmit operation
  Wire.requestFrom(address, 1);

//Wait for a response from the I2C device
  if(Wire.available()){                                  // the requestFrom will always return
                                                                // the requested amount or Zero if the Slave
                                                                // does not respond.
    //Save the data sent from the I2C device
    data = Wire.read();
  }

//End the communication sequence.
  Wire.endTransmission();                          // actually send a the Transmit buffer (empty)
                                                              // this just a ‘attention’ call

Try this code as your read code:

/* read byte from device, return error as negative value
*/
int16_t i2cReadByte(uint8_t i2cAddr, uint8_t regAddr){
uint8_t result = 0;
Wire.beginTransmission(i2cAddr);
Wire.write(regAddr);
uint8_t ec=Wire.endTransmission(false); // don't send the stop use restart

if(ec==0){
  ec = Wire.requestFrom(i2cAddr,1);
  if (ec==0) result = -10; // error no data received
  else result =  Wire.read();
  }  
else result = -ec;
return result;
}

chuck.

Eventually the byte is extended to a signed long, when printed?

DrDiettrich:
Eventually the byte is extended to a signed long, when printed?

you are correct, I did not see that.

He must be calling his readByte() like this:

long value = readByte();
// and the complier did a sign extension from a 8bit to 32bit negative value!

// so maybe he could change the definition of readByte() to uint8_t readByte() instead of char readByte().

I am chagrined :wink:

Chuck.

I think that the library only contains one function for outputting a long value. It may help to use "byte" instead of "char" variables.

Thank you very much, changing the datatype to long did it.
I’m not sure I understand why this 8 to 32-bit conversion occured?

Vink:
Thank you very much, changing the datatype to long did it.
I’m not sure I understand why this 8 to 32-bit conversion occured?

we were just guessing, you did not post compilable code.

the 4 byte printout tells us that the compiler thought that the variable was a long (4bytes) and it took the value in the char, treated it as a signed char, a char with the high bit set is considered negative, when a char is expanded to a 4 byte long, the sign bit is used to fill bytes 1…3 of to long. this keeps the value of the long the same as the value of the char.

Base on the code fragments you posted, It should NOT have done that, therefor I speculated what you posted did not actually generate the output you described. I speculated your actual coding was something like this:

char readByte(byte i2cAddress, byte register);
// which would return a value from -128 to 127
// and called it with 
long value;
value = readByte(adxladdr,register);
// the compiler would execute the function, do a type conversion from char to long, since the returned char was negative, do a sign extension and generate B11111111 B11111111 B1111111 B11100101.

// nothing else made sense.

post your actual code so that we can compile it and verify the output.

I may be wrong, but with the info I have, this is the best guess.

Chuck.