Configuring interrupt on accelerometer (LIS331HH)

I’m trying to write a program that uses an accelerometer (LIS331HH, SparkFun Triple Axis Accelerometer Breakout - LIS331 - SEN-10345 - SparkFun Electronics) as the input to light LEDs. There are 6 LEDs, and each time the accelerometer records a bump, I want the interrupt to trigger, then calling a function to light the next LED in the chain and turn the previous one off. I found some code online already to read the accelerometer fine, but it didn’t use interrupts so I’ve been trying to configure those on my own. The datasheet is here (https://www.sparkfun.com/datasheets/Sensors/Accelerometer/LIS331HH.pdf). Also, I’m using a Pro Mini (3.3V, 8MHz, ATmega328).

Since I’m watching for a bump, I want to monitor if the inputs are either positive or negative, so I’m using interrupt 1 for high events and interrupt 2 for low events. The problem is setting the threshold that triggers the interrupt. The accelerometer provides raw readings between ±5500, which I then convert to Gs in the program. In the register that holds the threshold value of the interrupt, I only have 7 bits, giving me a maximum value of 127, so I don’t know how to get a meaningful threshold from it. Right now, the interrupt stays high all the time, even when the values are negative, so that isn’t right either. I think that might involve reading the INT1_SRC register, which I believe clears the interrupt event, but I’m not sure. My code is below (doesn’t involve LED lighting right now, just basic reading accelerometer and configuring interrupt so I can measure the interrupt on my own with a DMM and see if it gets set high on bumps). Any help would be appreciated!

// 3-axis Accelerometer
// Sparkfun Electronics Triple Axis Accelerometer Breakout - LIS331
// Arduino UNO

/* Wiring:
UNO LIS331

3.3V VCC
GND GND
10 CS 
11 SDA/SDI
12 SA0/SDO
13 SCL/SPC
*/

#include <SPI.h>
#include <stdlib.h>
#include <stdio.h>

#define SS 10 // Serial Select -> CS on LIS331
#define MOSI 11 // MasterOutSlaveIn -> SDI
#define MISO 12 // MasterInSlaveOut -> SDO
#define SCK 13 // Serial Clock -> SPC on LIS331

#define SCALE .0007324; // approximate scale factor for full range (+/-24g)
// scale factor: +/-24g = 48G range. 2^16 bits. 48/65536 = 0.0007324

// global acceleration values
double xAcc, yAcc, zAcc, total;

void setup()
{
Serial.begin(9600);

// Configure SPI
SPI_SETUP();

// Configure accelerometer
Accelerometer_Setup();
}


void loop()
{
readVal(); // get acc values and put into global variables

Serial.print(xAcc, 1);
Serial.print(",");
Serial.print(yAcc, 1);
Serial.print(",");
Serial.print(zAcc, 1);
Serial.print(",");
Serial.println(total, 1);

total = zAcc + yAcc + xAcc;

delay(10);
}

// Read the accelerometer data and put values into global variables
void readVal()
{
byte xAddressByteL = 0x28; // Low Byte of X value (the first data register)
byte readBit = B10000000; // bit 0 (MSB) HIGH means read register
byte incrementBit = B01000000; // bit 1 HIGH means keep incrementing registers
// this allows us to keep reading the data registers by pushing an empty byte
byte dataByte = xAddressByteL | readBit | incrementBit;
byte b0 = 0x0; // an empty byte, to increment to subsequent registers

digitalWrite(SS, LOW); // SS must be LOW to communicate
delay(1);
SPI.transfer(dataByte); // request a read, starting at X low byte
byte xL = SPI.transfer(b0); // get the low byte of X data
byte xH = SPI.transfer(b0); // get the high byte of X data
byte yL = SPI.transfer(b0); // get the low byte of Y data
byte yH = SPI.transfer(b0); // get the high byte of Y data
byte zL = SPI.transfer(b0); // get the low byte of Z data
byte zH = SPI.transfer(b0); // get the high byte of Z data
delay(1);
digitalWrite(SS, HIGH);

// shift the high byte left 8 bits and merge the high and low
int xVal = (xL | (xH << 8));
int yVal = (yL | (yH << 8));
int zVal = (zL | (zH << 8));

// scale the values into G's
xAcc = xVal * SCALE;
yAcc = yVal * SCALE;
zAcc = zVal * SCALE;
}

void SPI_SETUP()
{
pinMode(SS, OUTPUT);

// wake up the SPI bus
SPI.begin();

// This device reads MSB first:
SPI.setBitOrder(MSBFIRST);

/*
SPI.setDataMode()
Mode	 Clock Polarity (CPOL) Clock Phase (CPHA)
SPI_MODE0	 0	 0
SPI_MODE1	 0	 1
SPI_MODE2	 1	 0
SPI_MODE3	 1	 1
*/
SPI.setDataMode(SPI_MODE0);

/*
SPI.setClockDivider()
sets SPI clock to a fraction of the system clock
Arduino UNO system clock = 16 MHz
Mode SPI Clock
SPI_CLOCK_DIV2 8 MHz
SPI_CLOCK_DIV4 4 MHz
SPI_CLOCK_DIV8 2 MHz
SPI_CLOCK_DIV16 1 MHz
SPI_CLOCK_DIV32 500 Hz
SPI_CLOCK_DIV64 250 Hz
SPI_CLOCK_DIV128 125 Hz
*/

SPI.setClockDivider(SPI_CLOCK_DIV16); // SPI clock 1000Hz
}

void Accelerometer_Setup()
{
// Set up the accelerometer
// write to Control register 1: address 20h
byte addressByte = 0x20;
/* Bits:
PM2 PM1 PM0 DR1 DR0 Zen Yen Xen
PM2PM1PM0: Power mode (001 = Normal Mode)
DR1DR0: Data rate (00=50Hz, 01=100Hz, 10=400Hz, 11=1000Hz)
Zen, Yen, Xen: Z enable, Y enable, X enable
*/
byte ctrlRegByte = 0x37; // 00111111 : normal mode, 1000Hz, xyz enabled

// Send the data for Control Register 1
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// write to Control Register 2: address 21h
addressByte = 0x21;
// This register configures high pass filter
ctrlRegByte = 0x00; // High pass filter off

// Send the data for Control Register 2
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// Control Register 3 configures Interrupts
addressByte = 0x22;
/* Bits:
IHL PP_OD LIR2 I2_CFG1 I2_CFG0 LIR1 I1_CFG1 I1_CFG0
IHL: interrupt high low (0=active high)
PP_OD: push-pull/open drain selection (0=push-pull)
LIR2: latch interrupt request on INT2_SRC register (0=interrupt request not latched)
I2_CFG1, I2_CFG0: data signal on INT 2 pad control bits 
LIR1: latch interrupt request on INT1_SRC register (0=interrupt request not latched)
I1_CFG1, I1_CFG0: data signal on INT 1 pad control bits

Data signal on pad
I1(2)_CFG1      I1(2)_CFG0            INT 1(2) pad
    0                0              interrupt 1(2) source
    0                1              interrupt 1 source or interrupt 2 source
    1                0              data ready
    1                1              boot running

*/
ctrlRegByte = 0x24; // 00100100 : interrupt request latched to interrupt source 1 and interrupt source 2

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// write to Control Register 4: address 23h
addressByte = 0x23;
/* Bits:
BDU BLE FS1 FS0 STsign 0 ST SIM
BDU: Block data update (0=continuous update)
BLE: Big/little endian data (0=accel data LSB at LOW address)
FS1FS0: Full-scale selection (00 = +/-6G, 01 = +/-12G, 11 = +/-24G)
STsign: selft-test sign (default 0=plus)
ST: self-test enable (default 0=disabled)
SIM: SPI mode selection(default 0=4 wire interface, 1=3 wire interface)
*/
ctrlRegByte = 0x30; // 00110000 : 24G (full scale)


// Send the data for Control Register 4
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// Control Register for interrupt configuration (INT1_CFG)
addressByte = 0x30;
ctrlRegByte = 0x2A; // 00101010 : interrupt request enabled on high Z, high Y, high X events

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt threshold for high events (INT1_THS)
addressByte = 0x32;
ctrlRegByte = 0x7F; // 0 0000000 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt duration for high events (INT1_DURATION)
addressByte = 0x33;
ctrlRegByte = 0x02; // 0 0000010 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt configuration (INT2_CFG)
addressByte = 0x34;
ctrlRegByte = 0x15; // 00010101 : interrupt request enabled on low Z, low Y, low X events

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt threshold (INT2_THS)
addressByte = 0x36;
ctrlRegByte = 0x00; // 00000000 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

}

I want the interrupt to trigger

What interrupt? Is the accelerometer capable of generating a pulse that triggers an interrupt?

Typically, an accelerometer is polled.

Is
there
some
reason
every
line
of
code
starts
in
column
one?

The accelerometer has two outputs called INT1 and INT2, which can generate pulses, which can then be used for interrupts (I believe, correct me if I'm missing something). I'm trying to let the accelerometer constantly run and when a certain threshold is exceeded, INT1 will be set high (which I'll connect to a pin on the arduino and I'll use attachInterrupt() with it to determine the next action for the program).

I already have INT1 outputting a signal so I know it's possible to generate an output, I just don't know how to correctly set it as well as the threshold since it seems I can only set 127 (1111111) and most values are +-5500. Even when all the values are negative, I'm still getting a high output signal from INT1 which is more confusing since at least 127 is greater than those values, so I know I'm not configuring it right.

For reference, I'm setting up the registers and interrupts from the tables on pages 24-37 of the data sheet (https://www.sparkfun.com/datasheets/Sensors/Accelerometer/LIS331HH.pdf). And sorry about the lack of indenting, that's just how I found the code and never bothered to reformat it.

Managed to get it working well enough for my purposes. For future reference for others, I solved the problem of the interrupt always being high by setting the LIR1 and LIR2 bits in Control Register 3 to 0 (the value written to that register ended up being the default 00000000). When it was latched, the interrupt was only cleared when the INT1_SRC register was read, but I wanted the interrupt signal cleared according to the data produced by the accelerometer. For the threshold/duration, I just played around with the values until I was happy with how much of a bump was required to move to the next LED. Here’s the code if anyone else needs it (only lights 3 LEDs for now since that’s all I had on hand):

// 3-axis Accelerometer
// Sparkfun Electronics Triple Axis Accelerometer Breakout - LIS331
// Arduino UNO

/* Wiring:
UNO LIS331

3.3V VCC
GND GND
10 CS 
11 SDA/SDI
12 SA0/SDO
13 SCL/SPC
*/

#include <SPI.h>
#include <stdlib.h>
#include <stdio.h>

#define SS 10 // Serial Select -> CS on LIS331
#define MOSI 11 // MasterOutSlaveIn -> SDI
#define MISO 12 // MasterInSlaveOut -> SDO
#define SCK 13 // Serial Clock -> SPC on LIS331

#define SCALE 1//.0007324; // approximate scale factor for full range (+/-24g)
// scale factor: +/-24g = 48G range. 2^16 bits. 48/65536 = 0.0007324

// global acceleration values
double xAcc, yAcc, zAcc, total;
boolean start = true;

void setup()
{
Serial.begin(9600);

// Configure SPI
SPI_SETUP();

// Configure accelerometer
Accelerometer_Setup();
attachInterrupt(0, increment, RISING);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
pinMode(2, INPUT);
}


void loop()
{
readVal(); // get acc values and put into global variables

Serial.print(xAcc, 1);
Serial.print(",");
Serial.print(yAcc, 1);
Serial.print(",");
Serial.print(zAcc, 1);
Serial.print(",");
Serial.println(total, 1);

total = zAcc + yAcc + xAcc;

delay(10);
}

void increment(){
  if(start){
    digitalWrite(14, HIGH);
    start = false;
  }
  else if(digitalRead(16)==HIGH && digitalRead(14)==LOW){
    digitalWrite(16, LOW);
    digitalWrite(14, HIGH);
  }
  else if(digitalRead(14)==HIGH && digitalRead(15)==LOW){
    digitalWrite(14, LOW);
    digitalWrite(15, HIGH);
  }
  else if(digitalRead(15)==HIGH && digitalRead(16)==LOW){
    digitalWrite(15, LOW);
    digitalWrite(16, HIGH);
  }
}
  
    

// Read the accelerometer data and put values into global variables
void readVal()
{
byte xAddressByteL = 0x28; // Low Byte of X value (the first data register)
byte readBit = B10000000; // bit 0 (MSB) HIGH means read register
byte incrementBit = B01000000; // bit 1 HIGH means keep incrementing registers
// this allows us to keep reading the data registers by pushing an empty byte
byte dataByte = xAddressByteL | readBit | incrementBit;
byte b0 = 0x0; // an empty byte, to increment to subsequent registers

digitalWrite(SS, LOW); // SS must be LOW to communicate
delay(1);
SPI.transfer(dataByte); // request a read, starting at X low byte
byte xL = SPI.transfer(b0); // get the low byte of X data
byte xH = SPI.transfer(b0); // get the high byte of X data
byte yL = SPI.transfer(b0); // get the low byte of Y data
byte yH = SPI.transfer(b0); // get the high byte of Y data
byte zL = SPI.transfer(b0); // get the low byte of Z data
byte zH = SPI.transfer(b0); // get the high byte of Z data
delay(1);
digitalWrite(SS, HIGH);

// shift the high byte left 8 bits and merge the high and low
int xVal = (xL | (xH << 8));
int yVal = (yL | (yH << 8));
int zVal = (zL | (zH << 8));

// scale the values into G's
xAcc = xVal * SCALE;
yAcc = yVal * SCALE;
zAcc = zVal * SCALE;
}

void SPI_SETUP()
{
pinMode(SS, OUTPUT);

// wake up the SPI bus
SPI.begin();

// This device reads MSB first:
SPI.setBitOrder(MSBFIRST);

/*
SPI.setDataMode()
Mode    Clock Polarity (CPOL) Clock Phase (CPHA)
SPI_MODE0    0    0
SPI_MODE1    0    1
SPI_MODE2    1    0
SPI_MODE3    1    1
*/
SPI.setDataMode(SPI_MODE0);

/*
SPI.setClockDivider()
sets SPI clock to a fraction of the system clock
Arduino UNO system clock = 16 MHz
Mode SPI Clock
SPI_CLOCK_DIV2 8 MHz
SPI_CLOCK_DIV4 4 MHz
SPI_CLOCK_DIV8 2 MHz
SPI_CLOCK_DIV16 1 MHz
SPI_CLOCK_DIV32 500 Hz
SPI_CLOCK_DIV64 250 Hz
SPI_CLOCK_DIV128 125 Hz
*/

SPI.setClockDivider(SPI_CLOCK_DIV16); // SPI clock 1000Hz
}

void Accelerometer_Setup()
{
// Set up the accelerometer
// write to Control register 1: address 20h
byte addressByte = 0x20;
/* Bits:
PM2 PM1 PM0 DR1 DR0 Zen Yen Xen
PM2PM1PM0: Power mode (001 = Normal Mode)
DR1DR0: Data rate (00=50Hz, 01=100Hz, 10=400Hz, 11=1000Hz)
Zen, Yen, Xen: Z enable, Y enable, X enable
*/
byte ctrlRegByte = 0x37; // 00111111 : normal mode, 1000Hz, xyz enabled

// Send the data for Control Register 1
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// write to Control Register 2: address 21h
addressByte = 0x21;
// This register configures high pass filter
ctrlRegByte = 0x00; // High pass filter off

// Send the data for Control Register 2
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// Control Register 3 configures Interrupts
addressByte = 0x22;
/* Bits:
IHL PP_OD LIR2 I2_CFG1 I2_CFG0 LIR1 I1_CFG1 I1_CFG0
IHL: interrupt high low (0=active high)
PP_OD: push-pull/open drain selection (0=push-pull)
LIR2: latch interrupt request on INT2_SRC register (0=interrupt request not latched)
I2_CFG1, I2_CFG0: data signal on INT 2 pad control bits 
LIR1: latch interrupt request on INT1_SRC register (0=interrupt request not latched)
I1_CFG1, I1_CFG0: data signal on INT 1 pad control bits

Data signal on pad
I1(2)_CFG1      I1(2)_CFG0            INT 1(2) pad
    0                0              interrupt 1(2) source
    0                1              interrupt 1 source or interrupt 2 source
    1                0              data ready
    1                1              boot running

*/
ctrlRegByte = 0x00; // 00000000 : default

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// write to Control Register 4: address 23h
addressByte = 0x23;
/* Bits:
BDU BLE FS1 FS0 STsign 0 ST SIM
BDU: Block data update (0=continuous update)
BLE: Big/little endian data (0=accel data LSB at LOW address)
FS1FS0: Full-scale selection (00 = +/-6G, 01 = +/-12G, 11 = +/-24G)
STsign: selft-test sign (default 0=plus)
ST: self-test enable (default 0=disabled)
SIM: SPI mode selection(default 0=4 wire interface, 1=3 wire interface)
*/
ctrlRegByte = 0x30; // 00110000 : 24G (full scale)


// Send the data for Control Register 4
digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);


// Control Register for interrupt configuration (INT1_CFG)
addressByte = 0x30;
ctrlRegByte = 0x2A; // 00101010 : interrupt request enabled on high Z, high Y, high X events

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt threshold for high events (INT1_THS)
addressByte = 0x32;
ctrlRegByte = 0x0F; // 0 0000000 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt duration for high events (INT1_DURATION)
addressByte = 0x33;
ctrlRegByte = 0x02; // 0 0000010 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);
/*
// Control Register for interrupt configuration (INT2_CFG)
addressByte = 0x34;
ctrlRegByte = 0x15; // 00010101 : interrupt request enabled on low Z, low Y, low X events

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);

// Control Register for interrupt threshold (INT2_THS)
addressByte = 0x36;
ctrlRegByte = 0x00; // 00000000 : value TBD

digitalWrite(SS, LOW);
delay(1);
SPI.transfer(addressByte);
SPI.transfer(ctrlRegByte);
delay(1);
digitalWrite(SS, HIGH);

delay(100);
*/
}