Teensy 3.2, ADXL345, and SPI comms

Status
Not open for further replies.

lamey

Member
Hi all!

I've recently finished my first prototype of a project in an Arduino Uno involving an ADXL345 with an SPI comms, and Sparkfun ADXL345 library. I had to migrate to a Teensy 3.2 because of power and packaging size requirements, however, it seems that the ADXL345 does one of the following:

- returns non-changing values
- returns random values
- triggers certain registered interrupts

I've followed Sparkfun's hookup guide https://learn.sparkfun.com/tutorials/adxl345-hookup-guide, and have utilized their samples to test my accelerometer being integrated with the teensy board but no gives. Since Teensy 3.2 also has an SPI port in pins 10-13, i don't think there would be any problems with the connections. Below is how I connected the said connections:
Teensy 3.2ADXL345
3.3VVDD
GNDGND
10CS
11DI
12DO
13CLK

Here is my sample code for reference (note: I have modified Sparkfun's sample for testing):
Code:
#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);

/****************** VARIABLES ******************/
/*                                             */
int AccelMinX = 0;
int AccelMaxX = 0;
int AccelMinY = 0;
int AccelMaxY = 0;
int AccelMinZ = 0;
int AccelMaxZ = 0; 
int x,y,z;   

// for 16g
#define offsetX   -1       // OFFSET values
#define offsetY   -25
#define offsetZ   41

#define gainX     -4        // GAIN factors
#define gainY     -4
#define gainZ     4

/*//for 2g
#define offsetX   -2       // OFFSET values
#define offsetY   -193
#define offsetZ   277

#define gainX     -29        // GAIN factors
#define gainY     -28
#define gainZ     24*/

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

  adxl.setRangeSetting(16);           // 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.setRate(100);
   
  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(0);
  adxl.ActivityINT(0);
  adxl.FreeFallINT(0);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);

}

/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){
  obtainSample();
  ADXL_ISR();
  delay(1000);
}

void obtainSample(){
  
  // Accelerometer Readings
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  
  /* Note: Must perform offset and gain calculations prior to seeing updated results
  /  Refer to SparkFun ADXL345 Hook Up Guide: [url]https://learn.sparkfun.com/tutorials/adxl345-hookup-guide[/url]
  /  offsetAxis = 0.5 * (Acel+1g + Accel-1g)
  /  gainAxis = 0.5 * ((Acel+1g - Accel-1g)/1g) */

  // UNCOMMENT SECTION TO VIEW NEW VALUES
  x = (x - offsetX)/gainX;         // Calculating New Values for X, Y and Z
  y = (y - offsetY)/gainY;
  z = (z - offsetZ)/gainZ;
  
  if(x < AccelMinX) AccelMinX = x;
  if(x > AccelMaxX) AccelMaxX = x;

  if(y < AccelMinY) AccelMinY = y;
  if(y > AccelMaxY) AccelMaxY = y;

  if(z < AccelMinZ) AccelMinZ = z;
  if(z > AccelMaxZ) AccelMaxZ = z;
}

/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  byte interrupts = adxl.getInterruptSource();
  
  // 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
  } else if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}
My question now is should I normally experience such behavior with Sparkfun ADXL345 library and Teensy3.2? Have others experienced this as well? If it does not work, what alternative could I use instead? Please help, thanks!

Lamey
 
as the hookup guide suggests, in loop() you might print out x,y,z after obtainSample() to see if your sketch is seeing changing values as you wiggle the breakout board
 
Thank you for your reply manitou!

Yea the thing is I have already integrated the accelerometer with the uno before and it worked perfectly. Once I have tried it out with the Teensy however, the values doesn't seem to change, even if acceleration is applied to the board (i.e., wiggling, moving). Sometimes the values does change, but the changes occur while the accelerometer is at rest. Such characteristics have not occured when I tried it out with the Uno. Note that I've connected them via the same pins as with the Teensy (D10 - D13), with the circuitry for the Uno circuit utilizing a Logic Level Shifter in between.
 
can you attach a photo of your hookup -- maybe you have MOSI/MISO reversed...

Teensy pin 12 should go to SDO, and 11 to SDA on breakout
 
Last edited:
I've utilized an ADXL345 breakout board from the local store, below is how I've hooked the ADXL345 to the Teensy3.2.

