1

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
  }
}  
  • 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? – BrettAM Feb 18 '15 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 Feb 18 '15 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? – BrettAM Feb 18 '15 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 Feb 18 '15 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 Feb 18 '15 at 19:49
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?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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