Having trouble with ADXL345 interrupt functions

I can't figure out what I am doing wrong - I have been referring to the data sheet and examples of setting up ADXL345 interrupts.

But my test LED on digital pin 8 does not seem to be firing in response to the interrupt signal from the ADXL345 INT1 going to arduino mega pin 2.

The full code (ino and modified ADXL345 library) are attached but I will point out the key functions I am using first:

My ISR function in my .ino:

void freeFall(void)
{
  digitalWrite(8, nLED);
  if (nLED == HIGH)
    nLED = LOW;
  else
    nLED = HIGH;
}

Setup function:

void setup(void) 
{
  Serial.begin(115200);
  Serial.println("Accelerometer Test"); Serial.println("");
  
  /* 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_16G);
  // displaySetRange(ADXL345_RANGE_8G);
  // displaySetRange(ADXL345_RANGE_4G);
  // displaySetRange(ADXL345_RANGE_2G);
  
  /* Display some basic information on this sensor */
  displaySensorDetails();
  
  /* Display additional settings (outside the scope of sensor_t) */
  displayDataRate();
  displayRange();
  Serial.println("");
  [b]accel.setADXL345FreeFallIntFunc(0, &freeFall, ADXL345_PIN_1);[/b]
 }

Function setADXL345FreeFallIntFunc(0, &freeFall, ADXL345_PIN_1)

void Adafruit_ADXL345_Unified::setADXL345FreeFallIntFunc(uint8_t nArduinoIntNo, isr_func_ptr_type pIntFunc, pin_t nADXL345IntPin)
{
  // Create an Arduino interrupt.
  attachInterrupt(nArduinoIntNo, pIntFunc, RISING);
  
  // Map the interrupt function to an ADXL345 interrupt pin.
  if (nADXL345IntPin == ADXL345_PIN_1)
    writeRegister(ADXL345_REG_INT_MAP, ~ADXL345_FUNC_FREEFALL);
  else if (nADXL345IntPin == ADXL345_PIN_2)
    writeRegister(ADXL345_REG_INT_MAP, ADXL345_FUNC_FREEFALL);

  // Set the range to 16g
  setRange(ADXL345_RANGE_16G);

  // Set the free fall threshold g
  setFreeFallThreshold(ADXL345_FREEFALL_450mg);

  // Set the free fall time
  setFreeFallTime(ADXL345_FREEFALL_200ms);

  // Enable the ADXL345 function and interrupt.
  writeRegister(ADXL345_REG_INT_ENABLE, ADXL345_FUNC_FREEFALL);
}

