ADXL345 interrupts Uno from sleep mode

Hi, I would like to use the ADXL345 accelerometer to wake up the UNO from sleep. the adxl is configured to monitor "activity" and will generate an interrupt when that event occurs. the adxl's interrupt pin (INT1) is connected to uno's external int (int0, D2). upon detecting such event, the uno will wake up from its power_down mode.

i've written the sketch but it leaves out the waking up part for the moment. i just wanted to make the interrupt handling work, but that's where i'm stuck. the isr doesnt seem to clear the adxl's register. the interrupt pin of the adxl is staying high and not resetting at all. i would appreciate any help from you folks!

#include 
#include 
#include 

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library


void setup(){
  Wire.begin();
  Serial.begin(9600);
  adxl.powerOn();
  adxl.set_bw(ADXL345_BW_6);
  adxl.setLowPower(0);
  adxl.setActivityAc(0);
  
    
  //set activity/ activity thresholds (0-255)
  adxl.setActivityThreshold(2); //62.5mg per increment
  
  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(0);

  attachInterrupt(0, interrupt_call, CHANGE);
  adxl.getInterruptSource();

  
  //setting the interrupt to take place on int pin 1
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );


  //register interrupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);

  adxl.printAllRegister();
}

void loop(){

   }

void interrupt_call() {
    adxl.getInterruptSource();
    detachInterrupt(0); 
}

Here's my connection: ADXL345 UNO SCL --------- A5 SDA ----------- A4 INT1 ---------- D2

The axdl driver is from: http://bildr.org/2011/03/adxl345-arduino/

adxl345 data sheet: http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf

I got the interrupt piece working now. The problem was the ADXL hardware, after I replaced the sketch below worked.

//Arduino 1.0+ Only!
//Arduino 1.0+ Only!

#include 
#include 
const byte LED = 13;
int intPin = 2;
boolean intPinState = LOW;
#include 
volatile boolean activity = LOW;

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library


void setup(){
  Wire.begin();
  Serial.begin(9600);
  //attachInterrupt(0, interrupt0, RISING);
  adxl.powerOn();
  adxl.set_bw(ADXL345_BW_6);
  adxl.setLowPower(0);
  adxl.setActivityAc(0);
  
   
  //set activity/ activity thresholds (0-255)
  adxl.setActivityThreshold(4); //62.5mg per increment
  

  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(0);

  attachInterrupt(0, interrupt0, RISING);
  adxl.getInterruptSource();

  //setting all interupts to take place on int pin 1
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );


  //register interupt actions - 1 == on; 0 == off  
   adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
   adxl.printAllRegister();
}

void loop(){

    adxl.getInterruptSource();


  if(activity)                                                                 
  {   Serial.println("Activity!");
      digitalWrite(LED, HIGH);
      delay(500);
      digitalWrite(LED, LOW);
  }
    activity = false; 

                                                       
 }

void interrupt0() {
    activity=HIGH;
    }

So back to my main objective on how to make the ADXL wake up the UNO from power_down mode. How do I do that? I found a code that puts the UNO to power_down mode all the time, and it wakes up when INT0 (D2) interrupt goes LOW. But I'm not sure how to integrate it, need your advice. Here's the sleep code..

if(digitalRead(intPin) == HIGH){
       ADCSRA = 0;  
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
  
  // will be called when pin D2 goes low  
  attachInterrupt (0, wake, LOW);

  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS); 
  
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycl

That code looks good in the first overview, so you just have to integrate it into your sketch. Take care that the demo code you posted reacts on a falling edge of the INT0 pin while your chip is configured to produce a rising edge. If you take that into account, the combination of the two code fragments should be pretty straightforward. If not, describe in detail where you have a problem.

I’ve managed to create the script that would wake up the UNO with the ADXL’s activity. I inverted the interrupt output of the ADXL to be active low. This matched the UNO’s ISR trigger setting of LOW.
Sketch below.

