2015/06/27

How to use ADXL345 Triple Axis Accelerometer

This is a brief summary of my findings about ADXL345 Triple Axis Accelerometer.

There are at least 2 different kinds of breakout board for ADXL345. One of them can be represented by the one from Sparkfun.

https://www.sparkfun.com/products/9836

The other one can be represented by the one found on many e-commerce sites such as ebay.

http://www.ebay.com/itm/1pcs-ADXL345-Digital-Output-Tilt-Sensor-Accelerometer-Module-/281520781365?pt=LH_DefaultDomain_0&hash=item418bf23835

Aside from the obvious difference in the look, the major difference can be observed by looking at their schematics.

Here is the schematic for the one from Sparkfun.



Here is the schematic for the other one found on ebay.


A quick reference to the ADXL345 datasheet we could have the below findings:

1. The Sparkfun board takes 2.0 - 3.6V DC as supply voltage. The one on ebay has on board regulator which enables the board to take 5V DC as supply voltage.

2. The Sparkfun board supports either SPI or I2C, while the other one only supports I2C.


3. The board from ebay has a fixed I2C address of 0x53 (followed by the R/W bit) because the ALT ADDRESS pin (Pin 12) is fixed to the ground. Hence, it's using address 0xA6 for write and address 0xA7 for read.

Because of the difference in communication interface (SPI vs I2C), there are 2 different codes for using the board.

For SPI, Sparkfun provides an excellent quick start guide complete with wiring instruction and sample code. These info. can be found at https://www.sparkfun.com/tutorials/240.

For I2C, there are several good sites on the internet with lots of useful info. Below is a quick summary of what I got from them.

I2C Wiring

Assuming Arduino is used, we could use its Wire Library for I2C communication. In order to use the library, please follow the info. on https://www.arduino.cc/en/Reference/Wire to wire SDA and SCL of the breakout board to the corresponding pins on the Arduino board.



Since I am using Arduino Uno, here is how the wiring is made between Arduino Uno and the breakout board.



I2C Sample Code

#include <Wire.h>

byte DEVICE_ADDRESS = 0x53; //This address is fixed for the board we use because pin 12 is fixed to GND

byte POWER_CTRL = 0x2D;    //Power Control Register
byte DATA_FORMAT = 0x31;   //Data Format & Measurement Range Register

byte DATAX0 = 0x32;        //X-Axis Data 0
byte DATAX1 = 0x33;        //X-Axis Data 1
byte DATAY0 = 0x34;        //Y-Axis Data 0
byte DATAY1 = 0x35;        //Y-Axis Data 1
byte DATAZ0 = 0x36;        //Z-Axis Data 0
byte DATAZ1 = 0x37;        //Z-Axis Data 1

byte values[10];
int x,y,z;

void setup() {
  Wire.begin();    //Initiate the Wire library and join the I2C bus as a master. This is called only once.
  Serial.begin(9600);
  writeRegister(DEVICE_ADDRESS, DATA_FORMAT, 0x01); //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the register.
  writeRegister(DEVICE_ADDRESS, POWER_CTRL, 0x08); //Put the ADXL345 into Measurement Mode by writing the value 0x08 to the register.
}

void loop() {
  readRegister(DEVICE_ADDRESS, DATAX0, 6, values);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  x = ((int)values[1]<<8)|(int)values[0];
  //The Y value is stored in values[2] and values[3].
  y = ((int)values[3]<<8)|(int)values[2];
  //The Z value is stored in values[4] and values[5].
  z = ((int)values[5]<<8)|(int)values[4];

  //Below is an optional section, it maps the raw output to a different range.
  //  x = map(x, -150, 150, 0, 255);
  //  y = map(y, -150, 150, 0, 255);
  //  z = map(z, -150, 150, 0, 255);
  //End of optional section.

  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);
  delay(10);
}

void writeRegister(byte device, byte registerAddress, byte value) {
  Wire.beginTransmission(device);    //Start transmission to device
  Wire.write(registerAddress);       //Specify the address of the register to be written to
  Wire.write(value);                 //Send the value to be writen to the register
  Wire.endTransmission();            //End transmission
}

void readRegister(byte device, byte registerAddress, int numBytes, byte *values) {

  byte address = 0x80|registerAddress;
  if (numBytes > 1) address = address|0x40;

  Wire.beginTransmission(device);
  Wire.write(address);
  Wire.endTransmission();

  Wire.beginTransmission(device);    
  Wire.requestFrom(device, numBytes);  //Request 6 bytes from device

  int i = 0;
  while (Wire.available()) {          //Device may send less than requested
    values[i] = Wire.read();          //Receive a byte from device and put it into the buffer
    i++;
  }
  Wire.endTransmission();
}

To do list:
1. Calibration;
2. Converting raw output to other units (G, etc.)
3. Exploring other features of ADXL345: 1-Tap, 2-Tap, Free Fall, etc.

Reference:
- https://www.sparkfun.com/tutorials/240
https://www.youtube.com/watch?v=Qhw2wgsKDuI
- http://www.analog.com/en/products/mems/mems-accelerometers/adxl345.html#product-overview
- https://learn.adafruit.com/adxl345-digital-accelerometer
http://electronics.stackexchange.com/questions/94573/getting-adxl345-accelerometer-to-work-over-spi-with-arduino-uno
http://codeyoung.blogspot.tw/2009/11/adxl345-accelerometer-breakout-board.html

7 comments:

  1. thank you very much , i would like to know more in details how to use it as a game controller

    ReplyDelete
    Replies
    1. What would you like to achieve? How would you like to use the game controller with this device built into it?

      Delete
  2. Hi, I also buy the same breakout (the ebay one). At first, it can't work on SPI. But when I remove R4 (the resistor connect to SDO pin), it can work on SPI. I use nucleo stmf401re board and mbed ADXL345_HelloWorld sample code to test it.

    ReplyDelete
    Replies
    1. Thanks for the info. How many ADXL345 did you buy? Could you get all your ADXL345 modules to show the 3-axis readings correctly and consistently?

      Delete
    2. I only buy one. The 3-axis reading looks fine and works just as the behaviors describe by datasheet. But z-axis reading seems a little smaller than it should be (place on desk, z should be 1g but only 0.93 - 0.97g). Maybe calibration can improve this.

      Delete
    3. Thanks!! Could you post the link from which you bought your module? I may get some to give them a try..

      Delete
    4. http://www.icshop.com.tw/product_info.php/products_id/8145

      Delete