Added enums in my modified ADXL345 library (so I don't have to remember which bit goes where for all the registers):

/* Used with register 0x31 (ADXL345_REG_DATA_FORMAT) to set g range */
typedef enum
{
  ADXL345_RANGE_16G          = 0b11,   // +/- 16g
  ADXL345_RANGE_8G           = 0b10,   // +/- 8g
  ADXL345_RANGE_4G           = 0b01,   // +/- 4g
  ADXL345_RANGE_2G           = 0b00    // +/- 2g (default value)
} range_t;

/* Interrupt functions */
typedef enum
{
  ADXL345_FUNC_FREEFALL               = 0b00000100, // 4
  ADXL345_FUNC_INACTIVITY             = 0b00001000, // 8
  ADXL345_FUNC_ACTIVITY               = 0b00010000, // 16
  ADXL345_FUNC_SINGLE_TAP             = 0b00100000, // 32
  ADXL345_FUNC_DOUBLE_TAP             = 0b01000000, // 64
  ADXL345_FUNC_SINGLE_DOUBLE_TAP      = 0b01100000 // 96
} 
function_t;

/* ADXL345 interrupt pins */
typedef enum
{
  ADXL345_PIN_1 = 0b00000001, // INT 1
  ADXL345_PIN_2 = 0b00000010 // INT 2
} 
pin_t;

/* Thresholds */
typedef enum
{
  ADXL345_THRESHOLD_1G          = 0x0F,
  ADXL345_THRESHOLD_2G          = 0x1F,
  ADXL345_THRESHOLD_3G          = 0x3E,
  ADXL345_THRESHOLD_4G          = 0x3F,
  ADXL345_THRESHOLD_5G          = 0x4E,
  ADXL345_THRESHOLD_6G          = 0x9E,
  ADXL345_THRESHOLD_7G          = 0xAD,
  ADXL345_THRESHOLD_8G          = 0x7F,
  ADXL345_THRESHOLD_9G          = 0x8E,
  ADXL345_THRESHOLD_10G         = 0x9E,
  ADXL345_THRESHOLD_11G         = 0xAD,
  ADXL345_THRESHOLD_12G         = 0xBE,
  ADXL345_THRESHOLD_13G         = 0xCD,
  ADXL345_THRESHOLD_14G         = 0xDD,
  ADXL345_THRESHOLD_15G         = 0xEC,
  ADXL345_THRESHOLD_16G         = 0xFF
} 
tap_threshold_t;

/* Duration */
typedef enum
{
  ADXL345_DURATION_DISABLE       = 0b00000000,
  ADXL345_DURATION_625us         = 0b00000001,
  ADXL345_DURATION_1250us        = 0b00000010,
  ADXL345_DURATION_2500us        = 0b00000100,
  ADXL345_DURATION_5ms           = 0b00001000,
  ADXL345_DURATION_10ms          = 0b00010000,
  ADXL345_DURATION_20ms          = 0b00100000,
  ADXL345_DURATION_40ms          = 0b01000000,
  ADXL345_DURATION_80ms          = 0b10000000
} 
tap_duration_t;

/* Window & Latency */
typedef enum
{
  ADXL345_WINLAT_DISABLE      = 0b00000000,
  ADXL345_WINLAT_1p25ms       = 0b00000001,
  ADXL345_WINLAT_2p5ms        = 0b00000010,
  ADXL345_WINLAT_5ms          = 0b00000100,
  ADXL345_WINLAT_10ms         = 0b00001000,
  ADXL345_WINLAT_20ms         = 0b00010000,
  ADXL345_WINLAT_40ms         = 0b00100000,
  ADXL345_WINLAT_80ms         = 0b01000000,
  ADXL345_WINLAT_160ms        = 0b10000000,
  ADXL345_WINLAT_318ms        = 0b11111111,
} 
tap_window_latency_t;

/* Window & Latency */
typedef enum
{
  ADXL345_AXIS_DISABLE   = 0b0000,
  ADXL345_AXIS_Z         = 0b0001,
  ADXL345_AXIS_Y         = 0b0010,
  ADXL345_AXIS_X         = 0b0100,
  ADXL345_AXIS_SUPPRESS  = 0b1000, // Suppress double tap if acceleration is greater than threshold
}
axis_t;

/* Free fall threshold */
typedef enum
{
  ADXL345_FREEFALL_300mg      = 0b00000101,
  ADXL345_FREEFALL_375mg      = 0b00000110,
  ADXL345_FREEFALL_450mg      = 0b00000111,
  ADXL345_FREEFALL_525mg      = 0b00001000,
  ADXL345_FREEFALL_600mg      = 0b00001001,
} 
freefall_threshold_t;

/* Free fall time */
typedef enum
{
  ADXL345_FREEFALL_100ms      = 0b00010100,
  ADXL345_FREEFALL_150ms      = 0b00011110,
  ADXL345_FREEFALL_200ms      = 0b00101000,
  ADXL345_FREEFALL_250ms      = 0b00110010,
  ADXL345_FREEFALL_300ms      = 0b00111100,
  ADXL345_FREEFALL_350ms      = 0b01000110
} 
freefall_time_t;

Adafruit_ADXL345_U.cpp (12.3 KB)

Adafruit_ADXL345_U.h (12.8 KB)

sensortest.ino (4.69 KB)

void freeFall(void)
{
digitalWrite(8, nLED);
if (nLED == HIGH)
nLED = LOW;
else
nLED = HIGH;
}

Don't you want to toggle the state first?

  nLED = !nLED;

would replace your 4 lines of code.

  [b]accel.setADXL345FreeFallIntFunc(0, &freeFall, ADXL345_PIN_1);[/b]

Does that even compile?

How are you putting the accelerometer and the Arduino in free fall? Does polling the accelerometer indicate that it is indeed in free fall when you think the interrupt should happen?

I don't see where you set the pinMode for pin 8 to OUTPUT.

PaulS:
Don't you want to toggle the state first?

  nLED = !nLED;

would replace your 4 lines of code.

  [b]accel.setADXL345FreeFallIntFunc(0, &freeFall, ADXL345_PIN_1);[/b]

Does that even compile?

How are you putting the accelerometer and the Arduino in free fall? Does polling the accelerometer indicate that it is indeed in free fall when you think the interrupt should happen?

Yes it does compile.

And I am dropping the ADXL from about 15cm or so on to the desk.

groundfungus:
I don't see where you set the pinMode for pin 8 to OUTPUT.

Oh bugger - I forgot about that bit.

Yes it does compile.

With the bold tags?

Obviously there must be something else I have to do to the ADXL to setup the interrupt, but I don't know what it is.

I can only conclude that I have a module with a faulty chip on it because none of the code examples (of setting up an interrupt) will work with it.

Time to bin it and try another module I think.