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!
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: