Skip to main content

Motion detection

What this example shows​

Letting the BMA400 watch for movement on its own. The chip's generic interrupt 1 compares the acceleration with a reference and raises INT1 when any axis moves more than the threshold. Your controller only reacts to the interrupt.

Besides Qwiic or the I2C header pins, wire the breakout's INT1 pin to digital pin 2 on your controller, or change interruptPin in the sketch to the pin you use. The pin has to support interrupts.

The example code​

Select Board
motionDetection.ino
/**
**************************************************
*
* @file motionDetection.ino
*
* @brief Example showing how to use the BMA400's generic interrupt
* feature to detect motion via a hardware interrupt pin
*
* @link solde.red/333419 : Soldered BMA400 Accelerometer breakout
*
* @authors SparkFun Electronics, modified by Soldered Electronics
***************************************************/
#include <BMA400-SOLDERED.h>

// Create an instance of the BMA400 sensor
Soldered_BMA400 accelerometer;

// Pin connected to the sensor's INT1 pin, change to match your wiring
int interruptPin = 2;

// Flag to know when an interrupt occurs
volatile bool interruptOccurred = false;

void bma400InterruptHandler()
{
interruptOccurred = true;
}

void setup()
{
// Initialize serial for output
Serial.begin(115200);
Serial.println("BMA400 Example - Motion Detection");

// Initialize I2C bus
Wire.begin();

// Check if sensor is connected and initialize it.
// Address is optional, defaults to 0x14
while (accelerometer.begin() != BMA400_OK)
{
Serial.println("Error: BMA400 not connected, check wiring and I2C address!");
delay(1000);
}

Serial.println("BMA400 connected!");

// Configure the generic interrupt feature. It triggers an interrupt
// when the measured acceleration exceeds a reference acceleration
bma400_gen_int_conf config = {
.gen_int_thres = 5, // 8mg resolution (e.g. 5 = 40mg)
.gen_int_dur = 5, // 10ms resolution (e.g. 5 = 50ms)
.axes_sel = BMA400_AXIS_XYZ_EN, // Evaluate all axes for interrupts
.data_src = BMA400_DATA_SRC_ACCEL_FILT_2, // Datasheet recommends filter 2 (100Hz)
.criterion_sel = BMA400_ACTIVITY_INT, // Trigger when active
.evaluate_axes = BMA400_ANY_AXES_INT, // Trigger if any axis exceeds threshold
.ref_update = BMA400_UPDATE_EVERY_TIME, // Automatically update reference values
.hysteresis = BMA400_HYST_96_MG, // Hysteresis for noise rejection
.int_thres_ref_x = 0, // Raw 12-bit reference value
.int_thres_ref_y = 0, // Raw 12-bit reference value
.int_thres_ref_z = 512, // Raw 12-bit reference value (1g at 4g range)
.int_chan = BMA400_INT_CHANNEL_1 // Route interrupt to INT1 pin
};
accelerometer.setGeneric1Interrupt(&config);

// Configure INT1 pin to push/pull mode, active high
accelerometer.setInterruptPinMode(BMA400_INT_CHANNEL_1, BMA400_INT_PUSH_PULL_ACTIVE_1);

// Enable the generic 1 interrupt condition
accelerometer.enableInterrupt(BMA400_GEN1_INT_EN, true);

// Attach the interrupt handler to the microcontroller pin wired to INT1
attachInterrupt(digitalPinToInterrupt(interruptPin), bma400InterruptHandler, RISING);
}

void loop()
{
if (interruptOccurred)
{
interruptOccurred = false;

// Check which interrupt condition triggered
uint16_t interruptStatus = 0;
accelerometer.getInterruptStatus(&interruptStatus);

if (interruptStatus & BMA400_ASSERTED_GEN1_INT)
{
Serial.println("Motion detected!");
}
}
}

This example also uses attachInterrupt() and digitalPinToInterrupt() (Arduino reference), which come with the Arduino core and are not part of the Soldered BMA400 Accelerometer library.

Expected result:

Serial MonitorAutoscrollShow timestampNewline115200 baud
Message (Enter to send message to the board)
BMA400 Example - Motion Detection
BMA400 connected!
Motion detected!

The first two lines appear at start-up. Motion detected! appears each time the BMA400 signals movement on INT1.

Functions used​

Soldered_BMA400()returns none

Constructor. Creates the sensor object; it does not talk to the sensor until you call begin().

ReturnsConstructor; no return value.

int8_t begin(uint8_t address = BMA400_I2C_ADDRESS_DEFAULT, TwoWire &wirePort = Wire)returns int8_t

Starts the sensor over I2C: soft-resets the BMA400, checks its chip ID and puts it in normal power mode.

ReturnsBMA400_OK (0) on success, a negative error code otherwise. An address other than 0x14 or 0x15 returns BMA400_E_INVALID_CONFIG.

Parameters

TypeNameDescription
uint8_taddressI2C address. BMA400_I2C_ADDRESS_DEFAULT (0x14, the default) or BMA400_I2C_ADDRESS_SECONDARY (0x15).
TwoWire &wirePortI2C bus to use. Defaults to Wire.
int8_t setGeneric1Interrupt(bma400_gen_int_conf* config)returns int8_t

Writes the configuration of the BMA400's generic interrupt 1: threshold, duration, axes, data source, trigger criterion, reference update, hysteresis, reference values and the interrupt pin it is routed to.

Returns0 on success, negative on failure.

Parameters

TypeNameDescription
bma400_gen_int_conf*configPointer to the configuration. The example fills gen_int_thres (8 mg steps), gen_int_dur (10 ms steps), axes_sel, data_src, criterion_sel, evaluate_axes, ref_update, hysteresis, int_thres_ref_x, int_thres_ref_y, int_thres_ref_z (raw 12-bit values) and int_chan.
int8_t setInterruptPinMode(bma400_int_chan channel, uint8_t mode)returns int8_t

Sets an interrupt pin as push-pull or open drain, active high or active low.

Returns0 on success, negative on failure.

Parameters

TypeNameDescription
bma400_int_chanchannelThe pin to configure, for example BMA400_INT_CHANNEL_1 for INT1.
uint8_tmodeBMA400_INT_PUSH_PULL_ACTIVE_0, BMA400_INT_PUSH_PULL_ACTIVE_1 (default), BMA400_INT_OPEN_DRIVE_ACTIVE_0 or BMA400_INT_OPEN_DRIVE_ACTIVE_1.
int8_t enableInterrupt(bma400_int_type intType, bool enable)returns int8_t

Turns one interrupt condition on or off.

Returns0 on success, negative on failure.

Parameters

TypeNameDescription
bma400_int_typeintTypeThe condition, for example BMA400_GEN1_INT_EN for generic interrupt 1.
boolenabletrue to enable, false to disable.
int8_t getInterruptStatus(uint16_t* status)returns int8_t

Reads which interrupt conditions are asserted. Test the result against flags such as BMA400_ASSERTED_GEN1_INT.

Returns0 on success, negative on failure.

Parameters

TypeNameDescription
uint16_t*statusReceives the status flags, a combination of BMA400_ASSERTED_* values.

Putting it together​

With gen_int_thres = 5 and gen_int_dur = 5, the interrupt fires when an axis moves more than 40 mg away from its reference for 50 ms, following the example's comments. ref_update = BMA400_UPDATE_EVERY_TIME lets the chip update the reference on its own, and the Z reference of 512 is 1 g at the ±4 g range. INT1 is set to push-pull, active high, so the sketch attaches its handler on a RISING edge.

The handler only sets a volatile flag. loop() then calls getInterruptStatus() over I2C and prints Motion detected! when the generic 1 flag is set.