Xiao Sense Accelerometer Examples and Low Power

There were a couple of requests for examples of accelerometer use with optimized power, so I played around to create some examples and measure their power usage. The attached zip files contain a series of sketches that help quantify incremental power usage for a few accelerometer features.
PowerTests.zip (8.3 KB)

  • gpioWakeUp: 4.2 uA idle, 1.9 uA system_off sleep. I think this is close to minimal power usage for the Xiao sense and provides a baseline. Demonstrates wake up with a GPIO input. No attached interrupt routine.

  • gpioInterrupt: 18.6 uA idle, 1.9 uA system_off sleep. Adds an interrupt service routine attached to a button. Arduino uses ā€œhigh accuracyā€ interrupts, so adds 14uA to idle power usage. Increased power can be avoided using a custom interrupt routine as described here: Getting lower power consumption on Seeed XIAO nRF52840.

  • nudgeWakeUp: 4.2 uA idle, 7.9uA system_off sleep. Uses the ā€œwake-upā€ feature of the accelerometer to wake from system_off. The accelerometer only used for wake-up. No interrupt handling.

There is a trade-off between accelerator performance and power usage. The wake-up function power usage depends on the ā€œoutput data rateā€ (ODR). The application note uses a default of 416Hz with a resulting power usage of 162 uA in system_off sleep. The nudgeWakeUp sketch is using the minimum rate of 1.6Hz. It still detects movement, but the movement detection is noticeably different. For a specific application with a low power design goal I would imagine starting with the low power setting and then tuning parameters until it performed as desired.

  • doubleTapWakeUp: 4.2 uA idle, 28 uA system_off sleep. Uses the double-tap feature to wake from system_off. No interrupt handling.

The double-tap detection parameters are affected more by the ODR. The sketch ODR value of 52Hz is the lowest I could use and still get it to work somewhat reliably. (I didnā€™t play around that long, so someone might get different results). The application note uses 416Hz which results in 162 uA. If you change the ODR, you need to adjust other detection parameters to match the results of the application note.

  • combination: 179.3 uA idle, 7.9 uA system_off sleep. Combines all of the above and includes response to the double-tap. Uses the low power accelerator wake-up function during system_off sleep and turns on the double-tap response once awake. (My fitbit seems to work this way.)

Next Iā€™ll add some Bluetooth functionality and see how it affects the power usage.

6 Likes

Great work!! Thank you very much

Nice work daCoder,
Iā€™m using both Motion detection and Fall detection With BLE . it took allot of trial an Error to get the correct Sensitivity ,Duration, Tap THS reg and the ODR, for both features to work independently, Quiet and Shock time windows 7F and in combination.
I have some comments in there as well. Here are some snips. When I get more time Iā€™ll massage it to work on Dev board and post the complete code. It uses BLE to turn on and off each feature and Notifies the MIT app inventor 2 app. So Iā€™m interested in battery power saving and Iā€™m currently using the double-tap wake up from sleep to save battery now, but only ON & off are my only options, a low power operational mode WOULD be preferred. :wink:

// Add default values for enabling/disabling functions
bool enableFallDetection = true;
bool enableMotionDetection = false;
// Fall detection parameters
float impactThreshold = 1.5;  // G-force threshold for impact (default value)CD CC 0C 40* HEX 20 40 =10G, CD CC 0C 41 =8.80G ,20 41 =2.5 G, 10 40= 2.25G,80 3F 1.0G,C0 3F = 1.5G (liked 2.2)
const int impactTime = 250;   // Time (ms) to wait for impact
bool impactDetected = false;
unsigned long impactTimestamp;
unsigned long lastReadTimestamp = 0;
const int readInterval = 50;  // Time interval (ms) to read acceleration data
// Motion detection parameters
float motionSensitivity =  0.026; // Sensitivity threshold for motion detection (default value)CD CC 4C 3D (8F C2 F5 3E),0.42 F4 FD D4 3E,F4 FD 44 3D=.05*
unsigned long lastMotionTimestamp = 0;
const int motionInterval = 1000;  // Time interval (ms) to check for motion
//bool enableDoupleTap = 0;         // ** turned off for fall demo**
unsigned long lastActivityTime = millis();
String statusString;
//Create a instance of class BLE services & characteristics
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214");  // BluetoothĀ® Low Energy LED Service
// BluetoothĀ® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