//Arduino 1.0+ Only!
//Arduino 1.0+ Only!

#include <Wire.h>
#include <ADXL345.h>
#include <avr/sleep.h>
const byte LED = 13;
volatile boolean activity = LOW;

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
int i=0;

void setup(){
  Wire.begin();
  Serial.begin(9600);
  adxl.powerOn();
  adxl.set_bw(ADXL345_BW_6);
  adxl.setLowPower(0);
  adxl.setActivityAc(0);
  adxl.setInterruptLevelBit(1); 
  
  //set activity/ activity thresholds (0-255)
  adxl.setActivityThreshold(4); //62.5mg per increment

  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
 adxl.setActivityY(1);
  adxl.setActivityZ(0);

 //setting all interupts to take place on int pin 1
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
 
 //register interupt actions - 1 == on; 0 == off  
   adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
   //adxl.printAllRegister();
}

void loop(){
	
    adxl.getInterruptSource();

   if(!activity)
{
  Serial.println("Start");
  delay(50);
  ADCSRA = 0;   
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
 // will be called when pin D2 goes low  
  attachInterrupt (0, wake, LOW);
 
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS); 
  
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle
  Serial.println("Stop");
  }
 }  

void wake()                                                              
{
  // cancel sleep as a precaution
   sleep_disable();
   // must do this as the pin will probably stay low for a while
  detachInterrupt (0);
 }

Here’s the trickier part, how do I create a sketch that would put the UNO to sleep when the ADXL is active? This is the inverse of my initial objective.
I don’t think it’s going to work by just moving my main code to the ISR and vice-versa. This is where I’m stuck right now. Your feedback is very much appreciated!

Here's the trickier part, how do I create a sketch that would put the UNO to sleep when the ADXL is active? This is the inverse of my initial objective.

This is quite simple. Just set a flag in the interrupt routine, then in the loop check for that flag and if set clear it and put the Arduino to sleep. The problem is more how you want the Arduino to wake up then... What do you want to achieve? Is this just academical questioning?

This is not an academical questioning. Actually, this is what I really need to do for my project. I initially thought otherwise, but my real requirement is to place UNO to sleep when the ADXL is sensing activity. So yes, what do you think?

Then my question: How do you wake it from the sleep? And don't tell me that this should be done by shaking it again because that's not possible (at least not without additional hardware). I already wrote you how you can put it to sleep with very little modification of your sketch. What is your project? Can you describe in a bit more detail?

The adxl's interrupt output has two logic states; high and low. I've set up the output to be active low, so when there's activity, the level goes from high to low. This logic is matched by the ISR of the UNO, where it is triggered when the UNO detects LOW. When there's no activity, the adxl int output goes back to high. So, my modification requires that the UNO sleeps when the adxl is active and vice versa. So I don't think the adxl is needed to be shaken again to wake up the UNO, it should wake up when the adxl's int out is high. My project is basically a gadget that detects motion and interacts with phones, tablets and etc. It will allow the driver to interact with his phone, tablet or other devices, only when the car is stationary. When the car starts moving, it will halt it and at the same time goes into sleep mode to save battery. So it's safety-related.

Your feedback is very much appreciated! Do I need a hardware to do this?

I would suggest to trigger the interrupt in both cases then (CHANGE). Check in the interrupt handler if the signal line is low or high and act accordingly.

It will allow the driver to interact with his phone, tablet or other devices, only when the car is stationary.

Have you checked if the ADXL can detect if the car is moving? As far as I know it only detects acceleration so if you're driving on a highway you won't have acceleration (positive or negative) anymore but the car is still moving. But you will get an acceleration if you take up your phone/tablet or whatever. How do you plan to distinguish between these actions?

I haven't checked yet but I will try it out. Thanks and will let you know.

Have had done something similar and it is working now (with pin going to HIGH). May be you can adapt and use it: (I have used the same library)

//Arduino 1.0+ Only!
//Arduino 1.0+ Only!

