Pages: [1]   Go Down
Author Topic: Wire issue with ADXL345  (Read 1653 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Rock&Roll;
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I have an arduino UNO with an accelerometer ADXL345, which works through the TWI bus.

Using the Enerlib library to sleep arduino,  if it is slept in PowerDown mode, I can't wake it by an  interruption from the accelerometer.

Only works (with an interruption) when:
- Watchdog finishes every cycle but not when is completely  slept.
- If I disconnect the accelerometer, the arduino always awakes.

* I'm working with internal interruption from digital pins. It's tested that it works fine, also with external ones.

Probably, the microcontroller disable the TWI bus when it is in PowerDown mode, and there is an issue there, blocking the accelerometer to send the interruption.

Could anyone help me, please??
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do you expect the Arduino to wake up from power down mode by a signal on the I2C bus? This only works if the Arduino is an I2C slave. The ADXL345 is not able to be an I2C master, so your setup won't work. Correct me if I got something wrong.

What's possible, is to connect the INT1 or INT2 of the ADXL345 to either INT0 or INT1 of the Arduino. The interrupt pins are able to wake an ATmega chip from power down sleep mode.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Rock&Roll;
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

the ADXL's INT1 pin is connected to pin 11 in the Arduino UNO, to wake up it with a PCINT (internal interruption). But instead of wake up the Arduino, it remains sleep until it wakes up by the watchdog.

Code:
//sda.-a4
//scl.-a5
#include <ADXL345.h>
#include <Enerlib.h>
#include <Wire.h>
#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>

#define PIN_ADXL_ 11
#define pin 13
#define MAX_VALUE       1023.0
#define Vcc 5
#define TiempoVibracion   900
#define NumeroVibraciones 5
#define TiempoEnvioDatos 5

boolean firstTime = true;    // If 'True' is the first time, then change to 'False'
volatile unsigned long firstSend;
unsigned long init_int_time = 0;
unsigned long last_int_time = 0;

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
int contAdx = 0;
unsigned long tiempoAdxActual = 0;
unsigned long tiempoAdxAnterior = 0;
unsigned long tiempoAdxResta = 0;

Energy energy;

byte interrupts;
unsigned long Tiempo = (TiempoEnvioDatos * 60) / 8;
unsigned long NumeroDesbordamientos = 0;
volatile int activo = LOW; 

//___________________________________________________________________________________________
  // WATCHDOG

ISR(WDT_vect) {
  NumeroDesbordamientos++;
 
  if(NumeroDesbordamientos > Tiempo) {
    activo = HIGH;
  }
}

//___________________________________________________________________________________________
void setup(void) {
   
  pinMode(pin, OUTPUT);

  pinMode(PIN_ADXL_, INPUT);
  digitalWrite(PIN_ADXL_, HIGH);
  ConfigurarAdx();
  PCintPort::attachInterrupt(PIN_ADXL_, Adx, RISING);
 
  NumeroDesbordamientos = 0;  // reseteo contador
  activo = LOW;  // reseteo estado. Iniciar dormido.
 
  // Reference to 5V 
  analogReference(DEFAULT);
 
  Serial.begin(38400);

  WDTCSR = 0x00; // Deactivate Watchdog
  delay(1000);
  watchdog();  // configuracion del wacthdog
 
  activo = HIGH;
}
//___________________________________________________________________________________________
void loop(void) { 

  interrupts= adxl.getInterruptSource();
 
  if(activo) {
    WDTCSR = 0x00; // Deactivate Watchdog
    NumeroDesbordamientos = 0;  // reseteo contador
   
    Envio();
     
    activo = LOW; 
    WDTCSR = 0x71; // Reactivate Watchdog
  }

  energy.PowerDown();    //maximo ahorro de energia

//___________________________________________________________________________________________
void watchdog() {
  MCUSR &= ~(1 << WDRF);
  WDTCSR |= (1 << WDCE) | (1 << WDE);
  WDTCSR = 0x71;
}
//___________________________________________________________________________________________
void Envio() {
      Serial.print("\tAdxl345_Accel: ");
      Serial.println(contAdx);
}
//___________________________________________________________________________________________
void Adx()
{
  init_int_time = millis();
   
  if (init_int_time - last_int_time > 200) {
    tiempoAdxActual = millis();
    tiempoAdxResta = tiempoAdxActual - tiempoAdxAnterior;    // REVISAR
    tiempoAdxAnterior = tiempoAdxActual;
   
    if(tiempoAdxResta <= TiempoVibracion) {
      contAdx++;
     
      if(contAdx >= NumeroVibraciones) {
        activo = HIGH;
      }
    }
    else {
      contAdx = 0;
    }
 
  last_int_time = init_int_time;
  }
}
//___________________________________________________________________________________________
void ConfigurarAdx() {
  adxl.powerOn();
 
  //set activity/ inactivity thresholds (0-255)
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
 
  //look of activity movement on this axes - 1 == on; 0 == off
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);
 
  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);
 
  //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(10); //62.5mg per increment
  adxl.setTapDuration(15); //625μs per increment
  adxl.setDoubleTapLatency(10); //1.25ms per increment
  adxl.setDoubleTapWindow(80); //1.25ms per increment
 
  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
 
  //setting all interupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
 
  //register interupt actions - 1 == on; 0 == off 
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  0);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   0);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 0);
}
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you checked if you really get an interrupt in INT1 of the ADXL?

