SD CLK not wanting to share with others

Status
Not open for further replies.

Cooop

New member
I'm a coding virgin and have only been playing with a Teensy 3.2 since last week. I'm attempting to connect multiple SPI devices together in order to grab data and then store on an SD card. Currently I'm using the ADXL345 accel, L3GD20H gyro and an SD card breakout board. I intend to add two SPI output pressure sensors and some other digital inputs (ADC outputs) and a few analogue at a later date, all recording to the SD card.

Using the libraries I have had the accel and gyro working together fine and displaying data. I've also had the SD card working fine also on its own, however when I try to combine them all together to store the data from the sensors to the SD card it fails.

I've tracked it down to usage of the SCL line.... the accel and gyro are happy using the same SCK line and will continue to work with the SD card board SCL line also connected. The SD card will work with the sensors SCL lines disconnected but stop when either is connected. I've moved the SCL line of the Gyro across to 14 and can now use the gyro and SD card together but not the accel.

The SCL line for the accel must be set within the library somewhere as I cant find how to change it in the main code. I'm happy to dedicate on digital output to the SD card in order to make it work so my question is in two parts really

1) Why is the SD card unhappy at sharing the same SCL line as the sensors and how should I go about fixing it so they can all play together
2) Is it just easier to move the SCL line of the SD card (or Accel) and if so where can I find the variable to change this setting.

Code below, its a mash up of working code so apologies for the mess!


Code:
#include <SPI.h>
#include <Wire.h> 
#include <SD.h>
#include <Adafruit_L3GD20.h>

// set up variables using the SD utility library functions:
   #define GYRO_CS 10 // labeled CS
  #define GYRO_DO 12// labeled SA0
  #define GYRO_DI 11  // labeled SDA
  #define GYRO_CLK 14 // labeled SCL
  Adafruit_L3GD20 gyro(GYRO_CS, GYRO_DO, GYRO_DI, GYRO_CLK);

//Setup vairables for the gyro functions
int gyrox;
int gyroy;
int gyroz;


//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 values[10];  //This buffer will hold values read from the ADXL345 registers.
int Accelx,Accely,Accelz;  //These variables will be used to hold the x,y and z axis accelerometer values.
int AccelCS=9; //Chip select for the accel board


void setup() 
{
  Serial.begin(9600);
}

void getgyro() //individual function to grab the x axis from the gyro
{
   // Try to initialise and warn if we couldn't detect the chip
   if (!gyro.begin(gyro.L3DS20_RANGE_250DPS))
  {
    Serial.println("Unable to initialize the L3GD20");
     }
    gyro.read();   //tells the gyro to grab a data point
    gyrox = (gyro.data.x); //sets the global variable to the axis value data grab
    gyroy = (gyro.data.y); //sets the global variable to the axis value data grab
    gyroz = (gyro.data.z); //sets the global variable to the axis value data grabd
}

void getaccel()
{
  SPI.begin();   //Initiate an SPI communication instance.
  SPI.setDataMode(SPI_MODE3);  //Configure the SPI connection for the ADXL345.
  Serial.begin(9600);  //Create a serial connection to display the data on the terminal.
  pinMode(AccelCS, OUTPUT);   //Set up the Chip Select pin to be an output from the Arduino.
  digitalWrite(AccelCS, HIGH); //Before communication starts, the Chip Select pin needs to be set high.
  
   writeRegister(DATA_FORMAT, 0x01);    //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
   writeRegister(POWER_CTL, 0x08);   //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.  //Measurement mode  
  
  //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.
  Accelx = ((int)values[1]<<8)|(int)values[0];  //The X value is stored in values[0] and values[1].
  Accely = ((int)values[3]<<8)|(int)values[2];  //The Y value is stored in values[2] and values[3].
  Accelz = ((int)values[5]<<8)|(int)values[4];  //The Z value is stored in values[4] and values[5].
  }


void readSD()
{
Sd2Card card;
SdVolume volume;
SdFile root;
const int chipSelect = 15;   

 if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present."); 
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }
 // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }

  
  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  if (volumesize < 8388608ul) {
    Serial.print("Volume size (bytes): ");
    Serial.println(volumesize * 512);        // SD card blocks are always 512 bytes
  }
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 2;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop() 
{

 readSD();
   getgyro();
   Serial.print ("GX = ");
   Serial.print (gyrox);
   Serial.print(", GY = ");
   Serial.print (gyroy);
   Serial.print(", GZ = ");
   Serial.print (gyroz);
   Serial.print(" ");

   getaccel();
   Serial.print ("ACL X = ");
   Serial.print (Accelx);
   Serial.print(", ACL Y = ");
   Serial.print (Accely);
   Serial.print(", ACL Z = ");
   Serial.print (Accelz);
   Serial.println(" ");
   
   delay(500);
}




//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)
{
  digitalWrite(AccelCS, LOW);  //Set Chip Select pin low to signal the beginning of an SPI packet.
  SPI.transfer(registerAddress);  //Transfer the register address over SPI
  SPI.transfer(value);  //Transfer the desired register value over SPI.
  digitalWrite(AccelCS, HIGH);  //Set the Chip Select pin high to signal the end of an SPI packet.
}


//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(numBytes > 1)address = address | 0x40;  //If we're doing a multi-byte read, bit 6 needs to be set as well.
   digitalWrite(AccelCS, LOW); //Set the Chip select pin low to start an SPI packet.
   SPI.transfer(address); //Transfer the starting register address that needs to be read.
  for(int i=0; i<numBytes; i++)
  {
    values[i] = SPI.transfer(0x00);  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  }
  digitalWrite(AccelCS, HIGH);  //Set the Chips Select pin high to end the SPI packet.

}
 
Last edited:
I've tracked it down to usage of the SCL line.... the accel and gyro are happy using the same SCK line and will continue to work with the SD card board SCL line also connected. The SD card will work with the sensors SCL lines disconnected but stop when either is connected. I've moved the SCL line of the Gyro across to 14 and can now use the gyro and SD card together but not the accel.

The SCL line for the accel must be set within the library somewhere as I cant find how to change it in the main code. I'm happy to dedicate on digital output to the SD card in order to make it work so my question is in two parts really

1) Why is the SD card unhappy at sharing the same SCL line as the sensors and how should I go about fixing it so they can all play together
2) Is it just easier to move the SCL line of the SD card (or Accel) and if so where can I find the variable to change this setting.

As all programs run independently, port settings seem to be OK.
All SPI boards can share SCL,DI,DO only CS has to be different.

It seems however, that one of the SPI software implementation does not release the CS between write. Best is to check the CS lines with a logic analyzer, to see if CS stays low (i.e SD card software does not release SPI).

An initial workaround is to wait for SD card to be ready (there must be a API for that) pull SD-card CS high and get sensor data.
 
If you don't have a logic analyzer, you could set up your code to print out the state of the cs line after the operations were complete.
 
Or I imagine hooking up a LED (with a resistor connecting it to ground) to the CS line would also work, if it is being held down for long periods of time.
 
Thanks for the replies everyone, I'll try printing the CS line status at the end of each function or slow the functions down and check with an LED.
 
I seem to recall the Adafruit L3GD20 library does bit-bang SPI, instead of using the hardware SPI, unless they're changed that in more recent versions. I wonder if that could be causing the issue? Personally, I stopped using their library and just wrote the 3-4 functions I needed to get the values from that gyro using the real hardware SPI (MUCH faster! - though I was using an 8MHz 328p at the time)
 
Status
Not open for further replies.
Back
Top