T3.6, ADXL 345 SPI communication Difficulty

Status
Not open for further replies.
I am trying to read data from Adafruit ADXL345 breakout board onto Teensy 3.6 over SPI protocol. I can successfully read data using I2C on T3.6 and SPI on a Mega2560. For my application I need to read the data over SPI onto teensy.

My hardware is wired like this:

Teensy 3.6 | Adafruit ADXL345 breakout
10/CS0 | CS
11/MOSI0 | SDA
12/MISO0 | SDO
13/SCK0 | SCL
3.3V | VIN (not 3V3)
GND | GND

I am using Arduino IDE 1.8.5 with teensyduino 1.42.

I am using the example script that ships with the sparkfun ADXL345 library (I grabbed Paul Stoffregen's version from https://github.com/PaulStoffregen/SparkFun_ADXL345_Arduino_Library). I modified the example to output the raw values and skip reporting tap/freefall/etc. events. Code is at the end of this post.

The same code compiles for and gives sensible output on an arduino mega2560. When I load the code onto the T3.6 the serial shows:

Code:
SparkFun ADXL345 Accelerometer Hook Up Guide Example

-32640, 0, 0
-32640, 0, 0
-32640, 0, 0
-32640, 0, 0
-32640, 0, 0
-32640, 0, 0

On the mega2560 the serial shows sensible changes in output as I rotate the accelerometer board.

One possible explanation is that I had my MOSI/MISO lines switched. Could I have damaged the SPI port on T3.6 by having these switched? I'm hopeful this isn't the case as I tried the mega2560 before catching this mistake, so its pins were exposed to the same but it is now working.

My other hypothesis is that the logic level shifting included on the adafruit breakout board might be the cause of my woes? It's intended to allow use with 5V logic, but maybe it doesn't work fast enough when used at 3.3V?

Anyone have any ideas?

Code:
/*  ********************************************* 
 *  SparkFun_ADXL345_Example
 *  Triple Axis Accelerometer Breakout - ADXL345 
 *  Hook Up Guide Example 
 *  
 *  Utilizing Sparkfun's ADXL345 Library
 *  Bildr ADXL345 source file modified to support 
 *  both I2C and SPI Communication
 *  
 *  E.Robert @ SparkFun Electronics
 *  Created: Jul 13, 2016
 *  Updated: Sep 06, 2016
 *  
 *  Development Environment Specifics:
 *  Arduino 1.6.11
 *  
 *  Hardware Specifications:
 *  SparkFun ADXL345
 *  Arduino Uno
 *  *********************************************/

#include <SparkFun_ADXL345.h>         // SparkFun ADXL345 Library

/*********** COMMUNICATION SELECTION ***********/
/*    Comment Out The One You Are Not Using    */
ADXL345 adxl = ADXL345(10);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
//ADXL345 adxl = ADXL345();             // USE FOR I2C COMMUNICATION

/****************** INTERRUPT ******************/
/*      Uncomment If Attaching Interrupt       */
//int interruptPin = 2;                 // Setup pin 2 to be the interrupt pin (for most Arduino Boards)


/******************** SETUP ********************/
/*          Configure ADXL345 Settings         */
void setup(){
  delay(100);
  Serial.begin(9600);                 // Start the serial terminal
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  
  adxl.powerOn();                     // Power on the ADXL345

  adxl.setRangeSetting(8);           // Give the range settings
                                      // Accepted values are 2g, 4g, 8g or 16g
                                      // Higher Values = Wider Measurement Range
                                      // Lower Values = Greater Sensitivity

  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
                                      // Default: Set to 1
                                      // SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library 
   
  adxl.setActivityXYZ(1, 0, 0);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setActivityThreshold(75);      // 62.5mg per increment   // Set activity   // Inactivity thresholds (0-255)
 
  adxl.setInactivityXYZ(1, 0, 0);     // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setInactivityThreshold(75);    // 62.5mg per increment   // Set inactivity // Inactivity thresholds (0-255)
  adxl.setTimeInactivity(10);         // How many seconds of no activity is inactive?

  adxl.setTapDetectionOnXYZ(0, 0, 1); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF)
 
  // Set values for what is considered a TAP and what is a DOUBLE TAP (0-255)
  adxl.setTapThreshold(50);           // 62.5 mg per increment
  adxl.setTapDuration(15);            // 625 μs per increment
  adxl.setDoubleTapLatency(80);       // 1.25 ms per increment
  adxl.setDoubleTapWindow(200);       // 1.25 ms per increment
 
  // Set values for what is considered FREE FALL (0-255)
  adxl.setFreeFallThreshold(7);       // (5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(30);       // (20 - 70) recommended - 5ms per increment
 
  // Setting all interupts to take place on INT1 pin
  //adxl.setImportantInterruptMapping(1, 1, 1, 1, 1);     // Sets "adxl.setEveryInterruptMapping(single tap, double tap, free fall, activity, inactivity);" 
                                                        // Accepts only 1 or 2 values for pins INT1 and INT2. This chooses the pin on the ADXL345 to use for Interrupts.
                                                        // This library may have a problem using INT2 pin. Default to INT1 pin.
  
  // Turn on Interrupts for each mode (1 == ON, 0 == OFF)
  adxl.InactivityINT(1);
  adxl.ActivityINT(1);
  adxl.FreeFallINT(1);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);
  
  
//attachInterrupt(digitalPinToInterrupt(interruptPin), ADXL_ISR, RISING);   // Attach Interrupt

}

/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){
  
  // Accelerometer Readings
  int x,y,z;   
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  // Output Results to Serial
  /* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */  
  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z);
  
  //ADXL_ISR();
  // You may also choose to avoid using interrupts and simply run the functions within ADXL_ISR(); 
  //  and place it within the loop instead.  
  // This may come in handy when it doesn't matter when the action occurs. 
  delay(1);
}

/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  
  // getInterruptSource clears all triggered actions after returning value
  // Do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();
  
  // Free Fall Detection
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){
    Serial.println("*** FREE FALL ***");
    //add code here to do when free fall is sensed
  } 
  
  // Inactivity
  if(adxl.triggered(interrupts, ADXL345_INACTIVITY)){
    Serial.println("*** INACTIVITY ***");
     //add code here to do when inactivity is sensed
  }
  
  // Activity
  if(adxl.triggered(interrupts, ADXL345_ACTIVITY)){
    Serial.println("*** ACTIVITY ***"); 
     //add code here to do when activity is sensed
  }
  
  // Double Tap Detection
  if(adxl.triggered(interrupts, ADXL345_DOUBLE_TAP)){
    Serial.println("*** DOUBLE TAP ***");
     //add code here to do when a 2X tap is sensed
  }
  
  // Tap Detection
  if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}
 
