SPI not working when using SD card and ADXL345

Hello everyone,

I have an arduino nano connected via SPI to two ADXL345 adafruit breakout boards and an adafruit SD card reader/ writer. Indepenetly everything works fine, however as soon as I try to make to make the components work together it fails.

I looked at a bunch of other forum posts such as here and here and adressed issues such as setting the CS for slave devices to high, and setting the correct SPI mode (0 or 3). See code. However it still doesn’t work. The output I get from serial monitor is this:

0, -3, 551
0, -3, 552
0, -3, 552
-1, -3, 553

, 554

, 555
Trying to open SD file..
Trying to open SD file..

And then it just endless hangs at “trying to open SD file”.

#include <SparkFun_ADXL345.h>                // SparkFun ADXL345 Library
#include <pins_arduino.h>
#include <SD.h>
#include <SPI.h>

#define DEBUG_ENABLED           // COMMENT THIS IF DEBUGGING IS NOT NEEDED

#define ADXL_1_PIN                5
#define ADXL_2_PIN                6
#define SD_PIN                    10

ADXL345 adxl_1 = ADXL345(ADXL_1_PIN);

ADXL345 adxl_2 = ADXL345(ADXL_2_PIN);


bool    writeToSD  =   false;
int     i             =   0;      // Counter for data points
float   alpha         =   0.02;   // Moving average filter weight

float   avg           =   0.9;    // Initialise moving average filter.

int     dataRate      =   400;


int x_1, y_1, z_1;
int x_2, y_2, z_2;

double   measThresh; // start the data writing process, originally 0.9
double   measFloor;
double   avgStart;
unsigned long SDstart; 

File file;


/*
  void DEBUG_TRACE(String str)
  {
  #ifdef DEBUG_ENABLED
    Serial.println(String(str));
  #endif
  }
*/
//int i;


void setup()
{
  
  pinMode(ADXL_1_PIN, OUTPUT);
  pinMode(ADXL_2_PIN, OUTPUT);
  pinMode(SD_PIN, OUTPUT);
  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  delay(100); 


  Serial.begin(115200);
  delay(100); 

//
  SPI.begin(); 

  // ***************** SETUP ADXL 345 ****************************
  adxl_1.powerOn();                     // Power on the ADXL345
  delay(500);
  adxl_1.setRangeSetting(16);           // Give the range settings
  delay(500);
  adxl_1.setSpiBit(0);                  // Select '0'for 4 wire SPI, default is '1' for 3 wire SPI
  delay(500);
  adxl_1.setRate(dataRate);
  delay(500);
  adxl_1.setActivityXYZ(0, 0, 1);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  delay(500);
  //
  adxl_2.powerOn();                     // Power on the ADXL345
  delay(500);
  adxl_2.setRangeSetting(16);           // Give the range settings
  delay(500);
  adxl_2.setSpiBit(0);
  delay(500);
  adxl_2.setRate(dataRate);
  delay(500);
  adxl_2.setActivityXYZ(0, 0, 1);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  delay(500);

  if (!SD.begin(SD_PIN)) {
        Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  delay(500);


  measThresh = 1.5; // Threshold at which to start measuring
  measFloor  = 1;   // Floor value, below this train passage stops

  i = 0;
}

void loop()
{

  // *************************** ADXL345 ********************************

  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  SPI.setDataMode(SPI_MODE3); // Horrific hack to make ADXL345 work with SD reader.
  adxl_1.readAccel(&x_1, &y_1, &z_1);         // Read the accelerometer values and store them in variables declared above x,y,z
  adxl_2.readAccel(&x_2, &y_2, &z_2);
  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  SPI.setDataMode(SPI_MODE0); // Horrific hack to make ADXL345 work with SD reader.

  i         =     i + 1;
  
 
  String dataString = String(y_1) + String(", ") + String(y_2) + String(", ") + String(i);
  Serial.println(dataString);


    if (abs(y_1) || abs(y_2) > measThresh && writeToSD == false) // Start writing to SD
    {

        writeToSD  =   true;
        SDstart   =   millis();
        avg           =   measThresh;        
        file = SD.open("datalog2.txt", O_CREAT | O_WRITE | O_APPEND);
         while(!file){
  //      Loop in here until file is open.
          Serial.println("Trying to open SD file.."); 
      }
  
    }
    else if ( abs(y_1) || abs(y_2) <= measThresh && writeToSD == false) // Threshold not exceeded, do not write to SD
    {

    }
  

    if (writeToSD == true)  // Conditions for ending are evaluated.
    {
        compute_and_send_payload();
    }

}


//--------------------HELPER FUNCTIONS-----------------------

void compute_and_send_payload()
{
  avg       =   alpha * y_1 + (1 - alpha) * avg; // Moving average filter


//  // make a string for assembling the data to log:
  String dataString = String(y_1) + String(", ") + String(y_2) + String(", ") + String(i);

  file.println(dataString);
  Serial.println(dataString);


  if ( (abs(avg) > measFloor && (millis() - SDstart < 30000 )) || (millis() - SDstart < 3000))
  {
     // Keep going.
  }

  else 
  {
    file.close();
    Serial.println("Closing file"); 
    writeToSD = false;

  }
}

Update: I adapted the code so that the SD card is opened and closed for each measurement that is performed. It seems to work, however it makes the script very very slow, making it pretty much useless.

#include <SparkFun_ADXL345.h>                // SparkFun ADXL345 Library
#include <pins_arduino.h>
#include <SD.h>
#include <SPI.h>

#define DEBUG_ENABLED           // COMMENT THIS IF DEBUGGING IS NOT NEEDED

#define ADXL_1_PIN                5
#define ADXL_2_PIN                6
#define SD_PIN                    10
#define LED_PIN                   8 

ADXL345 adxl_1 = ADXL345(ADXL_1_PIN);

ADXL345 adxl_2 = ADXL345(ADXL_2_PIN);


bool    writeToSD  =   false;
int     i             =   0;      // Counter for data points
float   alpha         =   0.02;   // Moving average filter weight

float   avg           =   0.9;    // Initialise moving average filter.

int     dataRate      =   400;


int x_1, y_1, z_1;
int x_2, y_2, z_2;

double   measThresh; // start the data writing process, originally 0.9
double   measFloor;
double   avgStart;
unsigned long SDstart; 

File file;


/*
  void DEBUG_TRACE(String str)
  {
  #ifdef DEBUG_ENABLED
    Serial.println(String(str));
  #endif
  }
*/
//int i;


void setup()
{
  
  pinMode(ADXL_1_PIN, OUTPUT);
  pinMode(ADXL_2_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(SD_PIN, OUTPUT);
  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  digitalWrite(LED_PIN,HIGH); 
  delay(100); 


  Serial.begin(115200);
  delay(100); 

//
  SPI.begin(); 

  // ***************** SETUP ADXL 345 ****************************
  adxl_1.powerOn();                     // Power on the ADXL345
  delay(500);
  adxl_1.setRangeSetting(16);           // Give the range settings
  delay(500);
  adxl_1.setSpiBit(0);                  // Select '0'for 4 wire SPI, default is '1' for 3 wire SPI
  delay(500);
  adxl_1.setRate(dataRate);
  delay(500);
  adxl_1.setActivityXYZ(0, 0, 1);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  delay(500);
  //
  adxl_2.powerOn();                     // Power on the ADXL345
  delay(500);
  adxl_2.setRangeSetting(16);           // Give the range settings
  delay(500);
  adxl_2.setSpiBit(0);
  delay(500);
  adxl_2.setRate(dataRate);
  delay(500);
  adxl_2.setActivityXYZ(0, 0, 1);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  delay(500);

  if (!SD.begin(SD_PIN)) {
        Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  delay(500);


  measThresh = 1.5; // Threshold at which to start measuring
  measFloor  = 1;   // Floor value, below this train passage stops

  i = 0;
  digitalWrite(LED_PIN,LOW); 
}

void loop()
{

  // *************************** ADXL345 ********************************

  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  SPI.setDataMode(SPI_MODE3); // Horrific hack to make ADXL345 work with SD reader.
  adxl_1.readAccel(&x_1, &y_1, &z_1);         // Read the accelerometer values and store them in variables declared above x,y,z
  adxl_2.readAccel(&x_2, &y_2, &z_2);
  digitalWrite(ADXL_1_PIN,HIGH);
  digitalWrite(ADXL_2_PIN,HIGH);
  digitalWrite(SD_PIN,HIGH); 
  SPI.setDataMode(SPI_MODE0); // Horrific hack to make ADXL345 work with SD reader.

  i         =     i + 1;
  
 
  String dataString = String(y_1) + String(", ") + String(y_2) + String(", ") + String(i);
  Serial.println(dataString);


    if (abs(y_1) || abs(y_2) > measThresh && writeToSD == false) // Start writing to SD
    {

        writeToSD  =   true;
        SDstart   =   millis();
        avg           =   measThresh;        

  
    }
    else if ( abs(y_1) || abs(y_2) <= measThresh && writeToSD == false) // Threshold not exceeded, do not write to SD
    {

    }
  

    if (writeToSD == true)  // Conditions for ending are evaluated.
    {
        compute_and_send_payload();
    }

}


//--------------------HELPER FUNCTIONS-----------------------

void compute_and_send_payload()
{
  avg       =   alpha * y_1 + (1 - alpha) * avg; // Moving average filter


//  // make a string for assembling the data to log:
  String dataString = String(y_1) + String(", ") + String(y_2) + String(", ") + String(i);

    file = SD.open("datalog2.txt", O_CREAT | O_WRITE | O_APPEND);
    while(!file){
  //      Loop in here until file is open.
      Serial.println("Trying to open SD file..");
      file.println(dataString);
//      Serial.println(dataString); 
    }
    file.close();
    Serial.println(dataString); 
    Serial.println("Closing file"); 



  if ( (abs(avg) > measFloor && (millis() - SDstart < 30000 )) || (millis() - SDstart < 3000))
  {
     // Keep going.
  }

  else 
  {

    writeToSD = false;

  }
}