Hookup:
View attachment 11378

Below are separate images of ADXL345 and Teensy 3.2.

ADXL345:
View attachment 11379

Teensy 3.2:
View attachment 11380

If the images aren't clear, this is how I've hooked the ADXL345 up

Teensy 3.2 --- ADXL345
3.3V ------------VDD
GND ------------GND
10 ---------------CS
11 ---------------DO/SDO
12----------------DI/SDA
13 ---------------CLK/SCK

NOTES:

EDIT
The ADXL345's DI and DO pins are quite subjective, but I think it means that it's DI should go to the microcontroller's MOSI, and it's DO should go to the Microcontroller's MISO. Nevertheless, I've also tried interchanging the two lines and reuploading the code and restarting the microcontroller, but still to no avail.

I've previously hooked up an OLED Screen to the Teensy 3.2 using the ADAFRUIT SSD1306 Library (utilizing SPI pins 10 - 13) and it worked perfectly. I have retried utilizing an Arduino Uno to ensure if the ADXL345 is still working. I've implemented it via the same layout as shown to the table above, only difference is that the Arduino Uno implementation has a Voltage Level Shifter in between the SPI lines. I've utilized the code below for testing (Only difference with before is that the current code now prints values obtained from the accelerometer), and it worked perfectly. I've also utilized the same code with the Teensy 3.2.

Code:
#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);

/****************** VARIABLES ******************/
/*                                             */
int AccelMinX = 0;
int AccelMaxX = 0;
int AccelMinY = 0;
int AccelMaxY = 0;
int AccelMinZ = 0;
int AccelMaxZ = 0; 
int x,y,z;   

// for 16g
#define offsetX   -1       // OFFSET values
#define offsetY   -25
#define offsetZ   41

#define gainX     -4        // GAIN factors
#define gainY     -4
#define gainZ     4

/*//for 2g
#define offsetX   -2       // OFFSET values
#define offsetY   -193
#define offsetZ   277

#define gainX     -29        // GAIN factors
#define gainY     -28
#define gainZ     24*/

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

  adxl.setRangeSetting(16);           // 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.setRate(100);
   
  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(0);
  adxl.ActivityINT(0);
  adxl.FreeFallINT(0);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);

}

/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){
  obtainSample();
  ADXL_ISR();
  //delay(1000);
}

void obtainSample(){
  
  // Accelerometer Readings
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  
  /* Note: Must perform offset and gain calculations prior to seeing updated results
  /  Refer to SparkFun ADXL345 Hook Up Guide: https://learn.sparkfun.com/tutorials...5-hookup-guide
  /  offsetAxis = 0.5 * (Acel+1g + Accel-1g)
  /  gainAxis = 0.5 * ((Acel+1g - Accel-1g)/1g) */

  // UNCOMMENT SECTION TO VIEW NEW VALUES
  x = (x - offsetX)/gainX;         // Calculating New Values for X, Y and Z
  y = (y - offsetY)/gainY;
  z = (z - offsetZ)/gainZ;
  
  if(x < AccelMinX) AccelMinX = x;
  if(x > AccelMaxX) AccelMaxX = x;

  if(y < AccelMinY) AccelMinY = y;
  if(y > AccelMaxY) AccelMaxY = y;

  if(z < AccelMinZ) AccelMinZ = z;
  if(z > AccelMaxZ) AccelMaxZ = z;

  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z);
}

/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  byte interrupts = adxl.getInterruptSource();
  
  // 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
  } else if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}
 
Last edited:
Seems like the attachments from my previous post got busted (for me at least), please refer to this post for the images instead:
adxl345.jpg

hookup.jpg

teensy3-2.jpg
 
Hmmmm, I don't see anything funky with the wiring, though jumpers are long, but probably OK for 5mhz SPI. Maybe it's a speed problem, have you tried running T3.2 @48mhz or slower? Or in the library adding a delay after CS low and before CS high.

stumped ??
 
Yes, I'm actually testing it in 24MHz so that I could actually read the received values through Arduino IDE's Serial Monitor, while keeping the microcontroller's CPU speed low. I've also tested it in 16MHz and 8MHz before, with it's output being shown via an OLED screen connected through SPI pins 7-9 (Adafruit OLED SSD1306 Library).