#include 
#include 
#include 
#include 

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library

void setup(){
  Serial.begin(115200);
  
  pinMode(13, OUTPUT); 
  pinMode(2, INPUT);      // Make digital 2 an input
   
  adxl.powerOn();

  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(1);
  adxl.setTapDetectionOnY(1);
  adxl.setTapDetectionOnZ(1);

  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(20); //62.5mg per increment
  adxl.setTapDuration(200); //625?s per increment
  adxl.setDoubleTapLatency(200); //1.25ms per increment
  adxl.setDoubleTapWindow(10); //1.25ms per increment  
  
  //setting all interupts to take place on int pin 1
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  
}

void sleepNow()         // here we put the arduino to sleep
{
  Serial.println("aus");
  digitalWrite(13,LOW);
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  sleep_enable();
  adxl.getInterruptSource();
  attachInterrupt(0, wakeUp, CHANGE);
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  sleep_mode();
  sleep_disable();         // first thing after waking from sleep:
  detachInterrupt(0);
}

void wakeUp()
 {

 }

void loop(){

  Serial.println("an");
  digitalWrite(13,HIGH);
  
  //Do stuff here
  
  sleepNow(); 

  //register interupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 0);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 0);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  0);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   0);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 0);  
  
}

Important is the time the senor needs minimum doing an interrupt! My problem was that the interrupt arrived some times while the arduino was going to sleep. In this case the board didn't awoke anytime.

I noticed that you didn't use attachinterrupt but you have the detachinterrupt. How does that work?

attachInterrupt is 6 lines above detachInterrupt.

I overlooked it., my mistake.

Eicca, I tried your script with my modifications to only monitor the activity. Instead of single, double and freefall, I only catch any activity. It didn't do what I wanted. I wanted to sleep when there's activity, but it did the opposite. I was monitoring the current consumption and it was higher when there's activity and lower when there's no activity.

Here's my version.

//Arduino 1.0+ Only!
//Arduino 1.0+ Only!

#include 
#include 
#include 
#include 

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library

void setup(){
  Serial.begin(115200);
  
  pinMode(13, OUTPUT); 
  pinMode(2, INPUT);      // Make digital 2 an input
   
  adxl.powerOn();

   
  //setting all interupts to take place on int pin 1


  //set activity/ activity thresholds (0-255)
  adxl.setActivityThreshold(4); //62.5mg per increment

  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
 adxl.setActivityY(1);
  adxl.setActivityZ(0);
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.printAllRegister();


  
}

void sleepNow()         // here we put the arduino to sleep
{
  Serial.println("aus");
  digitalWrite(13,LOW);
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  sleep_enable();
  adxl.getInterruptSource();
  attachInterrupt(0, wakeUp, CHANGE);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  sleep_mode();
  sleep_disable();         // first thing after waking from sleep:
  detachInterrupt(0);
}

void wakeUp()
 {

 }

void loop(){

  Serial.println("an");
  digitalWrite(13,HIGH);
  
  //Do stuff here
  
  sleepNow(); 

  //register interupt actions - 1 == on; 0 == off  
   adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   0);

  
}

Hi,

in my code the sensor does send the interrupt HIGH and the arduino is going to (, better: staying in) sleep, if it is low. You have to send the invertation-bit to the ADXL to get the oposite.

I tried both configuration for the interrupt level;adxl.setInterruptLevelBit(1); and //adxl.setInterruptLevelBit(0); and the ADXL's output level toggled between high or low depending on the this bit configuration. However, even with this changes, it didn't make a difference with regards to the current consumption behavior. The current consumption when there's activity is higher than when there's no activity, in both instances. Would you be able to perform the same current measurement if you have a chance? Thanks!

Eicca,
When you said it was working, it looks like your sketch cycles thru a sleep and wake.
This is different from my objective of keeping it asleep when there’s activity and awake when there’s none.
You have no ISR in your attachinterrupt function. How is that?