Hello there,
I'm trying to detect free falls with my XIAO nRF52840 which has the LSM6DS3 IMU included.
However, I can't make it work - neither "by polling" not receiving any interrupt for this.
I found some good examples for (Double) Taps with interrupts and it works fine.
But when I adapt the code the free-fall detection I never get anything.
And just to be sure I bought multiple nRF52840 boards but none seems to work. So they are not just broken.
Even the sample code from the libraries doesn't result anything (it compiles, just does not trigger).
I even asked in forums like here
https://forum.arduino.cc/t/lsm6ds3-free-fall-detection-not-working/1163290/7
and
https://forum.seeedstudio.com/t/xiao-nrf52840-free-fall-detection-not-working/272103
Maybe someone here might know more. I saw some good blog posts and smart answers here.
The adapted sample code (also from Sparksfun) looks like that:
#include "LSM6DS3.h"
#include "Wire.h"
#include "SPI.h"
LSM6DS3 myIMU( I2C_MODE, 0x6A );
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Sketch came out of reset.\n");
if( myIMU.begin() != 0 )
{
Serial.print("Error at begin().\n");
}
else
{
Serial.print("\nbeginCore() passed.\n");
}
uint8_t errorAccumulator = 0;
uint8_t dataToWrite = 0;
//Setup the accelerometer******************************
dataToWrite = 0; //Start Fresh!
dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_200Hz;
dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_2g;
dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_416Hz;
// //Now, write the patched together data
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite);
errorAccumulator += myIMU.readRegister(&dataToWrite, LSM6DS3_ACC_GYRO_CTRL4_C);
// Write 00h into WAKE_UP_DUR
errorAccumulator += myIMU.writeRegister( LSM6DS3_ACC_GYRO_WAKE_UP_DUR, 0x00 );
// Set FF threshold (FF_THS[2:0] = 011b)
// Set six samples event duration (FF_DUR[5:0] = 000110b)
// Write 33h into FREE_FALL
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x33);
// FF interrupt driven to INT1 pin
// Write 10h into MD1_CFG
errorAccumulator += myIMU.writeRegister( LSM6DS3_ACC_GYRO_MD1_CFG, 0x10 );
// Also route to INT2 pin
// Write 10h into MD1_CFG
errorAccumulator += myIMU.writeRegister( LSM6DS3_ACC_GYRO_MD2_CFG, 0x10 );
// Latch interrupt
// Write 01h into TAP_CFG
errorAccumulator += myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x01);
if( errorAccumulator )
{
Serial.println("Problem configuring the device.");
}
else
{
Serial.println("Device O.K.");
}
}
void loop()
{
uint8_t readDataByte = 0;
//Read the wake-up source register
myIMU.readRegister(&readDataByte, LSM6DS3_ACC_GYRO_WAKE_UP_SRC);
//Mask off the FF_IA bit for free-fall detection
readDataByte &= 0x20;
//Check for free-fall
if( readDataByte )
{
//debounce
delay(10);
Serial.println("Interrupt caught. Free fall detected.");
}
}
#include "LSM6DS3.h"
#include "Wire.h"
LSM6DS3 myIMU(I2C_MODE, 0x6A);
#define int1Pin PIN_LSM6DS3TR_C_INT1
volatile uint8_t interruptCount = 0; // Amount of received interrupts
uint8_t prevInterruptCount = 0; // Interrupt Counter from last loop
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("--- START ---");
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
setLedRGB(false, false, true); // set blue led
myIMU.settings.accelEnabled = 1;
myIMU.settings.tempEnabled = 1;
myIMU.settings.gyroEnabled = 1; // Gyro currently not used, disabled to save power
if (myIMU.begin() != 0) {
Serial.println("IMU error");
} else {
Serial.println("IMU OK!");
}
setupFreeFallInterrupt();
pinMode(int1Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);
}
void loop() {
setLedRGB(false, false, true); // reset led to blue only
Serial.print("\Iterrupt Counter: ");
Serial.println(interruptCount);
// if interrupt was received in this cycle
if (interruptCount > prevInterruptCount) {
Serial.println("\Interrupt received!");
setLedRGB(false, true, false); // set green only
}
prevInterruptCount = interruptCount;
if (interruptCount >= 5) {
// Trigger System OFF after 5 interrupts
goToPowerOff();
}
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x01); // LATCHED
delay(500);
}
// -------------------- System ------------------------- //
void goToPowerOff() {
setLedRGB(false, false, false);
Serial.println("Going to System OFF");
setupFreeFallInterrupt(); // not needed here, if already applied..
delay(100); // delay seems important to apply settings, before going to System OFF
//Ensure interrupt pin from IMU is set to wake up device
nrf_gpio_cfg_sense_input(digitalPinToInterrupt(int1Pin), NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
// Trigger System OFF
NRF_POWER->SYSTEMOFF = 1;
}
// -------------------- Interrupts ------------------------- //
void setupFreeFallInterrupt() {
uint8_t error = 0;
uint8_t dataToWrite = 0;
// 4A = 01001010
// 0000 10 10 LSM6DS3_ACC_GYRO_BW_XL_100Hz LSM6DS3_ACC_GYRO_FS_XL_4g
dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_100Hz; // 0000 0001 200Hz
dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_4g; // 0000 0000 2g
dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_104Hz;// 0100 0000 104Hz
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite);
// Set the ODR config register to ODR/4 -> 1001
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL8_XL, 0x09);
// p.61
// enable linear acceleration sensor
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL9_XL, 0x38);
// Wakeup source (p.62)
// 00100000 x20
// 00101111 x2f FF
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_SRC, 0b00100000);
// TAP_CFG (58h) Register (page 77)
// Latch interrupt - Write 01h into TAP_CFG
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0b00000001); // LATCHED
//MD1_CFG (5Eh) Functions routing on INT1 register (page 80)
// Free fall
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0b000010000); // 00010000
//p.79 -> default valuesMD1_CFG
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_DUR, 0b00000000);
// p.80 ->
// 00110 : 6 events
// 011 : 312mg threshold
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x33); // 00110 011
error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0b000110); // 00001 011 1x 312mg
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x30); // 00110 000 156mg
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x00); // 00000 000 156mg
//error += myIMU.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x07); // 00000 111 500mg
if (error) {
Serial.println("Problem configuring the device.");
} else {
Serial.println("Device O.K.");
}
}
void int1ISR()
{
interruptCount++;
}
// -------------------- Utilities ------------------------- //
void setLedRGB(bool red, bool green, bool blue) {
if (!blue) { digitalWrite(LED_BLUE, HIGH); } else { digitalWrite(LED_BLUE, LOW); }
if (!green) { digitalWrite(LED_GREEN, HIGH); } else { digitalWrite(LED_GREEN, LOW); }
if (!red) { digitalWrite(LED_RED, HIGH); } else { digitalWrite(LED_RED, LOW); }
}