BLEService fallService("19B10002-E8F2-537E-4F6C-D104768A1214");
BLEStringCharacteristic fallCharacteristic("19B10003-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 20);//4E-6F-20-46-61-6C-6C"No Fall"(READ), Notify ON, 46414c4c "FALL"
BLEFloatCharacteristic impactLevelCharacteristic("19B10004-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
BLEBoolCharacteristic enableFallDetectionCharacteristic("19B10008-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
// BLE Service and Characteristics
BLEService motionService("19B10005-E8F2-537E-4F6C-D104768A1214");
BLEStringCharacteristic motionCharacteristic("19B10006-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 20);//4E-6F-20-4D-6F-74-69-6F-6E"No Motion", (READ), Notify ON, 4d4f54494f4e "MOTION"
BLEFloatCharacteristic motionSensitivityCharacteristic("19B10007-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
BLEBoolCharacteristic enableMotionDetectionCharacteristic("19B10009-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

BLEService systemStatusService("19B1000C-E8F2-537E-4F6C-D104768A1214"); // UUID for the service
BLEStringCharacteristic systemStatusCharacteristic("19B1000B-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite, 200 ); // UUID for the characteristic

Double Tap Wake upā€¦

void setupDoubleTapInterrupt(bool enable) {
  uint8_t error = 0;
  uint8_t dataToWrite = 0;

  // Double Tap Config
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x60);
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x8E);
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_THS_6D, 0x85);  // Changed the value to 0x01 for increased sensitivity was 85 Set tap threshold 8C,03 in demo
  //myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_THS_6D, tapThreshold);
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT_DUR2, 0x7F);  // Set Duration, Quiet and Shock time windows 7F
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x80); // Single & double-tap enabled (SINGLE_DOUBLE_TAP = 1)
  if (enable) {
     Serial.println("Double Tap ON!");
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x08);  // Enable the double-tap interrupt
  } else {
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x00);  // Disable the double-tap interrupt
    Serial.println("Double Tap OFF");
  }
}

GL :slight_smile: PJ

I am interested in setting up the NudgeWakeUp example but I am not exactly clear how to setup the Xiao or run your attached .cfg file. What is the exact setup?

  1. Get Xiao out of packaging
  2. Setup Seeed studio Board v1.0.0?
  3. Setup Adafruit NRF52 Board v1.4?
  4. Select Board as Seeed BLE Sense or Adafruit Seeed BLE Sense?
  5. Where do I put the cfg?
  6. What additional libraries do I need to install?
  7. Then do I compile and flash?

Am I going down the path wrong here. How can I get this to run?

@Gurmeet_Sidhu

A good place to start is to get the blink sketch working as described here: Getting Started with Xiao nrf52840

Next, you could get an IMU example working as described here: IMU Usage

Ignore the .cfg file. That is an alternate way to flash the firmware. I got tired of hitting the tiny button on the Xiao. The above two links should cover the rest of the questions. At least get you closer.

Iā€™m using the latest Seeed nrf52 board package: 1.1.3

1 Like

Was not able to get 1.1.3 to run because of this: "Seeed nRF52 Boards" update to 1.1.3 causes compile error - #13 by msfujino

Technically if you apply the fix here, you are selecting seeed nrf sense under Adafruit board. Is that something you did as well to get the blink and other sketches to work?

@Gurmeet_Sidhu

I ran into this as well, but I found no other reports of the issue so I thought it was something with my configuration.

It looked like the issue was two missing libraries that were indirectly referenced from the git repository. I fixed it by copying the missing libraries from the git repositories: Seeed nrf52 git repository

I think these were the two libraries I copied over:

  • Adafruit_TinyUSB_Arduino
  • Adafruit_nRFCrypto

Those libs are links in the git repository and the destination directories are empty: C:\Users\XXXX\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.3\libraries

1 Like

Thank you for your outstanding contribution to our products and we hope to add your contribution to the Wiki page to make our product information even better!
Once again, on behalf of the Seeed team, I would like to express our gratitude to you.

3 Likes

How can I get lower power usage when using the board 'Seeed XIAO BLE Sense - nRF52840 (Seeed nRF52 mbed-eables Boards)? I need this version of the board so that I can use Arduino Hardware BLE Serial library to work, but can not get the power below 3.5mA.

Hi All,
We have published a contrbutor wanted program, you can change the wiki contents, accept some assignments or share your thoughts with us. If you are willing to submit your own research and projects,We will offer a range of rewards to our contributors.

1 Like

nudgeWakeUp

hsa anybody use mbed-enabled run the nudgeWakeUp?

I need it. but not working.

  1. canā€™t include <Adafruit_SPIFlash.h>
    has error.
    1.1. so Iā€™cat use this func.
    void QSPIF_sleep(void) {
    flashTransport.begin();
    flashTransport.runCommand(0xB9);
    flashTransport.end();
    }
  2. pinMode(PIN_LSM6DS3TR_C_INT1, INPUT_PULLDOWN_SENSE);

mbed-enabled not defined the INPUT_PULLDOWN_SENSE
I has try ā€˜0x5ā€™ value, canā€™t work.

can help me ?

Hello, please check whether your library have been installed well? If well, you can try INPUT_PULLDOWN to replace it

@daCoder I get ā€œnot declaredā€ for the ā€œINPUT_PULLUP_SENSEā€ define and ā€œsd_power_system_off()ā€ function.

Iā€™ve been scanning the web, trying to include different files, librariesā€¦ Installed libraries and boards, but without luck. Any chance you can guide me towards a solution so I can enable the power off.

I beleive Iā€™m stuck because Iā€™m using the mbed-enabled boards, can this be the cause? Tried swapping board to the non mbed, but that just gave me a ton of new issuesā€¦

Iā€™m working with Seeed Studio XIAO nRF52840 (Sense) board.

Any help would be appriciated!

Hi TaTranky and welcome Here,
I would first try to get the above examples (post#3)to compile and run successfully. then see what power saving you can implement and what tradeoffs you can except.
I will indeed throw you a bone however and save you some time, in the sense of the embed 2.9.1 is the BSP to use in any effort of combinational usage of the sensors and BLE. it works.
You may also want to give these a read up,



Youtube videoā€¦

post anything you need help with , lots of smart folks willing to help here.
HTH
GL :slight_smile: PJ

@TaTranky I havenā€™t used the mbed version. I havenā€™t updated in while, so I updated my configuration from scratch then recompiled and ran the nudgeWakeUp example. I didnā€™t run into any issues.

  • Installed the latest Arduino IDE (2.2.1)
  • Installed the latest Seeed nRF52 Boards (1.1.5)
  • Updated the single out of date library: Adafruit SPIFlash (4.3.0)

I noticed it compiled with the Adafruit SPIFlash 4.3.0, but used the board package version of SdFat instead of the one installed with AdaFruit SPIFlash 4.3.0. Didnā€™t seem to cause an issue. Power measurements were similar to the original post.

Hi @daCoder ,

This post is very helpful thanks, it seems you have had quite a bit of experience with the xiao Sense,

Iā€™m working on a project where iā€™m needing very low power on the device description in the topic below. just wondering what your thoughts are on whether this is a good way to go about solving my project?
https://forum.seeedstudio.com/t/ble-proximity-detection-using-rssi-xiao-nrf52840/273190

thanks,
Ben

Hi, were you ever able to add Bluetooth functionality to the above low power examples. I cannot seem to get BLE libraries to compile with the Adafruit_SPIFlash.h library. thanks

#include <ArduinoBLE.h>

#include <LSM6DS3.h>

#include <Wire.h>

const int buttonPin = 2;  // the number of the pushbutton pin

const int ledPin = 13;    // the number of the LED pin

const int NTC_PIN = A0;

int buttonState = 0;

float temperature = 0.0;

const float BETA = 3950; // should match the Beta Coefficient of the thermistor

const int usbPin = LEDG;

int usbState = 0;

// https://github.com/NordicSemiconductor/bluetooth-numbers-database/blob/master/v1/characteristic_uuids.json

// Pressure 2A6D

// Scientific Temperature Celsius 2A3C

// "Temperature","uuid": "2A6E"

// "Temperature Celsius",  "uuid": "2A1F"

//"Temperature Fahrenheit", "uuid": "2A20"

//"Temperature Measurement uuid": "2A1C"

// "Temperature uuid": "2A1D"

const char* blePeripheralName = "MyBLEDevice";

BLEService customService("2A3C");

BLEStringCharacteristic customCharacteristic("2A3C", BLERead | BLENotify, 1024);

LSM6DS3 myIMU(I2C_MODE, 0x6A); // IMU

#define int1Pin 2

uint8_t interruptCount = 0; // Amount of received interrupts

uint8_t prevInterruptCount = 0; // Interrupt Counter from last loop

void setup() {

  Serial.begin(9600);

  if (!BLE.begin()) {

    Serial.println("Starting BLE failed!");

    while (1);

  }

  BLE.setLocalName(blePeripheralName);

  BLE.setAdvertisedService(customService);

  customService.addCharacteristic(customCharacteristic);

  BLE.addService(customService);

  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");

  if (myIMU.begin() != 0) {

        Serial.println("IMU error");

    } else {

        Serial.println("IMU OK!");

    }

  myIMU.settings.gyroEnabled = 0; // Gyro currently not used, disabled to save power

  setupDoubleTapInterrupt();

  pinMode(int1Pin, INPUT);

  attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);

 

  pinMode(LED_BUILTIN, OUTPUT);// initialize the LED pin as an output:

  pinMode(buttonPin, INPUT_PULLUP);// initialize the pushbutton pin as an input:

  pinMode(LEDR, OUTPUT);

  pinMode(LEDG, OUTPUT);

  pinMode(LEDB, OUTPUT);

  setLedRGB(false, false, true); // set blue led

}

void loop() {

  BLEDevice central = BLE.central();

  temperature = getNTCTemperature();

  usbState = digitalRead(usbPin);

  if (central) {

    Serial.print("Connected to central: ");

    Serial.println(central.address());

    while (central.connected()) {

      buttonState = digitalRead(buttonPin);

      Serial.println(buttonState);

      // Check if digital input is LOW (0)

      if ( buttonState == 0 ) {

        // Send an alert to the connected central device

        customCharacteristic.writeValue("Wire Disconnected!");

        digitalWrite(ledPin, HIGH);

      }

      else

      {

        digitalWrite(ledPin, LOW);

        customCharacteristic.writeValue("Wire Connected");

      }

      delay(1000); // Adjust the delay according to your requirements

    }

    digitalWrite(ledPin, HIGH);

    Serial.print("Disconnected from central: ");

    Serial.println(central.address());

  }

  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 >= 3) {

    // Trigger System OFF after 3 interrupts

    goToPowerOff();

  }

  delay(500);

}

// NTC

float getNTCTemperature()

{

  int analogValue = analogRead(NTC_PIN);

  float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;

  Serial.print("Temperature: ");

  Serial.print(celsius);

  Serial.println(" ā„ƒ");

  return celsius;

}

// -------------------- System ------------------------- //

void goToPowerOff() {

  setLedRGB(false, false, false);

  Serial.println("Going to System OFF");

  setupDoubleTapInterrupt(); // not needed here, if already applied..

  delay(1000); // 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 setupDoubleTapInterrupt() {

  uint8_t error = 0;

  uint8_t dataToWrite = 0;

  // Double Tap Config

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x60); //* Acc = 416Hz (High-Performance mode)// Turn on the accelerometer

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x8E);// INTERRUPTS_ENABLE, SLOPE_FDS// Enable interrupts and tap detection on X, Y, Z-axis

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_THS_6D, 0x85);// Set tap threshold 8C

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT_DUR2, 0x7F);// Set Duration, Quiet and Shock time windows 7F

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x80);// Single & double-tap enabled (SINGLE_DOUBLE_TAP = 1)

  myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x08);// Double-tap interrupt driven to INT1 pin

}

void int1ISR()

{

  interruptCount++;

 ;

}

// -------------------- Utilities ------------------------- //

void setLedRGB(bool red, bool green, bool blue) {

  if (!blue) { digitalWrite(LEDB, HIGH); } else { digitalWrite(LEDB, LOW); }

  if (!green) { digitalWrite(LEDG, HIGH); } else { digitalWrite(LEDG, LOW); }

  if (!red) { digitalWrite(LEDR, HIGH); } else { digitalWrite(LEDR, LOW); }

}

Hi there , Looks Good :wink: :+1:
GL :slight_smile: PJ

1 Like

@aaronfrom My Bluetooth implementations use Zephyr. I havenā€™t gotten around to using Bluetooth with Arduino. Thanks to faizannazir for providing an answer.