ADXL 345 no reading with SPI

I've done a search in regards to this problem and it appears a number of people have/had this problem with no resolution. The ADXL345 runs fine with I2C. However I want more speed, hence going with SPI.

My connections and code are shown here:
https://www.sparkfun.com/tutorials/240

//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>

//Assign the Chip Select signal to pin 10.
int CS=10;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D;	//Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32;	//X-Axis Data 0
char DATAX1 = 0x33;	//X-Axis Data 1
char DATAY0 = 0x34;	//Y-Axis Data 0
char DATAY1 = 0x35;	//Y-Axis Data 1
char DATAZ0 = 0x36;	//Z-Axis Data 0
char DATAZ1 = 0x37;	//Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //Create a serial connection to display the data on the terminal.
  Serial.begin(9600);
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS, HIGH);
  
  //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x01);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
}

void loop(){
  //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(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] & 0xFF;
  //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];
  
  //Print the results to the terminal.
  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);      
  delay(100); 
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
}

My output is always 0,0,0.

I have shortened the SDO, SDA and SCL wires to 1 inch with no improvement.

I connected an old analog scope to the communication lines. CS and SCL remain high. SDO and SDA remain low. I don't see any switching. It doesn't look like I'm getting through to the ADXL.

Any insights & help is appreciated.
Gerry

I can not find a problem.
The example is for the Arduino Uno. If you have an other board, it might not work. Are you perhaps using an Arduino Leonardo or Mega ?

I'm using the Uno.

Hallo!
Sparkfun Codes works well.
On an Uno , you will need a (4) Levelshifter..the Breakouts are 3,6 V max

mfg Martin

The instructions for chip select are very confusing. Chip-select = pin 10 is for when you want the arduino to be the spi slave device controlled by something else. which you usually don't want, when interfacing with sensors. Try using a different pin for the chip select signal to the sensor device.

michinyon:
The instructions for chip select are very confusing. Chip-select = pin 10 is for when you want the arduino to be the spi slave device controlled by something else. which you usually don't want, when interfacing with sensors. Try using a different pin for the chip select signal to the sensor device.

Pin 10 is the hardware SS pin. It need to be set to output for the UNO SPI hardware to be master (no matter what pin you use for SS) and if it's set to input and your using the hardware SPI then it will make the UNO a slave device.

Thanks for the reply's. I don't understand it. There may be thousands of these accelerometers working with the Uno. Many are connected as shown in the Spark Fun link. Yet the absolute maximum input voltage of the ADXL345 is 3.9V. The Uno data outputs are I believe 5V. A voltage level shifter was suggested; I tend to agree. I think the ADXL may be saved because the Uno outputs are current limited. The I2C configuration was working OK. That's also operating off of 5V with no level shifter, right?

It's also strange that Uno pin 13 is chosen for the clock signal (SCL). The Uno LED is loading the clock signal. That can't be good for signal integrity.

I was a bit careless yesterday fooling around with the accelerometer. I lifted the power input and to my surprise, the on-board ADXL red LED remained on. Do the ADXL data inputs have clamping diodes to Vcc? That's probably the reason 5V data inputs won't destroy the chip. Is there a schematic for the ADXL345 circuit board? In any event, I probably overstressed the unit when I connected 5V to Vs. It may have been defective before that event. More accelerometers are on order.

What's a common voltage level shift circuit used for this application?

Gerry

Hello!
4-channel Bi-directional Logic Level Converter.. 5V High 3,3 Low
A small Breakout with 4 MosFets on it ...from $2 to $4 at your local Store.
Maybe the 345 lives, do also on mine ,5V to Int1...rerouting and it works again.
Have Luck!

mfg Martin

OK. Level converters are on order. I could very well have a signal integrity problem. They should clear up the signal at least.

I'm surprised the 345 is still operational in I2C mode. I got a little burn blister on my finger when touching the IC yesterday with 5V on it. i though for sure it was dead.

The troubleshooting goes on.

Gerry

Any Update on this Gary?

I received a different brand of ADXL345 modules. The first module didn't work in SPI mode. This module is identified as having pin headers on two sides of the module. The newer module has just one pin header row. It works in SPI mode without a voltage level converter.

Even though it "works", there's still a problem. 5V is being fed to the ADXL345 SPI inputs. The ADXL wants 3.3V. The excess voltage feeds through the SPI clamping diodes to Vcc. This raises Vcc to 3.9V. Seems like the chip can take it. I believe now the accelerometer scaling is screwed up. Scaling is based on Vcc = 3.3V. Accelerometer data is 18% low.

All is well after adding the suggested voltage converter.

Gerry

Hi, I just thought I'd follow up on this thread since it's still valid because the ADXL345 modules that are having a problem in SPI mode and returning all 0's when doing an SPI read are still being sold. Given that there's all 0's, it looks like a problem with setting the chip into measurement mode. I just wish I had come across this thread sooner before putzing around for hours trying to get the 2 header pin version working with SPI. I've attached a pic of what the modules look like, both good and bad. (I have both modules.)

The module that's working in SPI as Gerry described it has a single row of 8 header pins. They both have 3.3v regulators on-board, but the non-working modules has larger value resistors as you can see.

I came across this same problem. I am using Arduino Mega 2560 and ADXL 345(8pins on one side). The connections are as follows

ADXL345---- ARDUINO MEGA 2560

GND---------- GND
VCC---------- 3.3 V
CS------------PIN 19(SS)
SDO----------PIN22(MISO)
SDA----------PIN20(SDA)
SCL----------PIN21(SCL)

The code is same as the one given in the sparkfun tutroial except for the "int CS=19" line
I am getting the same error. The readings on Serial monitor shows ' 0,0,0'
I understand that the alternate is to use I2C. But I really need to get this SPI connection working.

Any kinda help to fix this would be really appreciated.
Thanks in advance.

#include <SPI.h>

//Assign the Chip Select signal to pin 10.
int CS=19;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D;  //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //Create a serial connection to display the data on the terminal.
  Serial.begin(9600);
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS, HIGH);
  
  //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x01);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
}

void loop(){
  //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(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];
  
  //Print the results to the terminal.
  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);      
  delay(10); 
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
}

I finally found what was wrong with the code! :slight_smile: Finally made it work by changing the SPI MODE to 3 and reversing the initialisation order of the DATA FORMAT and POWER CTL. I'm using a different controller, so the SPI language is a little bit different, but you could adapt it easily for an Arduino.

#include <SPI.h>

static const int spiClk = 1000000; // 1 MHz SPI communication speed

char POWER_CTL = 0x2D;   // Power Control Register
char DATA_FORMAT = 0x31; // Data Format Register
char DATAX0 = 0x32;      // X-Axis Data 0
char DATAX1 = 0x33;      // X-Axis Data 1
char DATAY0 = 0x34;      // Y-Axis Data 0
char DATAY1 = 0x35;      // Y-Axis Data 1
char DATAZ0 = 0x36;      // Z-Axis Data 0
char DATAZ1 = 0x37;      // Z-Axis Data 1
char values[10];         // Buffer that will hold values read from the ADXL345 registers
int x, y, z;             // Will be used to hold the x,y and z axis accelerometer values
int CS0 = 15;            // Chip select for the ADXL345

SPIClass * hspi = NULL;  // Uninitalised pointers to SPI objects

// ================================================================
// ===                      SETUP ROUTINE                       ===
// ================================================================

void setup() {
  hspi = new SPIClass(HSPI);

  //initialise hspi with default pins
  //SCLK = 14, MISO = 12, MOSI = 13, SS = 15
  hspi->begin();

  Serial.begin(115200);

  pinMode(CS0, OUTPUT);    // Set up slave select (CS) pin as output
  digitalWrite(CS0, HIGH); // Before communication starts, the Chip Select pin needs to be set high

  writeRegister(POWER_CTL, 0x08);   // Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(DATA_FORMAT, 0x0B); // Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
}

// ================================================================
// ===                      LOOP ROUTINE                        ===
// ================================================================

void loop() {

  readRegister(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];

  //Print the results to the terminal.
  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);
  delay(1);
}

// ================================================================
// ===                 WRITE REGISTER ROUTINE                   ===   // This function will write a value to a register on the ADXL345.
// ================================================================

//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value) {
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE3));
  digitalWrite(CS0, LOW);           //Set Chip Select pin low to signal the beginning of an SPI packet.
  hspi->transfer(registerAddress);  //Transfer the register address over SPI.
  hspi->transfer(value);            //Transfer the desired register value over SPI.
  digitalWrite(CS0, HIGH);          //Set the Chip Select pin high to signal the end of an SPI packet.
  hspi->endTransaction();
}

// ================================================================
// ===                  READ REGISTER ROUTINE                   ===   // This function will read a certain number of registers starting from a specified address and store their values in a buffer.
// ================================================================

//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.

void readRegister(char registerAddress, int numBytes, char * values) {
  char address = 0x80 | registerAddress;  // Since we're performing a read operation, the most significant bit of the register address should be set.
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if (numBytes > 1) {
    address = address | 0x40;
  }
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE3));
  digitalWrite(CS0, LOW);  // Set the Chip select pin low to start an SPI packet.
  hspi->transfer(address);  //Transfer the starting register address that needs to be read.

  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for (int i = 0; i < numBytes; i++) {
    values[i] = hspi->transfer(0x00);
  }
  digitalWrite(CS0, HIGH);  //Set the Chips Select pin high to end the SPI packet.
  hspi->endTransaction();
}

// ================================================================
// ===                 READ REGISTER2 ROUTINE                   ===
// ================================================================

void readRegister2(char registerAddress, int numBytes) {
  char address = 0x80 | registerAddress;  // Since we're performing a read operation, the most significant bit of the register address should be set.
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if (numBytes > 1) {
    address = address | 0x40;
  }
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE3));
  digitalWrite(CS0, LOW);
  hspi->transfer(address);

  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for (int i = 0; i < numBytes; i++) {
    values[i] = hspi->transfer(0x00);
  }
  digitalWrite(CS0, HIGH);  // Set the Chips Select pin high to end the SPI packet.
  hspi->endTransaction();
}

// ================================================================
// ===                         the END                          ===
// ================================================================

Most MEMS sensors that claim to be both I2C and SPI are not.

They use the SPI chip select pin to switch between I2C and SPI mode, so you cannot share the
device with anything else (on some chips there are two interfaces, which cannot be shared on
the same SPI bus either!!).

And you need to check the clock phase and polarity settings in the datasheet - they can be
made to work in SPI if you get everything right.

Hay,i wanna ask u if its work ,the adxl345
8 pins with 4 pins wach side,i am trying to make it work,but it shows me 0,0,0 i dont have any idea why,i just connect it by spi can u send me a photo of wiring it and code,please i need it