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
/**
**************************************************
*
* @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:
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 noneConstructor. 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_tStarts 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
| Type | Name | Description |
|---|---|---|
uint8_t | address | I2C address. BMA400_I2C_ADDRESS_DEFAULT (0x14, the default) or BMA400_I2C_ADDRESS_SECONDARY (0x15). |
TwoWire & | wirePort | I2C bus to use. Defaults to Wire. |
int8_t setGeneric1Interrupt(bma400_gen_int_conf* config)returns int8_tWrites 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
| Type | Name | Description |
|---|---|---|
bma400_gen_int_conf* | config | Pointer 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_tSets an interrupt pin as push-pull or open drain, active high or active low.
Returns0 on success, negative on failure.
Parameters
| Type | Name | Description |
|---|---|---|
bma400_int_chan | channel | The pin to configure, for example BMA400_INT_CHANNEL_1 for INT1. |
uint8_t | mode | BMA400_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_tTurns one interrupt condition on or off.
Returns0 on success, negative on failure.
Parameters
| Type | Name | Description |
|---|---|---|
bma400_int_type | intType | The condition, for example BMA400_GEN1_INT_EN for generic interrupt 1. |
bool | enable | true to enable, false to disable. |
int8_t getInterruptStatus(uint16_t* status)returns int8_tReads which interrupt conditions are asserted. Test the result against flags such as BMA400_ASSERTED_GEN1_INT.
Returns0 on success, negative on failure.
Parameters
| Type | Name | Description |
|---|---|---|
uint16_t* | status | Receives 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.