ADXL345 data sheet says max SPI is 5mhz. you might modify library to use slower SPI clock.
Code:
ADXL345::ADXL345(int CS) {
	status = ADXL345_OK;
	error_code = ADXL345_NO_ERROR;
	
	gains[0] = 0.00376390;
	gains[1] = 0.00376009;
	gains[2] = 0.00349265;
	_CS = CS;
	I2C = false;
	SPI.begin();
	SPI.setDataMode(SPI_MODE3);
        [B]SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));[/B]
	pinMode(_CS, OUTPUT);
	digitalWrite(_CS, HIGH);
}
in Sparkfun lib https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library

older thread (relevant?) https://forum.pjrc.com/threads/46013-Teensy-3-2-ADXL345-and-SPI-comms
 
Thanks manitou, setting the speed to 4MHz as you have suggested resolved my problem, the same code now generates sensible results on the T3.6 (I haven't tried the mega2560 since making the change).
 
Hello!
I add that line in code what Manitou suggested, but for still isn't working. Do you have any suggestion ?
 
@Vuck0 - Always hard to know, when there is no code or context shown.
For example is this the only thing on the SPI buss? Or do you have something else like a display on your setup? If you have something else his one line change only updated the SPI at start of the stuff.

And I personally don't like their code here. In particular doing things like calling SPI.begin and setting pin states and the like as part of the constructor... You are often taking pot luck on when that code will be called and in what order and if the hardware is actually been initialized properly yet.

If it were me, I would probably start off, moving some stuff around. LIke:
The Constructor I would probably NOT do the SPI.begin stuff. Instead I would probably move it to the power up function like used for I2C... Something like:
Code:
ADXL345::ADXL345(int CS) {
	status = ADXL345_OK;
	error_code = ADXL345_NO_ERROR;

	gains[0] = 0.00376390;
	gains[1] = 0.00376009;
	gains[2] = 0.00349265;
	_CS = CS;
	I2C = false;
[COLOR="#FF0000"]#if 0
	SPI.begin();
	SPI.setDataMode(SPI_MODE3);
	// probably would also do the CS stuff below as well...
#endif[/COLOR]
	pinMode(_CS, OUTPUT);
	digitalWrite(_CS, HIGH);
}

void ADXL345::powerOn() {
	if(I2C) {
		Wire.begin();				// If in I2C Mode Only
	} 
	[COLOR="#FF0000"]else {
		SPI.begin();
	}[/COLOR]
	//ADXL345 TURN ON
	writeTo(ADXL345_POWER_CTL, 0);	// Wakeup
	writeTo(ADXL345_POWER_CTL, 16);	// Auto_Sleep
	writeTo(ADXL345_POWER_CTL, 8);	// Measure
}

I would then also change two functions that deal with Read and Write to SPI:
Code:
/************************** WRITE FROM SPI **************************/
/*         Point to Destination; Write Value; Turn Off              */
void ADXL345::writeToSPI(byte __reg_address, byte __val) {
  digitalWrite(_CS, LOW);
[COLOR="#FF0000"]  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));[/COLOR]
  SPI.transfer(__reg_address);
  SPI.transfer(__val);
[COLOR="#FF0000"]  SPI.endTransaction();[/COLOR]
  digitalWrite(_CS, HIGH);
}

/*************************** READ FROM SPI **************************/
/*                                                                  */
void ADXL345::readFromSPI(byte __reg_address, int num, byte _buff[]) {
  // Read: Most Sig Bit of Reg Address Set
  char _address = 0x80 | __reg_address;
  // If Multi-Byte Read: Bit 6 Set
  if(num > 1) {
  	_address = _address | 0x40;
  }

  digitalWrite(_CS, LOW);
[COLOR="#FF0000"]  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));[/COLOR]
  SPI.transfer(_address);		// Transfer Starting Reg Address To Be Read
  for(int i=0; i<num; i++){
    _buff[i] = SPI.transfer(0x00);
  }
[COLOR="#FF0000"]  SPI.endTransaction();[/COLOR]
  digitalWrite(_CS, HIGH);
}
And see if that worked. If it did, I would probably clean it up, a little and for example check to make sure SPI supports transactions, by doing this under #ifdef
Code:
#ifdef SPI_HAS_TRANSACTION
[COLOR="#FF0000"]  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));[/COLOR]
#endif
Maybe add #else to handle for other setups (probably not)...
Also probably would setup to not hard code to use SPI object, but allow object to be defined on other SPI objects, with option on constructor of which one defaulting to SPI...

And then try to issue a Pull Request back to the library owner on github
 
@KurtE Thanks for your answer!

Code:
/*  ********************************************* 
 *  SparkFun_ADXL345_Example
 *  Triple Axis Accelerometer Breakout - ADXL345 
 *  Hook Up Guide Example 
 *  
 *  Utilizing Sparkfun's ADXL345 Library
 *  Bildr ADXL345 source file modified to support 
 *  both I2C and SPI Communication
 *  
 *  E.Robert @ SparkFun Electronics
 *  Created: Jul 13, 2016
 *  Updated: Sep 06, 2016
 *  
 *  Development Environment Specifics:
 *  Arduino 1.6.11
 *  
 *  Hardware Specifications:
 *  SparkFun ADXL345
 *  Arduino Uno
 *  *********************************************/

#include <SparkFun_ADXL345.h>         // SparkFun ADXL345 Library

/*********** COMMUNICATION SELECTION ***********/
/*    Comment Out The One You Are Not Using    */
ADXL345 adxl = ADXL345(10);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
//ADXL345 adxl = ADXL345();             // USE FOR I2C COMMUNICATION

/****************** INTERRUPT ******************/
/*      Uncomment If Attaching Interrupt       */
//int interruptPin = 2;                 // Setup pin 2 to be the interrupt pin (for most Arduino Boards)


/******************** SETUP ********************/
/*          Configure ADXL345 Settings         */
void setup(){
  delay(100);
  Serial.begin(9600);                 // Start the serial terminal
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  
  adxl.powerOn();                     // Power on the ADXL345

  adxl.setRangeSetting(8);           // Give the range settings
                                      // Accepted values are 2g, 4g, 8g or 16g
                                      // Higher Values = Wider Measurement Range
                                      // Lower Values = Greater Sensitivity

  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
                                      // Default: Set to 1
                                      // SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library 
   
  adxl.setActivityXYZ(1, 0, 0);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setActivityThreshold(75);      // 62.5mg per increment   // Set activity   // Inactivity thresholds (0-255)
 
  adxl.setInactivityXYZ(1, 0, 0);     // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setInactivityThreshold(75);    // 62.5mg per increment   // Set inactivity // Inactivity thresholds (0-255)
  adxl.setTimeInactivity(10);         // How many seconds of no activity is inactive?

  adxl.setTapDetectionOnXYZ(0, 0, 1); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF)
 
  // Set values for what is considered a TAP and what is a DOUBLE TAP (0-255)
  adxl.setTapThreshold(50);           // 62.5 mg per increment
  adxl.setTapDuration(15);            // 625 μs per increment
  adxl.setDoubleTapLatency(80);       // 1.25 ms per increment
  adxl.setDoubleTapWindow(200);       // 1.25 ms per increment
 
  // Set values for what is considered FREE FALL (0-255)
  adxl.setFreeFallThreshold(7);       // (5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(30);       // (20 - 70) recommended - 5ms per increment
 
  // Setting all interupts to take place on INT1 pin
  //adxl.setImportantInterruptMapping(1, 1, 1, 1, 1);     // Sets "adxl.setEveryInterruptMapping(single tap, double tap, free fall, activity, inactivity);" 
                                                        // Accepts only 1 or 2 values for pins INT1 and INT2. This chooses the pin on the ADXL345 to use for Interrupts.
                                                        // This library may have a problem using INT2 pin. Default to INT1 pin.
  
  // Turn on Interrupts for each mode (1 == ON, 0 == OFF)
  adxl.InactivityINT(1);
  adxl.ActivityINT(1);
  adxl.FreeFallINT(1);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);
  
  
//attachInterrupt(digitalPinToInterrupt(interruptPin), ADXL_ISR, RISING);   // Attach Interrupt

}

/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){
  
  // Accelerometer Readings
  int x,y,z;   
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  // Output Results to Serial
  /* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */  
  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z);
  
  //ADXL_ISR();
  // You may also choose to avoid using interrupts and simply run the functions within ADXL_ISR(); 
  //  and place it within the loop instead.  
  // This may come in handy when it doesn't matter when the action occurs. 
  delay(1);
}

/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  
  // getInterruptSource clears all triggered actions after returning value
  // Do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();
  
  // Free Fall Detection
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){
    Serial.println("*** FREE FALL ***");
    //add code here to do when free fall is sensed
  } 
  
  // Inactivity
  if(adxl.triggered(interrupts, ADXL345_INACTIVITY)){
    Serial.println("*** INACTIVITY ***");
     //add code here to do when inactivity is sensed
  }
  
  // Activity
  if(adxl.triggered(interrupts, ADXL345_ACTIVITY)){
    Serial.println("*** ACTIVITY ***"); 
     //add code here to do when activity is sensed
  }
  
  // Double Tap Detection
  if(adxl.triggered(interrupts, ADXL345_DOUBLE_TAP)){
    Serial.println("*** DOUBLE TAP ***");
     //add code here to do when a 2X tap is sensed
  }
  
  // Tap Detection
  if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}


and library change

Code:
/*
Sparkfun's ADXL345 Library Main Source File
SparkFun_ADXL345.cpp

E.Robert @ SparkFun Electronics
Created: Jul 13, 2016
Updated: Sep 06, 2016

Modified Bildr ADXL345 Source File @ http://code.bildr.org/download/959.zip
to support both I2C and SPI Communication

Hardware Resources:
- Arduino Development Board
- SparkFun Triple Access Accelerometer ADXL345

Development Environment Specifics:
Arduino 1.6.8
SparkFun Triple Axis Accelerometer Breakout - ADXL345
Arduino Uno
*/

#include "Arduino.h"
#include "SparkFun_ADXL345.h"
#include <Wire.h>
#include <SPI.h>

#define ADXL345_DEVICE (0x53)    // Device Address for ADXL345
#define ADXL345_TO_READ (6)      // Number of Bytes Read - Two Bytes Per Axis

ADXL345::ADXL345() {
	status = ADXL345_OK;
	error_code = ADXL345_NO_ERROR;
	
	gains[0] = 0.00376390;		// Original gain 0.00376390 
	gains[1] = 0.00376009;		// Original gain 0.00376009
	gains[2] = 0.00349265;		// Original gain 0.00349265
	I2C = true;
}

ADXL345::ADXL345(int CS) {
	status = ADXL345_OK;
	error_code = ADXL345_NO_ERROR;
	
	gains[0] = 0.00376390;
	gains[1] = 0.00376009;
	gains[2] = 0.00349265;
	_CS = CS;
	I2C = false;
	SPI.begin();
	SPI.setDataMode(SPI_MODE3);
	// probably would also do the CS stuff below as well...
	pinMode(_CS, OUTPUT);
	digitalWrite(_CS, HIGH);
}
void ADXL345::powerOn() {
	if(I2C) {
		Wire.begin();				// If in I2C Mode Only
	}
	else {
		SPI.begin();
	}
	//ADXL345 TURN ON
	writeTo(ADXL345_POWER_CTL, 0);	// Wakeup     
	writeTo(ADXL345_POWER_CTL, 16);	// Auto_Sleep
	writeTo(ADXL345_POWER_CTL, 8);	// Measure
}


/*********************** READING ACCELERATION ***********************/
/*    Reads Acceleration into Three Variables:  x, y and z          */

void ADXL345::readAccel(int *xyz){
	readAccel(xyz, xyz + 1, xyz + 2);
}

void ADXL345::readAccel(int *x, int *y, int *z) {
	readFrom(ADXL345_DATAX0, ADXL345_TO_READ, _buff);	// Read Accel Data from ADXL345
	
	// Each Axis @ All g Ranges: 10 Bit Resolution (2 Bytes)
	*x = (int16_t)((((int)_buff[1]) << 8) | _buff[0]);
	*y = (int16_t)((((int)_buff[3]) << 8) | _buff[2]);
	*z = (int16_t)((((int)_buff[5]) << 8) | _buff[4]);
}

void ADXL345::get_Gxyz(double *xyz){
	int i;
	int xyz_int[3];
	readAccel(xyz_int);
	for(i=0; i<3; i++){
		xyz[i] = xyz_int[i] * gains[i];
	}
}

/***************** WRITES VALUE TO ADDRESS REGISTER *****************/
void ADXL345::writeTo(byte address, byte val) {
	if(I2C) {
		writeToI2C(address, val);
	}
	else {
		writeToSPI(address, val);
	}
}

/************************ READING NUM BYTES *************************/
/*    Reads Num Bytes. Starts from Address Reg to _buff Array        */
void ADXL345::readFrom(byte address, int num, byte _buff[]) {
	if(I2C) {
		readFromI2C(address, num, _buff);	// If I2C Communication
	}
	else {
		readFromSPI(address, num, _buff);	// If SPI Communication 
	}
}

/*************************** WRITE TO I2C ***************************/
/*      Start; Send Register Address; Send Value To Write; End      */
void ADXL345::writeToI2C(byte _address, byte _val) {
	Wire.beginTransmission(ADXL345_DEVICE); 
	Wire.write(_address);             
	Wire.write(_val);                 
	Wire.endTransmission();         
}

/*************************** READ FROM I2C **************************/
/*                Start; Send Address To Read; End                  */
void ADXL345::readFromI2C(byte address, int num, byte _buff[]) {
	Wire.beginTransmission(ADXL345_DEVICE);  
	Wire.write(address);             
	Wire.endTransmission();         
	
	Wire.beginTransmission(ADXL345_DEVICE); 
	Wire.requestFrom(ADXL345_DEVICE, num);  // Request 6 Bytes
	
	int i = 0;
	while(Wire.available())					
	{ 
		_buff[i] = Wire.read();				// Receive Byte
		i++;
	}
	if(i != num){
		status = ADXL345_ERROR;
		error_code = ADXL345_READ_ERROR;
	}
	Wire.endTransmission();         	
}

/************************** WRITE FROM SPI **************************/
/*         Point to Destination; Write Value; Turn Off              */
void ADXL345::writeToSPI(byte __reg_address, byte __val) {
  digitalWrite(_CS, LOW);
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
  SPI.transfer(__reg_address); 
  SPI.transfer(__val); 
  SPI.endTransaction();
  digitalWrite(_CS, HIGH); 
}

/*************************** READ FROM SPI **************************/
/*                                                                  */
void ADXL345::readFromSPI(byte __reg_address, int num, byte _buff[]) {
  // Read: Most Sig Bit of Reg Address Set
  char _address = 0x80 | __reg_address;
  // If Multi-Byte Read: Bit 6 Set 
  if(num > 1) {
  	_address = _address | 0x40;
  }

  digitalWrite(_CS, LOW);
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));
  SPI.transfer(_address);		// Transfer Starting Reg Address To Be Read  
  for(int i=0; i<num; i++){
    _buff[i] = SPI.transfer(0x00);
  }
  SPI.endTransaction();
  digitalWrite(_CS, HIGH);
}

/*************************** RANGE SETTING **************************/
/*          ACCEPTABLE VALUES: 2g, 4g, 8g, 16g ~ GET & SET          */
void ADXL345::getRangeSetting(byte* rangeSetting) {
	byte _b;
	readFrom(ADXL345_DATA_FORMAT, 1, &_b);
	*rangeSetting = _b & B00000011;
}

void ADXL345::setRangeSetting(int val) {
	byte _s;
	byte _b;
	
	switch (val) {
		case 2:  
			_s = B00000000; 
			break;
		case 4:  
			_s = B00000001; 
			break;
		case 8:  
			_s = B00000010; 
			break;
		case 16: 
			_s = B00000011; 
			break;
		default: 
			_s = B00000000;
	}
	readFrom(ADXL345_DATA_FORMAT, 1, &_b);
	_s |= (_b & B11101100);
	writeTo(ADXL345_DATA_FORMAT, _s);
}

/*************************** SELF_TEST BIT **************************/
/*                            ~ GET & SET                           */
bool ADXL345::getSelfTestBit() {
	return getRegisterBit(ADXL345_DATA_FORMAT, 7);
}

// If Set (1) Self-Test Applied. Electrostatic Force exerted on the sensor
//  causing a shift in the output data.
// If Set (0) Self-Test Disabled.
void ADXL345::setSelfTestBit(bool selfTestBit) {
	setRegisterBit(ADXL345_DATA_FORMAT, 7, selfTestBit);
}

/*************************** SPI BIT STATE **************************/
/*                           ~ GET & SET                            */
bool ADXL345::getSpiBit() {
	return getRegisterBit(ADXL345_DATA_FORMAT, 6);
}

// If Set (1) Puts Device in 3-wire Mode
// If Set (0) Puts Device in 4-wire SPI Mode
void ADXL345::setSpiBit(bool spiBit) {
	setRegisterBit(ADXL345_DATA_FORMAT, 6, spiBit);
}

/*********************** INT_INVERT BIT STATE ***********************/
/*                           ~ GET & SET                            */
bool ADXL345::getInterruptLevelBit() {
	return getRegisterBit(ADXL345_DATA_FORMAT, 5);
}

// If Set (0) Sets the Interrupts to Active HIGH
// If Set (1) Sets the Interrupts to Active LOW
void ADXL345::setInterruptLevelBit(bool interruptLevelBit) {
	setRegisterBit(ADXL345_DATA_FORMAT, 5, interruptLevelBit);
}

/************************* FULL_RES BIT STATE ***********************/
/*                           ~ GET & SET                            */
bool ADXL345::getFullResBit() {
	return getRegisterBit(ADXL345_DATA_FORMAT, 3);
}

// If Set (1) Device is in Full Resolution Mode: Output Resolution Increase with G Range
//  Set by the Range Bits to Maintain a 4mg/LSB Scale Factor
// If Set (0) Device is in 10-bit Mode: Range Bits Determine Maximum G Range
//  And Scale Factor
void ADXL345::setFullResBit(bool fullResBit) {
	setRegisterBit(ADXL345_DATA_FORMAT, 3, fullResBit);
}

/*************************** JUSTIFY BIT STATE **************************/
/*                           ~ GET & SET                            */
bool ADXL345::getJustifyBit() {
	return getRegisterBit(ADXL345_DATA_FORMAT, 2);
}

// If Set (1) Selects the Left Justified Mode
// If Set (0) Selects Right Justified Mode with Sign Extension
void ADXL345::setJustifyBit(bool justifyBit) {
	setRegisterBit(ADXL345_DATA_FORMAT, 2, justifyBit);
}

/*********************** THRESH_TAP BYTE VALUE **********************/
/*                          ~ SET & GET                             */
// Should Set Between 0 and 255
// Scale Factor is 62.5 mg/LSB
// A Value of 0 May Result in Undesirable Behavior
void ADXL345::setTapThreshold(int tapThreshold) {
	tapThreshold = constrain(tapThreshold,0,255);
	byte _b = byte (tapThreshold);
	writeTo(ADXL345_THRESH_TAP, _b);  
}

// Return Value Between 0 and 255
// Scale Factor is 62.5 mg/LSB
int ADXL345::getTapThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_TAP, 1, &_b);  
	return int (_b);
}

/****************** GAIN FOR EACH AXIS IN Gs / COUNT *****************/
/*                           ~ SET & GET                            */
void ADXL345::setAxisGains(double *_gains){
	int i;
	for(i = 0; i < 3; i++){
		gains[i] = _gains[i];
	}
}
void ADXL345::getAxisGains(double *_gains){
	int i;
	for(i = 0; i < 3; i++){
		_gains[i] = gains[i];
	}
}

/********************* OFSX, OFSY and OFSZ BYTES ********************/
/*                           ~ SET & GET                            */
// OFSX, OFSY and OFSZ: User Offset Adjustments in Twos Complement Format
// Scale Factor of 15.6mg/LSB
void ADXL345::setAxisOffset(int x, int y, int z) {
	writeTo(ADXL345_OFSX, byte (x));  
	writeTo(ADXL345_OFSY, byte (y));  
	writeTo(ADXL345_OFSZ, byte (z));  
}

void ADXL345::getAxisOffset(int* x, int* y, int*z) {
	byte _b;
	readFrom(ADXL345_OFSX, 1, &_b);  
	*x = int (_b);
	readFrom(ADXL345_OFSY, 1, &_b);  
	*y = int (_b);
	readFrom(ADXL345_OFSZ, 1, &_b);  
	*z = int (_b);
}

/****************************** DUR BYTE ****************************/
/*                           ~ SET & GET                            */
// DUR Byte: Contains an Unsigned Time Value Representing the Max Time 
//  that an Event must be Above the THRESH_TAP Threshold to qualify 
//  as a Tap Event
// The scale factor is 625µs/LSB
// Value of 0 Disables the Tap/Double Tap Funcitons. Max value is 255.
void ADXL345::setTapDuration(int tapDuration) {
	tapDuration = constrain(tapDuration,0,255);
	byte _b = byte (tapDuration);
	writeTo(ADXL345_DUR, _b);  
}

int ADXL345::getTapDuration() {
	byte _b;
	readFrom(ADXL345_DUR, 1, &_b);  
	return int (_b);
}

/************************** LATENT REGISTER *************************/
/*                           ~ SET & GET                            */
// Contains Unsigned Time Value Representing the Wait Time from the Detection
//  of a Tap Event to the Start of the Time Window (defined by the Window 
//  Register) during which a possible Second Tap Even can be Detected.
// Scale Factor is 1.25ms/LSB. 
// A Value of 0 Disables the Double Tap Function.
// It Accepts a Maximum Value of 255.
void ADXL345::setDoubleTapLatency(int doubleTapLatency) {
	byte _b = byte (doubleTapLatency);
	writeTo(ADXL345_LATENT, _b);  
}

int ADXL345::getDoubleTapLatency() {
	byte _b;
	readFrom(ADXL345_LATENT, 1, &_b);  
	return int (_b);
}

/************************** WINDOW REGISTER *************************/
/*                           ~ SET & GET                            */
// Contains an Unsigned Time Value Representing the Amount of Time 
//  After the Expiration of the Latency Time (determined by Latent register)
//  During which a Second Valid Tape can Begin. 
// Scale Factor is 1.25ms/LSB. 
// Value of 0 Disables the Double Tap Function. 
// It Accepts a Maximum Value of 255.
void ADXL345::setDoubleTapWindow(int doubleTapWindow) {
	doubleTapWindow = constrain(doubleTapWindow,0,255);
	byte _b = byte (doubleTapWindow);
	writeTo(ADXL345_WINDOW, _b);  
}

int ADXL345::getDoubleTapWindow() {
	byte _b;
	readFrom(ADXL345_WINDOW, 1, &_b);  
	return int (_b);
}

/*********************** THRESH_ACT REGISTER ************************/
/*                          ~ SET & GET                             */
// Holds the Threshold Value for Detecting Activity.
// Data Format is Unsigned, so the Magnitude of the Activity Event is Compared 
//  with the Value is Compared with the Value in the THRESH_ACT Register. 
// The Scale Factor is 62.5mg/LSB. 
// Value of 0 may Result in Undesirable Behavior if the Activity Interrupt Enabled. 
// It Accepts a Maximum Value of 255.
void ADXL345::setActivityThreshold(int activityThreshold) {
	activityThreshold = constrain(activityThreshold,0,255);
	byte _b = byte (activityThreshold);
	writeTo(ADXL345_THRESH_ACT, _b);  
}

// Gets the THRESH_ACT byte
int ADXL345::getActivityThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_ACT, 1, &_b);  
	return int (_b);
}

/********************** THRESH_INACT REGISTER ***********************/
/*                          ~ SET & GET                             */
// Holds the Threshold Value for Detecting Inactivity.
// The Data Format is Unsigned, so the Magnitude of the INactivity Event is 
//  Compared with the value in the THRESH_INACT Register. 
// Scale Factor is 62.5mg/LSB. 
// Value of 0 May Result in Undesirable Behavior if the Inactivity Interrupt Enabled. 
// It Accepts a Maximum Value of 255.
void ADXL345::setInactivityThreshold(int inactivityThreshold) {
	inactivityThreshold = constrain(inactivityThreshold,0,255);
	byte _b = byte (inactivityThreshold);
	writeTo(ADXL345_THRESH_INACT, _b);  
}

int ADXL345::getInactivityThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_INACT, 1, &_b);  
	return int (_b);
}

/*********************** TIME_INACT RESIGER *************************/
/*                          ~ SET & GET                             */
// Contains an Unsigned Time Value Representing the Amount of Time that
//  Acceleration must be Less Than the Value in the THRESH_INACT Register
//  for Inactivity to be Declared. 
// Uses Filtered Output Data* unlike other Interrupt Functions
// Scale Factor is 1sec/LSB. 
// Value Must Be Between 0 and 255. 
void ADXL345::setTimeInactivity(int timeInactivity) {
	timeInactivity = constrain(timeInactivity,0,255);
	byte _b = byte (timeInactivity);
	writeTo(ADXL345_TIME_INACT, _b);  
}

int ADXL345::getTimeInactivity() {
	byte _b;
	readFrom(ADXL345_TIME_INACT, 1, &_b);  
	return int (_b);
}

/*********************** THRESH_FF Register *************************/
/*                          ~ SET & GET                             */
// Holds the Threshold Value, in Unsigned Format, for Free-Fall Detection
// The Acceleration on all Axes is Compared with the Value in THRES_FF to
//  Determine if a Free-Fall Event Occurred. 
// Scale Factor is 62.5mg/LSB. 
// Value of 0 May Result in Undesirable Behavior if the Free-Fall interrupt Enabled.
// Accepts a Maximum Value of 255.
void ADXL345::setFreeFallThreshold(int freeFallThreshold) {
	freeFallThreshold = constrain(freeFallThreshold,0,255);
	byte _b = byte (freeFallThreshold);
	writeTo(ADXL345_THRESH_FF, _b);  
}

int ADXL345::getFreeFallThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_FF, 1, &_b);  
	return int (_b);
}

/************************ TIME_FF Register **************************/
/*                          ~ SET & GET                             */
// Stores an Unsigned Time Value Representing the Minimum Time that the Value 
//  of all Axes must be Less Than THRES_FF to Generate a Free-Fall Interrupt.
// Scale Factor is 5ms/LSB. 
// Value of 0 May Result in Undesirable Behavior if the Free-Fall Interrupt Enabled.
// Accepts a Maximum Value of 255.
void ADXL345::setFreeFallDuration(int freeFallDuration) {
	freeFallDuration = constrain(freeFallDuration,0,255);  
	byte _b = byte (freeFallDuration);
	writeTo(ADXL345_TIME_FF, _b);  
}

int ADXL345::getFreeFallDuration() {
	byte _b;
	readFrom(ADXL345_TIME_FF, 1, &_b);  
	return int (_b);
}

/************************** ACTIVITY BITS ***************************/
/*                                                                  */
bool ADXL345::isActivityXEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 6); 
}
bool ADXL345::isActivityYEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 5); 
}
bool ADXL345::isActivityZEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 4); 
}
bool ADXL345::isInactivityXEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 2); 
}
bool ADXL345::isInactivityYEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 1); 
}
bool ADXL345::isInactivityZEnabled() {  
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 0); 
}

void ADXL345::setActivityX(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 6, state); 
}
void ADXL345::setActivityY(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 5, state); 
}
void ADXL345::setActivityZ(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 4, state); 
}
void ADXL345::setActivityXYZ(bool stateX, bool stateY, bool stateZ) {
	setActivityX(stateX);
	setActivityY(stateY);
	setActivityZ(stateZ);
}
void ADXL345::setInactivityX(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 2, state); 
}
void ADXL345::setInactivityY(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 1, state); 
}
void ADXL345::setInactivityZ(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 0, state); 
}
void ADXL345::setInactivityXYZ(bool stateX, bool stateY, bool stateZ) {
	setInactivityX(stateX);
	setInactivityY(stateY);
	setInactivityZ(stateZ);
}

bool ADXL345::isActivityAc() { 
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 7); 
}
bool ADXL345::isInactivityAc(){ 
	return getRegisterBit(ADXL345_ACT_INACT_CTL, 3); 
}

void ADXL345::setActivityAc(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 7, state); 
}
void ADXL345::setInactivityAc(bool state) {  
	setRegisterBit(ADXL345_ACT_INACT_CTL, 3, state); 
}

/************************* SUPPRESS BITS ****************************/
/*                                                                  */
bool ADXL345::getSuppressBit(){ 
	return getRegisterBit(ADXL345_TAP_AXES, 3); 
}
void ADXL345::setSuppressBit(bool state) {  
	setRegisterBit(ADXL345_TAP_AXES, 3, state); 
}

/**************************** TAP BITS ******************************/
/*                                                                  */
bool ADXL345::isTapDetectionOnX(){ 
	return getRegisterBit(ADXL345_TAP_AXES, 2); 
}
void ADXL345::setTapDetectionOnX(bool state) {  
	setRegisterBit(ADXL345_TAP_AXES, 2, state); 
}
bool ADXL345::isTapDetectionOnY(){ 
	return getRegisterBit(ADXL345_TAP_AXES, 1); 
}
void ADXL345::setTapDetectionOnY(bool state) {  
	setRegisterBit(ADXL345_TAP_AXES, 1, state); 
}
bool ADXL345::isTapDetectionOnZ(){ 
	return getRegisterBit(ADXL345_TAP_AXES, 0); 
}
void ADXL345::setTapDetectionOnZ(bool state) {  
	setRegisterBit(ADXL345_TAP_AXES, 0, state); 
}

void ADXL345::setTapDetectionOnXYZ(bool stateX, bool stateY, bool stateZ) {
	setTapDetectionOnX(stateX);
	setTapDetectionOnY(stateY);
	setTapDetectionOnZ(stateZ);
}

bool ADXL345::isActivitySourceOnX(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 6); 
}
bool ADXL345::isActivitySourceOnY(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 5); 
}
bool ADXL345::isActivitySourceOnZ(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 4); 
}

bool ADXL345::isTapSourceOnX(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 2); 
}
bool ADXL345::isTapSourceOnY(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 1); 
}
bool ADXL345::isTapSourceOnZ(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 0); 
}

/*************************** ASLEEP BIT *****************************/
/*                                                                  */
bool ADXL345::isAsleep(){ 
	return getRegisterBit(ADXL345_ACT_TAP_STATUS, 3); 
}

/************************** LOW POWER BIT ***************************/
/*                                                                  */
bool ADXL345::isLowPower(){ 
	return getRegisterBit(ADXL345_BW_RATE, 4); 
}
void ADXL345::setLowPower(bool state) {  
	setRegisterBit(ADXL345_BW_RATE, 4, state); 
}

/*************************** RATE BITS ******************************/
/*                                                                  */
double ADXL345::getRate(){
	byte _b;
	readFrom(ADXL345_BW_RATE, 1, &_b);
	_b &= B00001111;
	return (pow(2,((int) _b)-6)) * 6.25;
}

void ADXL345::setRate(double rate){
	byte _b,_s;
	int v = (int) (rate / 6.25);
	int r = 0;
	while (v >>= 1)
	{
		r++;
	}
	if (r <= 9) { 
		readFrom(ADXL345_BW_RATE, 1, &_b);
		_s = (byte) (r + 6) | (_b & B11110000);
		writeTo(ADXL345_BW_RATE, _s);
	}
}

/*************************** BANDWIDTH ******************************/
/*                          ~ SET & GET                             */
void ADXL345::set_bw(byte bw_code){
	if((bw_code < ADXL345_BW_0_05) || (bw_code > ADXL345_BW_1600)){
		status = false;
		error_code = ADXL345_BAD_ARG;
	}
	else{
		writeTo(ADXL345_BW_RATE, bw_code);
	}
}

byte ADXL345::get_bw_code(){
	byte bw_code;
	readFrom(ADXL345_BW_RATE, 1, &bw_code);
	return bw_code;
}




/************************* TRIGGER CHECK  ***************************/
/*                                                                  */
// Check if Action was Triggered in Interrupts
// Example triggered(interrupts, ADXL345_SINGLE_TAP);
bool ADXL345::triggered(byte interrupts, int mask){
	return ((interrupts >> mask) & 1);
}

/*
 ADXL345_DATA_READY
 ADXL345_SINGLE_TAP
 ADXL345_DOUBLE_TAP
 ADXL345_ACTIVITY
 ADXL345_INACTIVITY
 ADXL345_FREE_FALL
 ADXL345_WATERMARK
 ADXL345_OVERRUNY
 */


byte ADXL345::getInterruptSource() {
	byte _b;
	readFrom(ADXL345_INT_SOURCE, 1, &_b);
	return _b;
}

bool ADXL345::getInterruptSource(byte interruptBit) {
	return getRegisterBit(ADXL345_INT_SOURCE,interruptBit);
}

bool ADXL345::getInterruptMapping(byte interruptBit) {
	return getRegisterBit(ADXL345_INT_MAP,interruptBit);
}

/*********************** INTERRUPT MAPPING **************************/
/*         Set the Mapping of an Interrupt to pin1 or pin2          */
// eg: setInterruptMapping(ADXL345_INT_DOUBLE_TAP_BIT,ADXL345_INT2_PIN);
void ADXL345::setInterruptMapping(byte interruptBit, bool interruptPin) {
	setRegisterBit(ADXL345_INT_MAP, interruptBit, interruptPin);
}

void ADXL345::setImportantInterruptMapping(int single_tap, int double_tap, int free_fall, int activity, int inactivity) {
	if(single_tap == 1) {
		setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );}
	else if(single_tap == 2) {
		setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT2_PIN );}

	if(double_tap == 1) {
		setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );}
	else if(double_tap == 2) {
		setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT2_PIN );}

	if(free_fall == 1) {
		setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,   ADXL345_INT1_PIN );}
	else if(free_fall == 2) {
		setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,   ADXL345_INT2_PIN );}

	if(activity == 1) {
		setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,   ADXL345_INT1_PIN );}
	else if(activity == 2) {
		setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,   ADXL345_INT2_PIN );}

	if(inactivity == 1) {
		setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );}
	else if(inactivity == 2) {
		setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT2_PIN );}
}

bool ADXL345::isInterruptEnabled(byte interruptBit) {
	return getRegisterBit(ADXL345_INT_ENABLE,interruptBit);
}

void ADXL345::setInterrupt(byte interruptBit, bool state) {
	setRegisterBit(ADXL345_INT_ENABLE, interruptBit, state);
}

void ADXL345::singleTapINT(bool status) {
	if(status) {
		setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
	}
	else {
		setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 0);
	}
}
void ADXL345::doubleTapINT(bool status) {
	if(status) {
		setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
	}
	else {
		setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 0);		
	}	
}
void ADXL345::FreeFallINT(bool status) {
	if(status) {
		setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
	}
	else {
		setInterrupt( ADXL345_INT_FREE_FALL_BIT,  0);
	}	
}
void ADXL345::ActivityINT(bool status) {
	if(status) {
		setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
	}
	else {
		setInterrupt( ADXL345_INT_ACTIVITY_BIT,   0);
	}
}
void ADXL345::InactivityINT(bool status) {
	if(status) {
		setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
	}
	else {
		setInterrupt( ADXL345_INT_INACTIVITY_BIT, 0);
	}
}

void ADXL345::setRegisterBit(byte regAdress, int bitPos, bool state) {
	byte _b;
	readFrom(regAdress, 1, &_b);
	if (state) {
		_b |= (1 << bitPos);  // Forces nth Bit of _b to 1. Other Bits Unchanged.  
	} 
	else {
		_b &= ~(1 << bitPos); // Forces nth Bit of _b to 0. Other Bits Unchanged.
	}
	writeTo(regAdress, _b);  
}

bool ADXL345::getRegisterBit(byte regAdress, int bitPos) {
	byte _b;
	readFrom(regAdress, 1, &_b);
	return ((_b >> bitPos) & 1);
}

/********************************************************************/
/*                                                                  */
// Print Register Values to Serial Output =
// Can be used to Manually Check the Current Configuration of Device
void ADXL345::printAllRegister() {
	byte _b;
	Serial.print("0x00: ");
	readFrom(0x00, 1, &_b);
	print_byte(_b);
	Serial.println("");
	int i;
	for (i=29;i<=57;i++){
		Serial.print("0x");
		Serial.print(i, HEX);
		Serial.print(": ");
		readFrom(i, 1, &_b);
		print_byte(_b);
		Serial.println("");    
	}
}

void print_byte(byte val){
	int i;
	Serial.print("B");
	for(i=7; i>=0; i--){
		Serial.print(val >> i & 1, BIN);
	}
}



Wiring: GND-GND, VCC -3.3, CS - 10, SD0-12, SDA-11, SCL -13 , CPU speed 180 Mhz for serial print, and still doesn't working :(
 
Pictures might help. Example how are the pins connected? Breadboard? If so are Teensy pins soldered to the Teensy...
I mention this as it has been several times where someone has tried to use friction from pins to teensy and spent a long time debugging to find out that they did not have proper electrical connection.

Also when you say is not working. What output is showing up in the Serial Monitor?

Note: I will often add in code to wait for awhile for Serial monitor to start so I can see the output. Something like:
Code:
void setup(){
  delay(100);
  Serial.begin(9600);                 // Start the serial terminal
 [COLOR="#B22222"] while (!Serial && millis() < 5000) ; // wait up to 5 seconds for Serial monitor to be connected. 
[/COLOR]
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();

If things are hooked up correctly and no other things on SPI pins and... Then if you are not getting any debug at all, then I would probably add some more Serial.print statements after each area to see where I got to.

Also hint. Sometimes if hard crash, then some stuff in Serial prints may not make it out of the buffers...

In those cases I may add in flush Again like:
Code:
...
  adxl.powerOn();                     // Power on the ADXL345

  adxl.setRangeSetting(8);           // Give the range settings
                                      // Accepted values are 2g, 4g, 8g or 16g
                                      // Higher Values = Wider Measurement Range
                                      // Lower Values = Greater Sensitivity
  Serial.println("After set Range Settings"); Serial.flush();
But again what I would do depends on what actually is happening (or not)
 
Pins are connected on a breadboard like this: wiring.PNG, I find this picture on internet, i connected the same way, just with teensy 3.6
And on my Serial Monitor is: Serial Monitor.PNG
 
Again as I was trying to say, seeing an actual picture of YOUR setup might help. For example it might show non-existing or bad solder connections and/or solder bridging...

I also noticed you commented out the call to the call to ADXL_ISR
Not sure if it is needed or not. But the example sketch calls it.
 
@Vucko, as Kurt suggests, photos of your wiring/soldering etc. would be beneficial.

Other things to try:
Add while(!Serial); after Serial.begin(9600); (I don't have ADXL345, so with nothing connected to T3.6, your sketch prints -1, -1, -1 forever as expected with nothing hooked to SPI pins)

Do you have another 3.3v SPI device you can test with your T3.6? That would confirm T3.6 SPI is working. Lacking that, remove all connections from your T3.6 and just jumper pin 11 to pin 12 and run this little sketch:
Code:
// spi test  jumper pin 12 to pin 11

#include <SPI.h>

#define CS 10
#define SPICLOCK 4000000
#define SPI_BUFF_SIZE 1024
uint8_t rx_buffer[SPI_BUFF_SIZE];
uint8_t tx_buffer[SPI_BUFF_SIZE];

void setup() {
  Serial.begin(9600); while (!Serial);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
  SPI.begin();
  SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
}

void loop() {
  uint32_t t1;
  float mbs;

  // jumper MOSI to MISO
  for (int i = 0; i < SPI_BUFF_SIZE; i++) tx_buffer[i] = i;
  memset(rx_buffer, 0, SPI_BUFF_SIZE);
  digitalWrite(CS, LOW);
  SPI.transfer(tx_buffer, rx_buffer, SPI_BUFF_SIZE);
  digitalWrite(CS, HIGH);
  int errs = 0;
  for (int i = 0; i < SPI_BUFF_SIZE; i++) if (tx_buffer[i] != rx_buffer[i]) errs++;
  Serial.printf("errs %d  \n", errs);
  delay(3000);
}
Serial monitor should report "errs 0"

If T3.6 SPI is not working perhaps in your early experiments you connected 5v to sparkfun ADXL345 and fried some of the T3.6 SPI pins. T3.6 is NOT 5v tolerant.

Do you have another Teensy (3.2 or 3.5) with which you can test the ADXL345?


I am using Arduino IDE 1.8.5 with teensyduino 1.42.
You might also try upgrading to latest Arudino IDE and latest teensyduino ..

are you using this breakout board? https://www.sparkfun.com/products/9836
 
Last edited:
I hooked up Sparkfun ADXL345 to T3.6 and made the speed change to the library as described in post #2, and it works for me.
Code:
-1, -1, 31
-1, -1, 31
*** DOUBLE TAP ***
*** TAP ***
-1, -1, 31
-2, -1, 32
Also works at 5 mhz, SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3)); Worked on T3.5 too.
 
Last edited:
Hello. This code works on a Teensy 3.6 with 3 GY-291s and saves the data on a SD card. I should place each GY-291 in the appropriate range, so one at +/- 2g, the other at +/- 4g, etc. Do you have an idea how to do that in this code? Thanks!
#include <SD.h>
#include <stdio.h>
#include <SPI.h> // SPI library


