XIAO BLE Sense (nRF52840) Absolute Wrist TIlt

I am using XIAO BLE Sense nRF52840 which has the inbuilt IMU sensor, LSM6DS3TR-C. In its datasheet I came across the “Absolute Wrist Tilt (AWT)” function which “allows detecting when the angle between a selectable accelerometer semi-axis and the horizontal plane becomes higher than a specific user-selectable value”.
I want to generate an interrupt when the device is tilted by a roll (Y) of 85 to 180 deg, I can’t see anybody use this AWT function unlike free-fall, double tap, etc.
Does anyone know how to enable this?

Hi there,
No you are NOT …LOL :grin:
Yes, Not too difficult You can read the Data-sheet and look at the examples to gain some understanding.
You can generate an interrupt at a certain angle of tilt. AFAIK.
Look at some of the demo’s I posted about the IMU. It’s all about the configuration Register and the values you write to it. There are no High level OUT of the can LIBs, Examples do exist, AFAIK. but I haven’t searched for it.
Also you can use a filter with the RAW floats to get a “YAW” value that also can be utilized.
HTH
GL :slight_smile: PJ :v:

I am unable to find a library that supports this AWT (I am using the Seeed LSM6DS3 library which doesn’t have this, for now).
So, I did try configuring the registers for “tilt detection” and it worked, but I don’t want to stick to the default tilt of 35 degrees… If you could tell me a way to configure this- it would be of great help!

//adapted from the Free Fall example
#include "LSM6DS3.h"
#include "Wire.h"

//Create a instance of class LSM6DS3
LSM6DS3 lsm6ds3(I2C_MODE, 0x6A);    //I2C device address 0x6A
uint16_t detectCount = 0;

void setup() {
    Serial.begin(9600);
    while (!Serial);
    if (lsm6ds3.begin() != 0) {
        Serial.println("Device error");
    } else {
        Serial.println("Device OK!");
    }

    if (0 != config_tilt_detect()) {
        Serial.println("Fail to configure!");
    } else {
        Serial.println("Success to Configure!");
    }
}

void loop() {
    uint8_t readDataByte = 0;
    //Read the wake-up source register
    lsm6ds3.readRegister(&readDataByte, LSM6DS3_ACC_GYRO_FUNC_SRC);
    //Mask off the TILT_IA bit for tilt detection
    readDataByte &= 0x20;
    if (readDataByte) {
        detectCount ++;
        Serial.print("Tilt detected!  ");
        Serial.println(detectCount);
    }
    delay(10);
}

int config_tilt_detect(void) {
    uint8_t error = 0;
    uint8_t dataToWrite = 0;

    dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_200Hz;
    dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_2g;
    dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_416Hz;

    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite); //same
    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_CTRL10_C, 0x3C); //same
    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_DUR, 0x00);//same
    // error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_FREE_FALL, 0x33);
    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x02); //tilt interrupt on INT1
    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_MD2_CFG, 0x02); //tilt interrupt on INT2
    error += lsm6ds3.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0xA1); 

    return error;
}

you can configure the LSM6DS3 sensor to generate an interrupt when the roll (Y) axis exceeds the desired angle range. Here’s a basic example of how you might do this :

#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM6DS3.h>

LSM6DS3 myIMU; // Create an instance of the LSM6DS3 class

void setup() {
  Serial.begin(9600);
  while (!Serial); // Wait for Serial Monitor to open

  if (!myIMU.begin()) {
    Serial.println("Failed to communicate with LSM6DS3.");
    while (1);
  }

  // Set the accelerometer full scale range to +/- 16g
  myIMU.setAccelRange(LSM6DS3_ACC_RANGE_16G);

  // Set the gyroscope full scale range to +/- 2000dps
  myIMU.setGyroRange(LSM6DS3_GYRO_RANGE_2000DPS);

  // Enable the high-pass filter for accelerometer data
  myIMU.enableAccelHPF();

  // Configure the interrupt to trigger when the Y-axis roll angle is between 85 and 180 degrees
  // This assumes you're using the interrupt pin on the LSM6DS3 breakout board
  myIMU.configInt1(gen_int1_route_t::INT1_CTRL_REG_GYRO_XL);

  // Set the angle threshold and duration for the interrupt
  myIMU.setAWTThreshold(LSM6DS3::AWT_THRESHOLD_85_DEG);
  myIMU.setAWTDuration(LSM6DS3::AWT_DURATION_4_SAMPLES);

  // Enable the interrupt
  myIMU.enableAWT();

  Serial.println("LSM6DS3 initialized. Waiting for tilt...");
}

void loop() {
  if (myIMU.readInterrupt(Sensor_Int1)) {
    Serial.println("Tilt detected! Angle exceeded 85 degrees.");
    // You can add additional actions here, such as resetting the sensor or performing specific tasks
    // based on the tilt detection.
  }

  delay(100); // Delay to reduce Serial output rate
}

In this example, the setAWTThreshold function sets the threshold angle for the Absolute Wrist Tilt (AWT) interrupt to 85 degrees, and the setAWTDuration function sets the number of samples required to maintain the threshold before triggering the interrupt. Adjust these values according to your specific requirements.

Also, make sure to refer to the LSM6DS3 datasheet and the SparkFun LSM6DS3 library documentation for more detailed information on how to configure the sensor
Basically it’s this way…

// AWT Config
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x60); // Set accelerometer to 416Hz in low-noise mode
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TILT_CFG, 0x38);  // Enable tilt detection on X and Y axes
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT_DUR2, 0x04);   // Set duration of tilt event
myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x00); // Disable single tap interrupt
myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x04);     // Enable tilt detection interrupt on INT1

HTH
GL :slight_smile: PJ
I have a example somewhere like the IMU park demo? if I find it I’ll post it here.Here is a great link , that helped me a while back.
How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing-DFRobot

Thank you so much for the reply- this is exactly what I need! But, the registers and functions used, ex. LSM6DS3_ACC_GYRO_TILT_CFG, enableAWT() are not declared in the LSM6DS3 library I have installed or the SparkFun one. [If I’m not wrong the first one was taken from SparkFun too]
Is there any other library I need to access these functions?

Hi there,
I think so, sparkfun maybe from the LSM6DS3TR, There’s are several LIB’s for it, Tilt. Also it can be derived from the Accelerometer and an The tangent equation as well.
The motion demo with position on here, Shows that turning up the sensitivity and lower the scale can be enough to sense any tilt at all.
HTH
GL :slight_smile: PJ
They are all derived from this one AFAIK;

I’d like to revive this re AWT - if possible. I did a lot of deep diving into the LSM6DS3 docs and in the end, I discovered that it looks to use INT2, where the other tiles (e.g. 35 degree) use INT1 INT2 per the seeed spec does not have INT2 wired.

Also - using the various libraries I do could not find the exact references. I did play with direct register writes which I think is the best way to define how to configure the chip to do what ever it is you want. The respective document register reference can be added to the code to reference the docs register name. This excludes the need to use any library and saves space.

I’ve searched high and low for specific “working” examples for AWT without success.

Does anyone have a full “WORKING” example for AWT with sleep/wake using register writes ( or a lagit library) to make this work on the XAIO NRF52849 sense?

Or confirm it doesn’t work because INT2 is not physically wired to a internal GPIO pin?

I can use an external ball./mercury switch, but I’d prefer to not lose an external GPIO pin.

Any help/assistance is appreciated.

PJ - The timer/interrupt you gave me was a great pointer (per my other need) - given I didn’t need a time, but a duration.

Hi there,
So I hear you on the INT2 thing. I know the schematic.
but check this out… You can map everything to INT1 pin, small amount of code overhead but can do.
Check out this thread, from Honvi a while back. Dude was like a hound dog on the hunt.
:smile: :+1: turns out same is for the LSM6DS3 part.
Register writes are all that’s required to configure. YMMV

continue…
HTH
GL :slight_smile: PJ
:v:

Wow that’s a slice of heaven image to see how it maps out. Have you found/have any working examples of the wake on tilt degree range? (e.g. 10-20 degrees (not the built in 35 degree)? I saw some light examples I think you/others pointed out but nothing that was a working example. There were references to library naming conventions, but I never found the correct library - to translate to specific registers for write/reg. Although if I had the correct library for the code that would be fine too.

Hi there,
As I myself don’t use it for AWT, but others have so see who comments.
There is a demo on Youtube AFAIk remember of the example , you must write to certain registers. Look at the technical reference guide for ST devices, I believe that’s who’s silicon is in there. there are two one is more in depth and has register write example in it.
Also I don’t know of a Lib explicitly for AWT but can’t help to think one does exist out there.
and I’m 99% sure it is adjustable. I know also there is a variant like it that does have the compass included to get a real YAW value or AOA (Angle of Attack) used in Joystick fly by wire system.

I used it (image) to sus out the interrupt for the Free fall(drop detection) and Motion stuff. working perfect btw.
keep digging you’ll get there.
I’ll have a rewind and look what I have on it & post it up if relevant.
HTH
GL :slight_smile: PJ
:v:

the video demo I saw a long ,long while back had a repo attached so also look on Git hub pretty sure it was for the one with the compass inside to. ie magnetometer if I recall.

c’mon man , What the heck is this? :face_with_peeking_eye: :-1:

That’s a special response :slight_smile: Not sure if that was an ad or scam.

Hi there,
Yea I have seen this b4… The embedded link is messed up.
rat bastids wasting our bandwidth :stuck_out_tongue_closed_eyes:
GL :slight_smile: PJ
:v: