Multiple ADXL345 + SD Card SPI configuration?

Hi all, can anyone advised why cant i an readings and logged my data onto the sd card?

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

//Assign the Chip Select signal to pin 10.
int CS = 6;
//const int chipSelect = 4;

//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.
float  x,y,z;
float xg,yg,zg;
float x1,y1,z1;
byte runComplete; //setting the number of iteration
int i; //delare i for count

void setup(){ 
 //Create a serial connection to display the data on the terminal.
 Serial.begin(9600);
 //Initiate an SPI communication instance.
 SPI.begin();
 //Configure the SPI connection for the ADXL345.
 SPI.setDataMode(SPI_MODE3);

 if (!SD.begin(4)) {
   Serial.println("initialization failed!");
   return; 
 }
 Serial.println("initialization done.");
  // open the file. note that only one file can be open at a time,
 // so you have to close this one before opening another.
 myFile = SD.open("test.txt", FILE_WRITE);

 // if the file opened okay, write to it:
 if (myFile) {
   Serial.print("Writing to test.txt...");
   myFile.println("testing 1, 2, 3.");
   // close the file:
   myFile.close();
   Serial.println("done.");
 } else {
   // if the file didn't open, print an error:
   Serial.println("error opening test.txt");
 }
 
 //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  
  //Serial.print("Initializing SD card...");

}
//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);
}

void acc1(){
 //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];
 
 //Convert the accelerometer value to G's. 
 //With 10 bits measuring over a +/-4g range we can find how to convert by using the equation:
 // Gs = Measurement Value * (G-range/(2^10)) or Gs = Measurement Value * (8/1024)
 xg = x * 0.0078;
 yg = y *  0.0078;
 zg = z *  0.0078;
 
 //Print the results to the terminal.
 Serial.print(xg);
 Serial.print(',');
 Serial.print(yg);
 Serial.print(',');
 Serial.println(zg);
 
 myFile = SD.open("test.txt");
 if (myFile){
   myFile.println(xg);
   myFile.close();
   Serial.println("done");
   } else{
   Serial.println(F("error opening test.txt")) ;// if the file didn't open, print an error:
     }
 delay(10); 
}
void loop()
{
 if (runComplete == 0){
 for (i=0; i<2501; i=i+1){
 Serial.print("Number of iteration(seconds) = "); Serial.println(i);
 acc1();
    delay(100);
  }
 runComplete = 1;
 }
}

Does your code show a fail on the serial monitor?

SurferTim:
Does your code show a fail on the serial monitor?

hi SurferTime,

yes it does!

And which error message would that be?

The SD card best responds to SPI mode0. I see you are setting it to mode3.

SurferTim:
And which error message would that be?

The SD card best responds to SPI mode0. I see you are setting it to mode3.

Do I need to set another set another SPI mode0 for SD card ? mode3 is for the ADXL345 actually

You may have to switch back and forth with the SPI mode. Which error message are you getting? Is it the SD initialize that fails, or the file open?

Hey, I have been getting this error a lot lately..

avrdude: stk500_paged_load(): (a) protocol error, expect=0x14, resp=0x01
avrdude: stk500_cmd(): programmer is out of sync
Problem uploading to board. See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.

SurferTim:
You may have to switch back and forth with the SPI mode. Which error message are you getting? Is it the SD initialize that fails, or the file open?

I am getting error at "File open" (line142)

Do you get the open error if the ADXL345s are not connected?

SurferTim:
Do you get the open error if the ADXL345s are not connected?

No, i get the same error.

I found the code below in this thread that was suppose to work. I tried running it, but the serial monitor doesnt shows up the acceleration values, while the SD card stop logging data after ~15 readings.. Can you please advice me what to do?
Thank you

// Include the relevant libraries provided with the Arduino
#include <SPI.h>
#include <SD.h>

// place holder for a large number
unsigned long time; // called it "time"

//Factors to change the data output by the accelerometer from raw data to G forces
double g=0.0039; //+/- 2g Make sure this matches the writeRegister Data Format on line 91!
//double g=0.0078; //+/- 4g
//double g=0.016;  //+/- 8g
//double g=0.031; //+/- 16g

#define SYNC_INTERVAL 10000 // mills between calls to flush() - to write data to the card
uint32_t syncTime = 0; // time of last sync()

// Assign the ADXL345 CS pin to Pin 10 ** make this whatever digital pin you chose to use**
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
char BW_RATE = 0x2C;    //Sampling Rate

//This buffer will hold values read from the ADXL345 registers.
char values[10];
//Initalize variables
int x,y,z;
int i;
double xg,yg,zg;
double totals[3];
File myFile;

void setup(){
  //Initiate an SPI communication instance.
  SPI.begin();
  Serial.begin(38400);   
 
  //Set up the Chip Select pin for the SD card to be an output from the Arduino.
  pinMode(8, OUTPUT);
  //Set chip select for ADXL345 to be output from Arduino.
  pinMode(CS, OUTPUT);

  //Set the CS Pin for the accelerometer high so that the ADXL345 and SD card won't be trying to talk at same time.
  digitalWrite(CS, HIGH);

  //Initialize the SD card
  if (!SD.begin(8)) { // the (8) is the CS pin you chose to use, on my sheild that pin is hardwired to "8"
    return;
  }
  // create a new file
  // starts with Crash00, and next one would be Crash01
  char filename[] = "Crash.txt";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      myFile = SD.open(filename, FILE_WRITE);
      break;  // leave the loop!
    }
  }
   
  //Print header to file
  myFile.println("Time in MilliSeconds,X_Axis,Y_Axis,Z_Axis, X_G's,Y_G's,Z_G's");

  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //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, 0x00);//0x00 +/- 2G, 0x01 +/- 4G. 0x10 +/- 8G,0x11 +/-16G
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode
  //Try and change sampling rate
  writeRegister(BW_RATE, 0x0D);
}

void loop(){

  //Count Milliseconds from time Arduino powered on
  time = millis();
 
  //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];

  //Convert raw data to g values
  xg=x*g;
  yg=y*g;
  zg=z*g;

  //Store g values in an array
  totals[0] = xg;
  totals[1] = yg;
  totals[2] = zg;

   // log time
    myFile.print(time);
    myFile.print(',');
   
  //Log accelerations
    myFile.print(x);
    myFile.print(',');
    myFile.print(y);
    myFile.print(',');
    myFile.print(z);
    myFile.print(',');
  for (i = 0; i < 3; i = i + 1) {
    myFile.print(totals[i]);
    myFile.print(',');
    // Open the serial monitor to see if it's working, select a baud rate of 38400, only displays milliseconds and G's
    Serial.print(time);
    Serial.print(',');
    Serial.print(totals[i]);
    Serial.print(',');
  }
  myFile.println();
  Serial.println();

  // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
  // which uses a bunch of power and takes time
  if ((millis() - syncTime) < SYNC_INTERVAL) return;
  syncTime = millis();

  // flush the system
  myFile.flush();
// delay to help clear some of the noise
// delayMicroseconds(2);

}   //END OF LOOP!!!!!

//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);
}

You should try to get the devices to work separately first. Get the SD card working, then the ADXL345s working, then combine the two sketches.

I only see one ADXL345 in that code. I have 3 on my breadboard right now. I discovered something that might be useful to you.

If you don't set the CS of every ADXL345 to high, then they interfere with each other. They don't know that they're not supposed to talk on the bus so they all talk at once. This will also prevent the SD card from working.

if (!SD.begin(4)) {

4 is a magic number. Give this pin a name and put that declaration at the top of your file. Then use the name everywhere you need it.

MorganS has a great point. Normally I would bring this up, but I let it slide this time. Always set all SPI slave selects to HIGH before initializing any of them for the reason MorganS presented. I set them to OUTPUT also, except in the case of the Due.