#define POWER_CTL_Register 0x2D // B101101
#define DATA_FORMAT_Register 0x31 // B110001
#define DATAX0_Register 0x32 // B110010

#define SIX_BYTES 6

int16_t accelX1;
int16_t accelY1;
int16_t accelZ1;

int16_t accelX2;
int16_t accelY2;
int16_t accelZ2;

int16_t accelX3;
int16_t accelY3;
int16_t accelZ3;

byte buffer[6];

void setup()
{
// Open Serial port to the User
Serial.begin(9600);

// Initialise the SD card read/writer
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("SD failed");
}

// Start SPI bus
SPI.begin();

// Power on the ADXL345 on CS pin 10
// If you have multiple ADXL345 they require their own CS pin
// The pins must be CS compatable, e.g. identified as a possible CS on the pinout
// Teensy 3.6 has pins 9,10,20,(21 untested),(15 untested)
TurnOnADXL345(9);
TurnOnADXL345(10);
TurnOnADXL345(20);
}

void loop(){

// Accelerometer Readings
// Please note these are uncalibrated numbers

// Read SPI device on CS pin 9
readAccel(9, &accelX1, &accelY1, &accelZ1);

// Read SPI device on CS pin 10
readAccel(10, &accelX2, &accelY2, &accelZ2);

// Read SPI device on CS pin 20
readAccel(20, &accelX3, &accelY3, &accelZ3);

// Print out the accelerator readings
// The resolution of the values is 2^10 = 1024
// Now we have positive and negative numbers, so resolution is +/- 512
// We have set 2g, so 2g = 512
// So we need to multiple by 2 and divide by 512 to get units of gravity.

// A clock is alway useful
Serial.print(millis());
Serial.print(",\t");

// Update the User
Serial.print(accelX1*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelY1*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelZ1*2.0f/512,3);
Serial.print(" g\t\t");

Serial.print(accelX2*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelY2*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelZ2*2.0f/512,3);
Serial.print(" g\t\t");

Serial.print(accelX3*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelY3*2.0f/512,3);
Serial.print(",\t");
Serial.print(accelZ3*2.0f/512,3);
Serial.println(" g");

// Create a File object to save to SD card
// A file name too large do not work. 8 characters is good.
File dataFile = SD.open("ADXL345.txt", FILE_WRITE);

// If the file can be opened, write to it
if (dataFile)
{
dataFile.print(millis());
dataFile.print(",\t");
dataFile.print(accelX1*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelY1*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelZ1*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelX2*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelY2*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelZ2*2.0f/512,3);
dataFile.print(" ,\t");
dataFile.print(accelX3*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelY3*2.0f/512,3);
dataFile.print(",\t");
dataFile.print(accelZ3*2.0f/512,3);
dataFile.println(", g");

dataFile.close();
}
}

void TurnOnADXL345(int16_t pinCS)
{
// We control this pin
pinMode(pinCS, OUTPUT);

// Don't let the pin float - so set it to a value.
// HIGH means we are not talking to it.
digitalWrite(pinCS, HIGH);

// POWER_CTL_Register
// D7
// D6
// D5 Link = 0
// D4 AUTO_SLEEP = 0
// D3 Measure = 1
// D2 Sleep = 0
// D1 Wakeup = 0
// D0 Wakeup = 0

// Wakeup device
// D1 = 0 & D0 = 0, reading frequency 8Hz
// Puts the ADXL345 into measurement mode
writeSPIregister(pinCS, POWER_CTL_Register, 8);

// Set accelerator range e.g. min range = max sensitivity

// Register 0x31 - DATA FORMAT (Read/Write) page 17 of 24
// D7 - SELF_TEST = 0 Disables the self-test force
// D6 - SPI = 0 Sets the device to 4-wire SPI mode
// D5 - INT_INVERT = 0 Sets interrupts to active HIGH
// D4 - 0
// D3 - FULL_RES = 0 Sets device ro 10-bit mode, and range set to max g range
// D2 - Justify = 0 Set right justified mode with sign extension
// D1 - Range
// D0 - Range

// _s = B00000000; for 2g
// _s = B00000001; for 4g
// _s = B00000010; for 8g
// _s = B00000011; for 16g

// Want 2g range, so maximum sensitivity
byte cmd = B00000000;

// Update the SPI register
writeSPIregister(pinCS, DATA_FORMAT_Register, cmd);
}

void readAccel(int16_t pinCS, int16_t *x, int16_t *y, int16_t *z)
{
// Read six bytes from the SPI
readSPIregister(pinCS, DATAX0_Register, SIX_BYTES, buffer);

// 10 Bit resolution accuracy
*x = (((int16_t)buffer[1]) << 8) | buffer[0];
*y = (((int16_t)buffer[3]) << 8) | buffer[2];
*z = (((int16_t)buffer[5]) << 8) | buffer[4];
}

// ======== SPI commands ===========

void writeSPIregister(int16_t pinCS, byte RegisterAddress, byte cmd)
{
// Define SPI bus parameters
// Max SPI clock frequency 5 MHz - page 8 of 24
// Mode Clock Polarity Clock Phase Output_Edge Data_Capture
// SPI_MODE3 (CPOL)1 (CPHA) 1 Falling Rising
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));

// We want to communicate with this SPI slave
digitalWrite(pinCS, LOW);

// This is the register we want
SPI.transfer(RegisterAddress);

// This is the command/value we set
SPI.transfer(cmd);

// Ok all done. Stop communication with this SPI slave
digitalWrite(pinCS, HIGH);

// Allow others to use SPI bus
SPI.endTransaction();
}

void readSPIregister(int16_t pinCS, byte RegisterAddress, int16_t num, byte buffer[])
{
// Need to set left bit in register address to enable Read Data
byte readRegisterAddress = 0x80 | RegisterAddress;

// Read Data + Address Increment
// To read or write multiple bytes in a single transmission, the multiple-byte bit, located after the R/W bit
// in the first byte transfer, must be set. After the register addressing and the first byte of data, each
// subsequent set of clock pulses (eight clock pulses) causes the ADXL345 to point to the next register for
// a read or write.
if(num > 1)
{
// Set bit to enable address increment
// 0x40 = B01000000
readRegisterAddress = readRegisterAddress | 0x40;
}

// Define SPI bus parameters
// Max SPI clock frequency 5 MHz - page 8 of 24
// Mode Clock Polarity Clock Phase Output_Edge Data_Capture
// SPI_MODE3 (CPOL)1 (CPHA) 1 Falling Rising
SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));

// We want to communicate with this SPI slave
digitalWrite(pinCS, LOW);

// This is the register we want
SPI.transfer(readRegisterAddress);

// Read the consecutive bytes
for (int16_t i=0; i<num; i++)
{
// Receiving buffer whilst transmitting 0x00
buffer = SPI.transfer(0x00);
}

// Ok all done. Stop communication with this SPI slave
digitalWrite(pinCS, HIGH);

// Allow others to use SPI bus
SPI.endTransaction();
}


 
Status
Not open for further replies.
Back
Top