Not receiving all datapoints from accelerometer using SPI

Hi everyone, I wanna start of saying this is my first project that involves any coding which is the reason I am stuck. I have looked around everywhere trying to add pieces of code that does what I want my accelerometer to do, as well as having read the datasheet to death.

All I want to do right now is get good data from my ADXL355z evaluation board to my Arduino Due. Before I make my ADXL357Bez work together with a ATMEGA16AU microcontroller on a tiny PCB for downhole measurements on a laboratory scale drilling rig.

I am currently receiving a lot of data from the accelerometer, however it’s not reading all movement (Especially X-axis). I’ll add the code in case there are any glaring mistakes.

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


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

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


void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //The speed is set by the setClockDivider() function, which divides the master clock (84MHz on Due) down to a frequency between 42MHz (/2) and X (/128).
  SPI.setClockDivider(2);  
  //Configure the SPI connection for the ADXL355. The timing scheme follows the clock polarity (CPOL) = 0 and clock phase (CPHA) = 0 and is therefore SPI mode 0.
  SPI.setDataMode(SPI_MODE0);
  //Sets the order of the bits shifted out of and into the SPI bus, either LSBFIRST (least-significant bit first) or MSBFIRST (most-significant bit first).
  SPI.setBitOrder(MSBFIRST);
  //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);
  
  //Measurement mode
  digitalWrite(CS, LOW);
  SPI.transfer(POWER_CTL);
  SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
  delay(50);   

 //Put the ADXL355 into Measurement Mode by writing 0 to the POWER_CTL register.
//digitalWrite(POWER_CTL, 0x00);  //Measurement mode  
} 

void loop(){
  digitalWrite(CS, LOW);
  values[0] = SPI.transfer(DATAX3);
  digitalWrite(CS, HIGH);
  delay(10);  
//  
  digitalWrite(CS, LOW);
  values[1] = SPI.transfer(DATAX2);
  digitalWrite(CS, HIGH);
  delay(50);    
//
  digitalWrite(CS, LOW);
  values[2] = SPI.transfer(DATAY3);
  digitalWrite(CS, HIGH);
  delay(50);  
//  
  digitalWrite(CS, LOW);
  values[3] = SPI.transfer(DATAY2);
  digitalWrite(CS, HIGH);
  delay(50);  
//
  digitalWrite(CS, LOW);
  values[4] = SPI.transfer(DATAZ3);
  digitalWrite(CS, HIGH);
  delay(50);  
//
  digitalWrite(CS, LOW);
  values[5] = SPI.transfer(DATAZ2);
  digitalWrite(CS, HIGH);
  delay(50);   

 //The x value is stored in values[0] and values[1].
 x = ((int)values[0]<<8)|(int)values[1];
 //The Y value is stored in values[2] and values[3].
 y = ((int)values[2]<<8)|(int)values[3];
 //The Z value is stored in values[4] and values[5].
 z = ((int)values[4]<<8)|(int)values[5];
 
  
  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);   
  //delay(100); 
}

All addresses should be included in the ADXL355.h file.

Here’s a picture of some data from the serial monitor: ADXL355z data - Album on Imgur

Link to datasheet: http://pdf1.alldatasheet.com/datasheet-pdf/view/903165/AD/ADXL355.html

There’s a good chance I have missed something glaringly obvious like bit data, clock divider or how I read data, but I am at a loss and could use all input I can get.

Help? :confused:

According to the datasheet you have to first address your register and then pulse it in.

So Reading register DATAX3 would look like this:

  digitalWrite(CS, LOW);
  SPI.transfer(DATAX3);
  values[0] = SPI.transfer();
  digitalWrite(CS, HIGH);

But you can eliminate the delay() calls, they are not necessary.

What you proposed is what I had in the code initially, tried changing back to it now and all the values I get are 0, 0, 0.

(Sorry about the cross-post, was unsure where it would be the most relevant)

Post the adapted code! And post a wiring diagram!

Adapted code:

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


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

//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;
byte buff;


void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //The speed is set by the setClockDivider() function, which divides the master clock (84MHz on Due) down to a frequency between 42MHz (/2) and X (/128).
  SPI.setClockDivider(21);  
  //Configure the SPI connection for the ADXL355. The timing scheme follows the clock polarity (CPOL) = 0 and clock phase (CPHA) = 0 and is therefore SPI mode 0.
  SPI.setDataMode(SPI_MODE0);
  //Sets the order of the bits shifted out of and into the SPI bus, either LSBFIRST (least-significant bit first) or MSBFIRST (most-significant bit first).
  SPI.setBitOrder(MSBFIRST);
  //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);
  
  //Measurement mode
  digitalWrite(CS, LOW);
  SPI.transfer(POWER_CTL);
  SPI.transfer(0x00);
  digitalWrite(CS, HIGH);  

 //Put the ADXL355 into Measurement Mode by writing 0 to the POWER_CTL register.
//digitalWrite(POWER_CTL, 0x00);  //Measurement mode  
} 

void loop(){
  digitalWrite(CS, LOW);
  SPI.transfer(DATAX3);
  values[0] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
//  
  digitalWrite(CS, LOW);
  SPI.transfer(DATAX2);
  values[1] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);  
//
  digitalWrite(CS, LOW);
  SPI.transfer(DATAY3);
  values[2] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
//  
  digitalWrite(CS, LOW);
  SPI.transfer(DATAY2);
  values[3] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
//
  digitalWrite(CS, LOW);
  SPI.transfer(DATAZ3);
  values[4] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
//
  digitalWrite(CS, LOW);
  SPI.transfer(DATAZ2);
  values[5] = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);

 //The x value is stored in values[0] and values[1].
 x = ((int)values[0]<<8)|(int)values[1];
 //The Y value is stored in values[2] and values[3].
 y = ((int)values[2]<<8)|(int)values[3];
 //The Z value is stored in values[4] and values[5].
 z = ((int)values[4]<<8)|(int)values[5];
 
  
  Serial.print(x, DEC);
  Serial.print(',');
  Serial.print(y, DEC);
  Serial.print(',');
  Serial.println(z, DEC);   
  //delay(100); 
}

Wiring: Imgur: The magic of the Internet
Wiring schematic for ADXL355: Imgur: The magic of the Internet

Please post pictures to the forum system directly and not some external image servers. If someone looks at this entry in a year or so the external links may fail.

The ADXL355 is a 3.3V device, you must not connect the SPI signals directly to the 5V signals of the Arduino, you may damage the chip. You must use level converters to connect this chip to a 5V Arduino. As the 5V of the Arduino are above the specs you might have already fried the chip. Get the level converter and a replacement ADXL355 board.

I am not sure I understand why that would be needed when connecting it to the 3.3V of the Arduino Due?

Excuse me, my mistake, I overlooked that you're using a Due.

Please use SPI transactions on the Due.

What's the value of DATAX3 in your .h file? It should be 0x11 or 17. If it's not that value you might have to form the correct command byte first.

No worries, I should've mentioned it in my post.

SPI transactions on the Due? Am I not doing that? :p

#define DATAX3                   0x08
#define DATAX2                   0x09
#define DATAX1                   0x0A
#define DATAY3                   0x0B
#define DATAY2                   0x0C
#define DATAY1                   0x0D
#define DATAZ3                   0x0E
#define DATAZ2                   0x0F
#define DATAZ1                   0x10

As I suspected, the header file just defines the addresses but not the commands. You can build the read command from the addresses using this line:

uint8_t cmd = (address << 1) | 0x01;

SPI transactions on the Due? Am I not doing that? :stuck_out_tongue:

No, that would look like this:

SPISettings settings(4000000, MSBFIRST, SPI_MODE0);
digitalWrite(CS, LOW);
SPI.beginTransaction(settings);
SPI.transfer(0x01);
SPI.endTransaction();
digitalWrite(CS, HIGH);

Cheers, I'll try that out when I get back on thursday