As for the problem, it seems that I'm encountering constant large values in my x, y, and z acceleration values (i.e., +- 65535). Moreover, the ADXL345 interrupts keep on firing even after being cleared out, though this problem is not consistently occurring (approx 50% of every program start). The values that I'm obtaining doesn't seem to change even if acceleration is applied to the module.

I've just read a thread with similar problems with mine: https://forum.pjrc.com/threads/39769-Teensy-3-2-amp-GY85 and I've tried the revised Sparkfun library proposed in that forum. It did reduced the value that I'm obtaining to a single digit instead of 65535 (reduced to -6, -6, and -10 for x, y, and z values respectively), but the previous problems are still occurring.

And yea, I think the jumpers wouldn't subject the signals to noise that much since my hookup with the Uno is much more worse.
 
Just reconnected another SPI device to pins 10-13 to check if the problem occurs because of busted pins or funky solders, sadly, the said device worked without problems.
 
The other issue when something works on UNO but not on teensy is the size of int's (16-bits on UNO, 32-bits on teensy). i'm not sure i see anything there, though readAccel() is doing some interesting casts ....
 
I see, so what does that imply? Does that deem sparkfun's library unusable at the moment? Or should I fix my int variable declarations to 16bit in the teensy code, or change the int variable declarations and casts in sparkfun's library into 32bit instead?
 
Tried changing int and double variable declarations (as well as casts) to int16_t and float in both the .ino file and the adxl345 libraries. Still not working, obtaining the following values:

serial output.jpg

NOTE:
Those outputs were obtained while applying acceleration onto the breakout board. "Double Tapping" was not being triggered as well. Even when the breakout board's at rest, it still outputs the same values.

Sketch file:
Code:
#include <SparkFun_ADXL345.h>

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

/****************** VARIABLES ******************/
/*                                             */
int16_t AccelMinX = 0;
int16_t AccelMaxX = 0;
int16_t AccelMinY = 0;
int16_t AccelMaxY = 0;
int16_t AccelMinZ = 0;
int16_t AccelMaxZ = 0; 
int16_t x,y,z;   

// for 16g
#define offsetX   -1       // OFFSET values
#define offsetY   -25
#define offsetZ   41

#define gainX     -4        // GAIN factors
#define gainY     -4
#define gainZ     4

/*//for 2g
#define offsetX   -2       // OFFSET values
#define offsetY   -193
#define offsetZ   277

#define gainX     -29        // GAIN factors
#define gainY     -28
#define gainZ     24*/

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

  adxl.setRangeSetting(16);           // 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.setRate(100);
   
  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(0);
  adxl.ActivityINT(0);
  adxl.FreeFallINT(0);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);

}

/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){
  obtainSample();
  ADXL_ISR();
  delay(1000);
}

void obtainSample(){
  
  // Accelerometer Readings
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  
  /* Note: Must perform offset and gain calculations prior to seeing updated results
  /  Refer to SparkFun ADXL345 Hook Up Guide: https://learn.sparkfun.com/tutorials...5-hookup-guide
  /  offsetAxis = 0.5 * (Acel+1g + Accel-1g)
  /  gainAxis = 0.5 * ((Acel+1g - Accel-1g)/1g) */

  // UNCOMMENT SECTION TO VIEW NEW VALUES
  x = (x - offsetX)/gainX;         // Calculating New Values for X, Y and Z
  y = (y - offsetY)/gainY;
  z = (z - offsetZ)/gainZ;
  
  if(x < AccelMinX) AccelMinX = x;
  if(x > AccelMaxX) AccelMaxX = x;

  if(y < AccelMinY) AccelMinY = y;
  if(y > AccelMaxY) AccelMaxY = y;

  if(z < AccelMinZ) AccelMinZ = z;
  if(z > AccelMaxZ) AccelMaxZ = z;

  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z);
}

/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  byte interrupts = adxl.getInterruptSource();
  
  // 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
  } else if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}

adxl345 header file:
Code:
/*
Sparkfun's ADXL345 Library Main Header File
ADXL345.h

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

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"

#ifndef ADXL345_h
#define ADXL345_h

/*************************** REGISTER MAP ***************************/
#define ADXL345_DEVID			0x00		// Device ID
#define ADXL345_RESERVED1		0x01		// Reserved. Do Not Access. 
#define ADXL345_THRESH_TAP		0x1D		// Tap Threshold. 
#define ADXL345_OFSX			0x1E		// X-Axis Offset. 
#define ADXL345_OFSY			0x1F		// Y-Axis Offset.
#define ADXL345_OFSZ			0x20		// Z- Axis Offset.
#define ADXL345_DUR				0x21		// Tap Duration.
#define ADXL345_LATENT			0x22		// Tap Latency.
#define ADXL345_WINDOW			0x23		// Tap Window.
#define ADXL345_THRESH_ACT		0x24		// Activity Threshold
#define ADXL345_THRESH_INACT	0x25		// Inactivity Threshold
#define ADXL345_TIME_INACT		0x26		// Inactivity Time
#define ADXL345_ACT_INACT_CTL	0x27		// Axis Enable Control for Activity and Inactivity Detection
#define ADXL345_THRESH_FF		0x28		// Free-Fall Threshold.
#define ADXL345_TIME_FF			0x29		// Free-Fall Time.
#define ADXL345_TAP_AXES		0x2A		// Axis Control for Tap/Double Tap.
#define ADXL345_ACT_TAP_STATUS	0x2B		// Source of Tap/Double Tap
#define ADXL345_BW_RATE			0x2C		// Data Rate and Power mode Control
#define ADXL345_POWER_CTL		0x2D		// Power-Saving Features Control
#define ADXL345_INT_ENABLE		0x2E		// Interrupt Enable Control
#define ADXL345_INT_MAP			0x2F		// Interrupt Mapping Control
#define ADXL345_INT_SOURCE		0x30		// Source of Interrupts
#define ADXL345_DATA_FORMAT		0x31		// Data Format Control
#define ADXL345_DATAX0			0x32		// X-Axis Data 0
#define ADXL345_DATAX1			0x33		// X-Axis Data 1
#define ADXL345_DATAY0			0x34		// Y-Axis Data 0
#define ADXL345_DATAY1			0x35		// Y-Axis Data 1
#define ADXL345_DATAZ0			0x36		// Z-Axis Data 0
#define ADXL345_DATAZ1			0x37		// Z-Axis Data 1
#define ADXL345_FIFO_CTL		0x38		// FIFO Control
#define ADXL345_FIFO_STATUS		0x39		// FIFO Status

#define ADXL345_BW_1600			0xF			// 1111		IDD = 40uA
#define ADXL345_BW_800			0xE			// 1110		IDD = 90uA
#define ADXL345_BW_400			0xD			// 1101		IDD = 140uA
#define ADXL345_BW_200			0xC			// 1100		IDD = 140uA
#define ADXL345_BW_100			0xB			// 1011		IDD = 140uA 
#define ADXL345_BW_50			0xA			// 1010		IDD = 140uA
#define ADXL345_BW_25			0x9			// 1001		IDD = 90uA
#define ADXL345_BW_12_5		    0x8			// 1000		IDD = 60uA 
#define ADXL345_BW_6_25			0x7			// 0111		IDD = 50uA
#define ADXL345_BW_3_13			0x6			// 0110		IDD = 45uA
#define ADXL345_BW_1_56			0x5			// 0101		IDD = 40uA
#define ADXL345_BW_0_78			0x4			// 0100		IDD = 34uA
#define ADXL345_BW_0_39			0x3			// 0011		IDD = 23uA
#define ADXL345_BW_0_20			0x2			// 0010		IDD = 23uA
#define ADXL345_BW_0_10			0x1			// 0001		IDD = 23uA
#define ADXL345_BW_0_05			0x0			// 0000		IDD = 23uA


 /************************** INTERRUPT PINS **************************/
#define ADXL345_INT1_PIN		0x00		//INT1: 0
#define ADXL345_INT2_PIN		0x01		//INT2: 1


 /********************** INTERRUPT BIT POSITION **********************/
#define ADXL345_INT_DATA_READY_BIT		0x07
#define ADXL345_INT_SINGLE_TAP_BIT		0x06
#define ADXL345_INT_DOUBLE_TAP_BIT		0x05
#define ADXL345_INT_ACTIVITY_BIT		0x04
#define ADXL345_INT_INACTIVITY_BIT		0x03
#define ADXL345_INT_FREE_FALL_BIT		0x02
#define ADXL345_INT_WATERMARK_BIT		0x01
#define ADXL345_INT_OVERRUNY_BIT		0x00

#define ADXL345_DATA_READY				0x07
#define ADXL345_SINGLE_TAP				0x06
#define ADXL345_DOUBLE_TAP				0x05
#define ADXL345_ACTIVITY				0x04
#define ADXL345_INACTIVITY				0x03
#define ADXL345_FREE_FALL				0x02
#define ADXL345_WATERMARK				0x01
#define ADXL345_OVERRUNY				0x00


 /****************************** ERRORS ******************************/
#define ADXL345_OK			1		// No Error
#define ADXL345_ERROR		0		// Error Exists

#define ADXL345_NO_ERROR	0		// Initial State
#define ADXL345_READ_ERROR	1		// Accelerometer Reading Error
#define ADXL345_BAD_ARG		2		// Bad Argument


class ADXL345
{
public:
	bool status;					// Set When Error Exists 

	byte error_code;				// Initial State
	float gains[3];				// Counts to Gs
	
	ADXL345();
	ADXL345(int16_t CS);
	void powerOn();
	void readAccel(int16_t* xyx);
	void readAccel(int16_t* x, int16_t* y, int16_t* z);
	void get_Gxyz(float *xyz);
	
	void setTapThreshold(int16_t tapThreshold);
	int16_t getTapThreshold();
	void setAxisGains(float *_gains);
	void getAxisGains(float *_gains);
	void setAxisOffset(int16_t x, int16_t y, int16_t z);
	void getAxisOffset(int16_t* x, int16_t* y, int16_t*z);
	void setTapDuration(int16_t tapDuration);
	int16_t getTapDuration();
	void setDoubleTapLatency(int16_t doubleTapLatency);
	int16_t getDoubleTapLatency();
	void setDoubleTapWindow(int16_t doubleTapWindow);
	int16_t getDoubleTapWindow();
	void setActivityThreshold(int16_t activityThreshold);
	int16_t getActivityThreshold();
	void setInactivityThreshold(int16_t inactivityThreshold);
	int16_t getInactivityThreshold();
	void setTimeInactivity(int16_t timeInactivity);
	int16_t getTimeInactivity();
	void setFreeFallThreshold(int16_t freeFallthreshold);
	int16_t getFreeFallThreshold();
	void setFreeFallDuration(int16_t freeFallDuration);
	int16_t getFreeFallDuration();
	
	bool isActivityXEnabled();
	bool isActivityYEnabled();
	bool isActivityZEnabled();
	bool isInactivityXEnabled();
	bool isInactivityYEnabled();
	bool isInactivityZEnabled();
	bool isActivityAc();
	bool isInactivityAc();
	void setActivityAc(bool state);
	void setInactivityAc(bool state);
	
	bool getSuppressBit();
	void setSuppressBit(bool state);
	bool isTapDetectionOnX();
	void setTapDetectionOnX(bool state);
	bool isTapDetectionOnY();
	void setTapDetectionOnY(bool state);
	bool isTapDetectionOnZ();
	void setTapDetectionOnZ(bool state);
	void setTapDetectionOnXYZ(bool stateX, bool stateY, bool stateZ);
	
	void setActivityX(bool state);
	void setActivityY(bool state);
	void setActivityZ(bool state);
	void setActivityXYZ(bool stateX, bool stateY, bool stateZ);
	void setInactivityX(bool state);
	void setInactivityY(bool state);
	void setInactivityZ(bool state);
	void setInactivityXYZ(bool stateX, bool stateY, bool stateZ);
	
	bool isActivitySourceOnX();
	bool isActivitySourceOnY();
	bool isActivitySourceOnZ();
	bool isTapSourceOnX();
	bool isTapSourceOnY();
	bool isTapSourceOnZ();
	bool isAsleep();
	
	bool isLowPower();
	void setLowPower(bool state);
	float getRate();
	void setRate(float rate);
	void set_bw(byte bw_code);
	byte get_bw_code();  
	
	bool triggered(byte interrupts, int16_t mask);
	
	byte getInterruptSource();
	bool getInterruptSource(byte interruptBit);
	bool getInterruptMapping(byte interruptBit);
	void setInterruptMapping(byte interruptBit, bool interruptPin);
	bool isInterruptEnabled(byte interruptBit);
	void setInterrupt(byte interruptBit, bool state);
	void setImportantInterruptMapping(int16_t single_tap, int16_t double_tap, int16_t free_fall, int16_t activity, int16_t inactivity);
	void InactivityINT(bool status);
	void ActivityINT(bool status);
	void FreeFallINT(bool status);
	void doubleTapINT(bool status);
	void singleTapINT(bool status);
	
	void getRangeSetting(byte* rangeSetting);
	void setRangeSetting(int16_t val);
	bool getSelfTestBit();
	void setSelfTestBit(bool selfTestBit);
	bool getSpiBit();
	void setSpiBit(bool spiBit);
	bool getInterruptLevelBit();
	void setInterruptLevelBit(bool interruptLevelBit);
	bool getFullResBit();
	void setFullResBit(bool fullResBit);
	bool getJustifyBit();
	void setJustifyBit(bool justifyBit);
	void printAllRegister();
	
private:
	void writeTo(byte address, byte val);
	void writeToI2C(byte address, byte val);
	void writeToSPI(byte address, byte val);
	void readFrom(byte address, int16_t num, byte buff[]);
	void readFromI2C(byte address, int16_t num, byte buff[]);
	void readFromSPI(byte address, int16_t num, byte buff[]);
	void setRegisterBit(byte regAdress, int16_t bitPos, bool state);
	bool getRegisterBit(byte regAdress, int16_t bitPos);  
	byte _buff[6] ;		//	6 Bytes Buffer
	int16_t _CS = 10;
	bool I2C = true;
	unsigned long SPIfreq = 5000000;
};
void print_byte(byte val);
#endif

adxl345 cpp file:
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(int16_t 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);
	pinMode(_CS, OUTPUT);
	digitalWrite(_CS, HIGH);
}

void ADXL345::powerOn() {
	if(I2C) {
		Wire.begin();				// If in I2C Mode Only
	}
	//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(int16_t *xyz){
	readAccel(xyz, xyz + 1, xyz + 2);
}

void ADXL345::readAccel(int16_t *x, int16_t *y, int16_t *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)((((int16_t)_buff[1]) << 8) | _buff[0]);
	*y = (int16_t)((((int16_t)_buff[3]) << 8) | _buff[2]);
	*z = (int16_t)((((int16_t)_buff[5]) << 8) | _buff[4]);
}

void ADXL345::get_Gxyz(float *xyz){
	int16_t i;
	int16_t 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, int16_t 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, int16_t num, byte _buff[]) {
	Wire.beginTransmission(ADXL345_DEVICE);  
	Wire.write(address);             
	Wire.endTransmission();         
	
	Wire.beginTransmission(ADXL345_DEVICE); 
	Wire.requestFrom(ADXL345_DEVICE, num);  // Request 6 Bytes
	
	int16_t 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.transfer(__reg_address); 
  SPI.transfer(__val); 
  digitalWrite(_CS, HIGH); 
}

/*************************** READ FROM SPI **************************/
/*                                                                  */
void ADXL345::readFromSPI(byte __reg_address, int16_t 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.transfer(_address);		// Transfer Starting Reg Address To Be Read  
  for(int16_t i=0; i<num; i++){
    _buff[i] = SPI.transfer(0x00);
  }
  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(int16_t 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(int16_t 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
int16_t ADXL345::getTapThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_TAP, 1, &_b);  
	return int16_t (_b);
}

/****************** GAIN FOR EACH AXIS IN Gs / COUNT *****************/
/*                           ~ SET & GET                            */
void ADXL345::setAxisGains(float *_gains){
	int16_t i;
	for(i = 0; i < 3; i++){
		gains[i] = _gains[i];
	}
}
void ADXL345::getAxisGains(float *_gains){
	int16_t 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(int16_t x, int16_t y, int16_t z) {
	writeTo(ADXL345_OFSX, byte (x));  
	writeTo(ADXL345_OFSY, byte (y));  
	writeTo(ADXL345_OFSZ, byte (z));  
}

void ADXL345::getAxisOffset(int16_t* x, int16_t* y, int16_t*z) {
	byte _b;
	readFrom(ADXL345_OFSX, 1, &_b);  
	*x = int16_t (_b);
	readFrom(ADXL345_OFSY, 1, &_b);  
	*y = int16_t (_b);
	readFrom(ADXL345_OFSZ, 1, &_b);  
	*z = int16_t (_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(int16_t tapDuration) {
	tapDuration = constrain(tapDuration,0,255);
	byte _b = byte (tapDuration);
	writeTo(ADXL345_DUR, _b);  
}

int16_t ADXL345::getTapDuration() {
	byte _b;
	readFrom(ADXL345_DUR, 1, &_b);  
	return int16_t (_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(int16_t doubleTapLatency) {
	byte _b = byte (doubleTapLatency);
	writeTo(ADXL345_LATENT, _b);  
}

int16_t ADXL345::getDoubleTapLatency() {
	byte _b;
	readFrom(ADXL345_LATENT, 1, &_b);  
	return int16_t (_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(int16_t doubleTapWindow) {
	doubleTapWindow = constrain(doubleTapWindow,0,255);
	byte _b = byte (doubleTapWindow);
	writeTo(ADXL345_WINDOW, _b);  
}

int16_t ADXL345::getDoubleTapWindow() {
	byte _b;
	readFrom(ADXL345_WINDOW, 1, &_b);  
	return int16_t (_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(int16_t activityThreshold) {
	activityThreshold = constrain(activityThreshold,0,255);
	byte _b = byte (activityThreshold);
	writeTo(ADXL345_THRESH_ACT, _b);  
}

// Gets the THRESH_ACT byte
int16_t ADXL345::getActivityThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_ACT, 1, &_b);  
	return int16_t (_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(int16_t inactivityThreshold) {
	inactivityThreshold = constrain(inactivityThreshold,0,255);
	byte _b = byte (inactivityThreshold);
	writeTo(ADXL345_THRESH_INACT, _b);  
}

int16_t ADXL345::getInactivityThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_INACT, 1, &_b);  
	return int16_t (_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(int16_t timeInactivity) {
	timeInactivity = constrain(timeInactivity,0,255);
	byte _b = byte (timeInactivity);
	writeTo(ADXL345_TIME_INACT, _b);  
}

int16_t ADXL345::getTimeInactivity() {
	byte _b;
	readFrom(ADXL345_TIME_INACT, 1, &_b);  
	return int16_t (_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(int16_t freeFallThreshold) {
	freeFallThreshold = constrain(freeFallThreshold,0,255);
	byte _b = byte (freeFallThreshold);
	writeTo(ADXL345_THRESH_FF, _b);  
}

int16_t ADXL345::getFreeFallThreshold() {
	byte _b;
	readFrom(ADXL345_THRESH_FF, 1, &_b);  
	return int16_t (_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(int16_t freeFallDuration) {
	freeFallDuration = constrain(freeFallDuration,0,255);  
	byte _b = byte (freeFallDuration);
	writeTo(ADXL345_TIME_FF, _b);  
}

int16_t ADXL345::getFreeFallDuration() {
	byte _b;
	readFrom(ADXL345_TIME_FF, 1, &_b);  
	return int16_t (_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 ******************************/
/*                                                                  */
float ADXL345::getRate(){
	byte _b;
	readFrom(ADXL345_BW_RATE, 1, &_b);
	_b &= B00001111;
	return (pow(2,((int16_t) _b)-6)) * 6.25;
}

void ADXL345::setRate(float rate){
	byte _b,_s;
	int16_t v = (int16_t) (rate / 6.25);
	int16_t 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, int16_t 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(int16_t single_tap, int16_t double_tap, int16_t free_fall, int16_t activity, int16_t 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, int16_t 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, int16_t 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("");
	int16_t 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){
	int16_t i;
	Serial.print("B");
	for(i=7; i>=0; i--){
		Serial.print(val >> i & 1, BIN);
	}
}
 
I see, so what does that imply? Does that deem sparkfun's library unusable at the moment? Or should I fix my int variable declarations to 16bit in the teensy code, or change the int variable declarations and casts in sparkfun's library into 32bit instead?

I'm more concerned that the values from the board/SPI are not changing. You could try printing out the HEX values of _buff in lib's readAccel().

Some observations:

1) i don't have an ADXL345 to test, and I've been looking at mostly adafruit and sparkfun web pages for description/libraries. However, examining your photos you have a board from e-gizmo.com.
http://www.e-gizmo.com/oc/index.php?route=product/product&product_id=509
That URL shows board has 10K pullups on all SPI lines, and their little demo sketch uses software-SPI (bit bang)! You could try their bit-bang sketch (should work on UNO) but not sure if the Teensy will work with that bit-bang sketch. SPI clock in bit-bang sketch ran at 600khz on T3.2@120mhz.

2) given the 10K pullups, you might try configuring the hardware SPI to a slower speed (UNO default is 4mhz SPI clock). Teensy default SPI clock is F_BUS/8. Max SPI clock for ADXL345 is 5mhz.

3) the faster Teensy might still be causing a problem with speed of setting CS LOW and HIGH, so you could try adding delayMicroseconds(5) after CS LOW and before setting CS HIGH in library (several places)

you might consider getting an Adafruit or Sparkfun version of the ADXL345 or other MPU's like MPU9250
https://www.tindie.com/products/onehorse/mpu9250-teensy-3x-add-on-shields/
 
Last edited:
Hmmmm, I don't see anything funky with the wiring, though jumpers are long, but probably OK for 5mhz SPI. Maybe it's a speed problem, have you tried running T3.2 @48mhz or slower? Or in the library adding a delay after CS low and before CS high.

stumped ??

T3.5 i ran 8MHz SPI with 22 gauge solid wire 3x longer than that, to a bank of 8xMCP23S17 expanders :)
 
Yea, Ive read E-Gizmo's "User Manual" as they call it a few hours ago, neglecting the document in the first place was my mistake, as well as assuming that I won t be needing it even though I'll be interfacing the breakout board to a new microcontroller, with a very different processor than the Uno. I'll give their bit-bang sketch a try in a while.

Since you've proposed replacing the breakout board as well, I actually have an ADXL346 (ultra low-voltage version of ADXL345) breakout board from Elecrow, and a logic level shifter. Though I'm unsuccessful of finding its "user manual / datasheet," do you think it'll be more compatible to the sparkfun library than e-gizmo's breakout board?

Elecrow ADXL346:
https://www.elecrow.com/3axis-digital-accelerometeradxl346-p-1236.html

Note:
I've also tried a few libraries awhile back but to no avail.

https://gist.github.com/FuzzyWuzzie/b1903a8353dc1ec57da8

https://learn.adafruit.com/adxl345-digital-accelerometer/programming
 
Since you've proposed replacing the breakout board as well, I actually have an ADXL346 (ultra low-voltage version of ADXL345) breakout board from Elecrow, and a logic level shifter. Though I'm unsuccessful of finding its "user manual / datasheet," do you think it'll be more compatible to the sparkfun library than e-gizmo's breakout board?

Hard to say, datasheet https://www.elecrow.com/download/ADXL346-datasheet.pdf says Vin 1.75v to 2.75v, that could be awkward. Max SPI rate is also 5mhz. I don't see a schematic for the breakout board so don't know whether there are pullups or just LDO and level shifters or ?

i'd first try adding code to library to reduce SPI to 4mhz or 1 mhz. The ADXL345 data sheet says max SPI clock is 5mhz.
In library SparkFun_ADXL345.cpp add SPISettings
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);
}

EDIT: works for me, see https://forum.pjrc.com/threads/5685...ion-Difficulty?p=248160&viewfull=1#post248160
 
Last edited:
Alright thanks for your help manitou, I'll try the options that you've told me, and update this forum once I've exhausted them all.
 
Okay, thanks for bringing that out mjs513. You're right, it did work via I2C bus, tried remedying the problem with the SPI interface by utilizing manitou's answers, but it still didn't work. Thanks for the help guys, one love.
 
Tried your proposed solutions manitou, tried it both in 1MHz and 4MHz but still didn't work, thanks for the help anyway. For all of you trying to interface the said breakout board with the teensy 3.2 via SPI interface, I suggest you utilize its I2C bus interfacing capabilities instead. Thanks everyone, one love.
 
Okay, thanks for bringing that out mjs513. You're right, it did work via I2C bus, tried remedying the problem with the SPI interface by utilizing manitou's answers, but it still didn't work. Thanks for the help guys, one love.
Hi Lamey could you please post your code using I2C. I’m working on a similar project with the teensy and ADXL345 and it could really help. Thanks!
 
Status
Not open for further replies.
Back
Top