Quote
* I'm working with internal interruption from digital pins. It's tested that it works fine, also with external ones.

What does that mean? What's the distinction between internal and external interruption?

You're aware that the interrupt line is only activated if a tap is detected, are you?
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2036
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

if the accelerometer device has an "interrupt" output,   that doesn't go through the I2C bus,   that would be a separate
wired connection from the "interrupt" output pin on the accelerometer chip or breakout board,   to some pin on the
Arduino capable of recognising the interrupt state change.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Rock&Roll;
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's right.

ADXL's INT1 pin is connected to digital pin of the Arduino board, so I can use an internal interrupt and wake up the MCU when a tap occurs.

I wrote down that interruptions occurs when MCU is awake, and when WDT finishes each cycle, but when is completely asleep, interruption doesn't 'jump'.
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm kinda new to the AVRs, so forgive me if I say something stupid.  You seem to be wanting it to wake up by using a PCINTx (interrupt on pin change) instead of INT0 or INT1 which are on fixed pins and can't be reassigned.  The datasheet says that if the external device attempting to wake up the AVR doesn't hold the signal long enough for the AVR to wake up and get going, that the chip will wake up but NOT generate an interrupt.  Could this be what you are seeing?  What happens if you force it by just touching a wire to the pin?
Logged

Experience, it's what you get when you were expecting something else.

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I wrote down that interruptions occurs when MCU is awake, and when WDT finishes each cycle, but when is completely asleep, interruption doesn't 'jump'.

What does "doesn't jump" mean? Does it mean the ADXL345 isn't pulling the INT1 high for the interrupt? Or does it mean it pulls the pin high but the ATmega doesn't react on it?

How is your I2C bus wired? Do you use internal pull-ups or external ones? There's a difference between the two setups when the MCU goes asleep (start condition for the ADXL345).
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Rock&Roll;
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

and thanks all!

@afremont:
 - If I force the interrupt by a wire, it works perfectly.
 - With MCU always awake, ADXL's interrupt works fine.

@pylon:
 - 'Doesn't jump', I mean ATmega doesn't react on it.
 - I'm using internal pull-ups. Could this be the problem?

I'm still trying to discover why is this happening, although I'm going to some of these things.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
- 'Doesn't jump', I mean ATmega doesn't react on it.

That's strange because that denies my theory below.

Quote
- I'm using internal pull-ups. Could this be the problem?

That could be a problem.
Using the internal pullups, the I2C bus will go in a floating state when the ATmega goes asleep. It may set the ADXL into any state, that's why I assumed that the INT1 will never be activated in this case (see above). I would install external 4k7 pullups and try again. As long as there's no activity on the bus this shouldn't consume much power.
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2036
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The interrupt from the accelerometer chip or breakout board is NOT using the I2C bus.   If you use it,
it is connected directly to one of the digital pins of the arduino.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4702
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The interrupt from the accelerometer chip or breakout board is NOT using the I2C bus.   If you use it,
it is connected directly to one of the digital pins of the arduino.

This is clear already, there's a separate line (INT1) that has to go to a GPIO on the Arduino, we discussed this earlier in the thread.

But the whole chip is controlled by the I2C bus. If the OP is using the internal pull-ups for driving the I2C bus, the bus goes to a floating, not defined state when the ATmega goes asleep. Do you know how the ADXL345 reacts on that? Me not, because it's probably also not defined. That's why I suggested using external pull-ups.
Logged

texas
Offline Offline
God Member
*****
Karma: 27
Posts: 862
old, but not dead
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree with pylon, put in the external pull-ups.  If the I2C inputs float, it's anyone's guess as to what might happen.  Chances are though that whatever happens, won't do it consistently.  smiley-wink 

Also, I want to reiterate that the CPU won't call the ISR unless the int-on-change pin still reflects the change.  It appears that the ADXL345 will hold the INT output pin high until the internal registers are read.  This should allow for any length of wake-up time the CPU needs.
Logged

Experience, it's what you get when you were expecting something else.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Rock&Roll;
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

thanks to all!!

With an external pull-up, it works!!

I have to verify it better, but for the first time (with a 4k7 resistor) it is working.

Regards!
Logged

Pages: [1]   Go Up
Jump to: