0

I would like the sensor values to be updated each 10ms(100Hz) and then run the algorithm and repeat the same process. However, after timing the algorithm it is taking only 2ms, I think the data_ready interrupt is not working as expected. Physical hardware connection is from INT1 of ADXL345 to pin2 of the UNO.

edit:

I have configured the accelerometer to have a data rate of 100Hz. I have set up an interrupt with data_ready to run the algorithm present in the loop each time a new sample comes that is each 10ms. However each sample is coming every 2ms which shows the interrupt is not working and I would like to know why. I have timed the interrupt with the millis(); function before and after calling the interrupt, also I have stored the samples in an array and printed it on the serial interface and the samples were repeated as it was updated every 2ms instead of 10ms. The algorithm I have developed needs the sampling rate to be 100Hz.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <avr/io.h>
#include <avr/power.h>


#define F_CPU 16000000UL


volatile int sensor_update=0;


//-----------------------------------------------------------------------------------     -----------
//Write to ADXL345 registers
void writeTo(int device, byte address, byte val) {
Wire.beginTransmission(device); //start transmission to device
Wire.write(address);        // send register address
Wire.write(val);        // send value to write
Wire.endTransmission(); //end transmission
}



//----------------------------------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////////////////////////////

//ISR function

void interrupt(void){
sensor_update=1;

}


//////////////////////////////////////////////////////////////////////////////////////////////////



void buzz(int targetPin, long frequency, long length) {
long delayValue = 1000000/frequency/2; // calculate the delay value between     transitions
//// 1 second's worth of microseconds, divided by the frequency, then split in half since

  //// there are two phases to each cycle
  //// calculate the number of cycles for proper timing
  long numCycles = frequency * length/ 1000; 

  //// multiply frequency, which is really cycles per second, by 
  //// the number of seconds to get the total number of cycles to produce
  for (long i=0; i < numCycles; i++){ // for the calculated length of time...
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait againf or the calculated delay value
  }
}


/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);

void setup(void)
{
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  Serial.begin(9600);
  //Serial.println("Accelerometer Test"); Serial.println("");

  pinMode(4, OUTPUT);// buzzer output pin

  /* Initialise the sensor */
  if(!accel.begin())
  {
    /* There was a problem detecting the ADXL345 ... check your connections */
    //Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
    while(1);
  }

  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL345_RANGE_16_G);
  accel.setDataRate(ADXL345_DATARATE_100_HZ);
  // displaySetRange(ADXL345_RANGE_8_G);
  // displaySetRange(ADXL345_RANGE_4_G);
  // displaySetRange(ADXL345_RANGE_2_G);

  //Create an interrupt that will trigger when a tap is detected.
  attachInterrupt(0, interrupt, RISING);

  writeTo(0x1D, 0x2E, 0);
  writeTo(0x1D, 0x2F, 0);
  writeTo(0x1D, 0x2E, 128);
  writeTo(0x1D, 0x2F, 127);
}

void loop(void)
{


  if(sensor_update==1 ){
    //When sensor_update is set to 1 in the ISR,the algorithm process the data from the accelerometer being updated every 10ms(100Hz)
     sensor_update=0;//reset
  }
}  
5
  • It looks like some of your code got cut off; could you add that? also, can you try and give a more detailed description of what you want the code to do? what did you use to time your code? Commented Feb 18, 2015 at 0:52
  • basically my algorithm needs a sampling rate of 100Hz and that is what I used to develop it in the first place. The interrupt even though configured with this data rate is not working as expected, I am guessing it is an interrupt setup problem.
    – user49395
    Commented Feb 18, 2015 at 1:16
  • Should you be manually running the interrupt function in the loop, or should that only run when the sensor causes the interrupt to happen? Commented Feb 18, 2015 at 1:38
  • I actually just spotted that. After removing the interrupt call from the loop, the interrupt simply never kicks in now. The enable and map registers are set up correctly,could someone confirm that please.
    – user49395
    Commented Feb 18, 2015 at 1:42
  • after some troubleshooting: putting pin2 as an input doesn't change anything. testing if the output from ADXL INT1 is toggling with 1Hz output rate with a multimeter give 0V so the problem is coming from the accelerometer, somehow it is not generating anything. edit: I have changed the device to 0x53 instead of 0x1D and now the LED is always on, still not toggling tough.
    – user49395
    Commented Feb 18, 2015 at 19:49

2 Answers 2

1

According to the data-sheet:

The interrupt functions are latched and cleared by either reading the data registers (Address 0x32 to Address 0x37) until the interrupt condition is no longer valid for the data-related interrupts or by reading the INT_SOURCE register (Address 0x30) for the remaining interrupts.

Therefore, an ISR that just sets a flag will not be called a second time. At the very least, you need to read the INT_SOURCE register. If you are using the SparkFun ADXL345 library, then this would be a call of the form:

ADXL345 adxl = ADXL345();
void setup() { 
  adxl.powerOn();
  adxl.setInterruptBitLevel(true); // active low
  attachInterrupt(digitalPinToInterrupt(interruptPin), isr, LOW);
  pinMode(interruptPin, INPUT);
  adxl.singleTapINT(1);
  ...
}

void isr(void) { 
  detachInterrupt(digitalPinToInterrupt(interruptPin));
  interrupts();
  byte source = adxl.getInterruptSource();
  ...
  attachInterrupt(digitalPinToInterrupt(interruptPin), isr, LOW);
}

Note that I use a level-triggered interrupt here and re-enable interrupts before calling adxl.getInterruptSource(). The issue is that this call may take some time to talk over the I2C bus. To ensure that there are no reentrant calls, I detach the interrupt first. Without this, the level-triggered mode causes an interrupt loop.

The use of a level-triggered interrupt makes sense because the ADXL won't produce another interrupt until you read from INT_SOURCE. It also avoids the problem of missing an edge detection, which tends to cause subtle bugs that are hard to find.

I was unsure about the soundness of turning on interrupts within the ISR and so asked a question about this - What is the right way to query an I2C device from an interrupt service routine?

0

Been bashing my head with this one. And have searched the internet for a solution And tried for hours to program a solution. From my tests the problem seems to be the Register 0x30—INT_SOURCE is populated with triggers. But the INT pin is only triggered when the Register 0x30—INT_SOURCE is read. This means that firstly the Arduino can't be woken from sleep by the INT1 or INT2 pins because they don't change unless the Arduino is already awake and reading the Register 0x30—INT_SOURCE Second problem is to trigger an interrupt INT pin to jump to the ISR interrupt service routine you have to read Register 0x30—INT_SOURCE. And if you are going to do that then you might as well forget the interrupt and just jump into the ISR() and check registers in that. Which is how the example in the Sparkfun_ADXL345_Example for arduino ended up with the ADXL_ISR(); call in the main loop. To sum up. Unless some one knows away to get the ADXL345 to change state on its INT pins without the need to read Register 0x30—INT_SOURCE, then the device is useless for use with the INT pins. I have given up on it and looking for another device to wake my ESP32 from sleep. Such as the BMI160 - Bosch which looks like a contender and has a arduino library for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.