XIAO BLE Sense in deep sleep mode

We also failing to get into the deep sleep, would be nice get some improvement soon. otherwise it will be quite hard to use XIAO BLE sense for wearable projects.

hi,
I tried to run your code with my xiao ble nrf52840 sense and it indeed going to sleep after 5 double tabs BUT it doesn’t wake up on the 6. I tried everything and it just staying in deep sleep!
I am new to the iot world, maybe I am doing something wrong :frowning_face:

here what i did:

#include "LSM6DS3.h"
#include "Wire.h"
LSM6DS3 myIMU(I2C_MODE, 0x6A); // IMU
#define int1Pin PIN_LSM6DS3TR_C_INT1

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED

uint8_t interruptCount = 0; // Amount of received interrupts
uint8_t prevInterruptCount = 0; // Interrupt Counter from last loop

void setup() {
  Serial.begin(9600);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb
  pinMode(ledPin, OUTPUT); // use the LED as an output
  
  Serial.println("Hello, I am awake!");
  myIMU.settings.gyroEnabled = 0; // Gyro currently not used, disabled to save power
  if (myIMU.begin() != 0) {
    Serial.println("IMU error");
  } else {
    Serial.println("IMU OK!");
  }

  setupDoubleTapInterrupt();

  pinMode(int1Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);
}

void loop() {
  setLED(false);
  Serial.print("Interrupt Counter: ");
  Serial.println(interruptCount);

  if (interruptCount > prevInterruptCount) {
    Serial.println("Interrupt received!");
  }
  prevInterruptCount = interruptCount;

  if (interruptCount >= 5) {
    // Trigger System OFF after 5 interrupts
    goToPowerOff();
  }

  delay(500);
}

void goToPowerOff() {
  Serial.println("Going to System OFF");
  setLED(true);
  setupDoubleTapInterrupt();
  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;
}

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
  // ODR_XL = 416 Hz, FS_XL = 2g
  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++;
}

  void setLED(bool on)
  {
  // data = 1 -> LED = On
  // data = 0 -> LED = Off
  digitalWrite(LED_BUILTIN, on ? HIGH : LOW);
  }

Try defining all variables that may be modified in an interrupt to „volatile“.

changed BUT still the same result :frowning:

you forgot the Delay.
;-p

1 Like

So this was bugging me as to why it worked and for other it doesn’t
I reran a cut and paste of your original code posted and ONLY added the delay;
didn’t work here either so, I got my original code and it DIDN’T work either. WTH? :flushed:

Went back , loaded 2.9.0

Using board 'xiaonRF52840' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\Seeeduino\hardware\mbed\2.9.0
Using core 'arduino' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\Seeeduino\hardware\mbed\2.9.0

Good news YOUR code worked with delay to put to sleep and to wakeup AOK.
HTH
GL :slight_smile:

#include "LSM6DS3.h"
#include "Wire.h"
LSM6DS3 myIMU(I2C_MODE, 0x6A); // IMU
#define int1Pin PIN_LSM6DS3TR_C_INT1

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED

uint8_t interruptCount = 0; // Amount of received interrupts
uint8_t prevInterruptCount = 0; // Interrupt Counter from last loop

void setup() {
  Serial.begin(9600);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb
  pinMode(ledPin, OUTPUT); // use the LED as an output
  
  Serial.println("Hello, I am awake!");
  myIMU.settings.gyroEnabled = 0; // Gyro currently not used, disabled to save power
  if (myIMU.begin() != 0) {
    Serial.println("IMU error");
  } else {
    Serial.println("IMU OK!");
  }

  setupDoubleTapInterrupt();

  pinMode(int1Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);
}

void loop() {
  setLED(false);
  Serial.print("Interrupt Counter: ");
  Serial.println(interruptCount);

  if (interruptCount > prevInterruptCount) {
    Serial.println("Interrupt received!");
  }
  prevInterruptCount = interruptCount;

  if (interruptCount >= 5) {
    // Trigger System OFF after 5 interrupts
    goToPowerOff();
  }

  delay(500);
}

void goToPowerOff() {
  Serial.println("Going to System OFF");
  setLED(true);
  setupDoubleTapInterrupt();
  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);
  delay(2000);// Trigger System OFF
  NRF_POWER->SYSTEMOFF = 1;
}

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
  // ODR_XL = 416 Hz, FS_XL = 2g
  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++;
}

  void setLED(bool on)
  {
  // data = 1 -> LED = On
  // data = 0 -> LED = Off
  digitalWrite(LED_BUILTIN, on ? HIGH : LOW);
  }

Anyone know why in “deep sleep” and running the code above why is the Charge LED lit?
TIA…When it’s “asleep” :stuck_out_tongue_closed_eyes:




Here are the PPKII graphs for the code above running You can see the Power ON, waiting for a double tap, Three Taps & then SLeep.
HTH
GL :slight_smile:

this thing is GREAT!



Highly recommend the $Hondo :money_mouth_face:… My code on my prototype has gone from 6hrs :joy:, as-is on an 450 Mah 3.85 Vdc battery with some adjustments went to 11 hrs, :upside_down_face: I was happy …Now 72 hrs. :sunglasses: with allot more to go…

@Citric @fe7565 @PJ_Glasso a lot of a good info about mbed vs adafruit board firmwares and sleep mode.

I was able to find examples how to do timer-based interrupts for mbed firmware, but not for the Adafruit/Bluefruit one. Do you know if timer-based interrupts are supported/working on non-mbed firmware?

Also, is it possible to use timer-based interrupts to wake device using either mbed or Bluefruit firmware?

so if I want to “power down” the XIAO and all connected peripherals and wake it up again with a button, is this possible or not? What’s the lowest current that can be achieved like this?
I have once done this with an Adafruit nrf52840 board and got a battery usage when powered down way less than its self-discharge

So actually no one, not even Seeed, knows how to power this thing down and up again just like basically every portable eletronic device nowadays is powered up / down, meaning with the push (long press?) of a button?
Is this really true?

1 Like

Have You tried this solution ?

https://github.com/khoih-prog/NRF52_TimerInterrupt

… should be good for “adafruit-bluefruit version”
I plan to check this in a few days.

I also assume that using

...
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);  
// or  sd_power_mode_set(NRF_POWER_MODE_CONSTLAT);  
sd_app_evt_wait();  // puts the nrf52 to sleep when there is nothing to do
...

timer interrupts described above should wake up my Xiao

… the same sketch is not working with XIAO ? have You tried ?

I plan to check this with my Xiao nrf52840 : bluefruit/softdevice and just sd_power_off , wake up by reset button. Hope it will run :slight_smile:

Yes, I looked at it. I also ended up not needed to wake up the board on a timer and using a pin interrupt instead which seems to work.

But the following note makes it not suitable for my needs, as I need to talk to BLE and Serial is needed for debugging. I was hoping it would have a “deferred” mode similar to regular Arduino pin interrupts, but it doesn’t.

For the time being I ended up with SoftwareTimer which seem to be part of the standard library for XIAO. It is also somewhat low level and also doesn’t have “deferred” option for callback. But it supports one-time timers and BLE and Serial seems to work in the callback.

1 Like

I prepared a sketch with SoftwareTimer and used sd_app_evt_wait() function to put my XIAO to LOWPWR mode
How can I check if this is working ?
The sketch is compiling, it is running …but I do not have a proper power meter to check if this sketch really make my XIAO running at low power.
this is my sketch

#include <Arduino.h>
#include <Adafruit_TinyUSB.h> // for Serial
#include <bluefruit.h>

/* SoftwareTimer is a helper class that uses FreeRTOS software timer
 * to invoke callback. Its periodic timing is flexible as opposed to
 * hardware timer and cannot be faster than rtos's tick which is configured
 * at  ~1 ms interval.
 *
 * If you need an strict interval timing, or faster frequency, check out
 * the hw_systick sketch example that use hardware systick timer.
 *
 * http://www.freertos.org/RTOS-software-timer.html
 */
SoftwareTimer blinkTimer;

void setup()
{
  Serial.begin(115200);
  Bluefruit.begin();          // Sleep functions need the softdevice to be active.
  sd_power_mode_set(NRF_POWER_MODE_LOWPWR); 
  pinMode(LED_BUILTIN, OUTPUT);  // initialize digital pin LED_BUILTIN as an output.
  blinkTimer.begin(1000, blink_timer_callback);  // Configure the timer with 1000 ms interval, with our callback
  blinkTimer.start();  // Start the timer
}

void loop()
{
  // do nothing here
}

/**
 * Software Timer callback is invoked via a built-in FreeRTOS thread with
 * minimal stack size. Therefore it should be as simple as possible. If
 * a periodically heavy task is needed, please use Scheduler.startLoop() to
 * create a dedicated task for it.
 *
 * More information http://www.freertos.org/RTOS-software-timer.html
 */
void blink_timer_callback(TimerHandle_t xTimerID)
{
  // freeRTOS timer ID, ignored if not used
  (void) xTimerID;
  Serial.println("timer callback");
  digitalToggle(LED_BUILTIN);
  sd_app_evt_wait(); // puts the nrf52 to sleep when there is nothing to do
}

Thanks for help.

1 Like

?? strange serial behaviour
I added one more line to the code above … just suspend loop
and now serial monitor is printing every 3 seconds. It looks like the XIAO is firing the softwaretimer every 1 second but serial is sending output every 3 seconds. Strange !?

I still can not check if xiao is really “system-on sleeping” (and consuming less power) hence I don’t have precise meter. If not - I will try tu use hardware timer.
If someone could check this out …would be great :slight_smile:

#include <Arduino.h>
#include <Adafruit_TinyUSB.h> // for Serial
#include <bluefruit.h>

/* SoftwareTimer is a helper class that uses FreeRTOS software timer
 * to invoke callback. Its periodic timing is flexible as opposed to
 * hardware timer and cannot be faster than rtos's tick which is configured
 * at  ~1 ms interval.
 *
 * If you need an strict interval timing, or faster frequency, check out
 * the hw_systick sketch example that use hardware systick timer.
 *
 * http://www.freertos.org/RTOS-software-timer.html
 */
SoftwareTimer blinkTimer;

void setup()
{
  Serial.begin(115200);
  Bluefruit.begin();          // Sleep functions need the softdevice to be active.
  sd_power_mode_set(NRF_POWER_MODE_LOWPWR); 
  pinMode(LED_BUILTIN, OUTPUT);  // initialize digital pin LED_BUILTIN as an output.
  blinkTimer.begin(1000, blink_timer_callback);  // Configure the timer with 1000 ms interval, with our callback
  blinkTimer.start();  // Start the timer

  suspendLoop(); // Suspend Loop() to save power, since we didn't have any code there
}

void loop()
{
  // do nothing here , loop is already suspended, CPU will not run loop() at all
}

/**
 * Software Timer callback is invoked via a built-in FreeRTOS thread with
 * minimal stack size. Therefore it should be as simple as possible. If
 * a periodically heavy task is needed, please use Scheduler.startLoop() to
 * create a dedicated task for it.
 *
 * More information http://www.freertos.org/RTOS-software-timer.html
 */
void blink_timer_callback(TimerHandle_t xTimerID)
{
  // freeRTOS timer ID, ignored if not used
  (void) xTimerID;
  Serial.print("timer callback at - ");
  Serial.println(millis());
  digitalToggle(LED_BUILTIN);
  sd_app_evt_wait(); // puts the nrf52 to sleep when there is nothing to do
}

serial monitor output

...
13:40:50.928 -> timer callback at - 222418
13:40:50.928 -> timer callback at - 223418
13:40:50.928 -> timer callback at - 224418
13:40:53.951 -> timer callback at - 225418
13:40:53.951 -> timer callback at - 226418
13:40:53.951 -> timer callback at - 227418
13:40:56.952 -> timer callback at - 228418
13:40:56.952 -> timer callback at - 229418
13:40:56.952 -> timer callback at - 230418
...

I’ll try it with the PPK2…standby.
:slight_smile: GL

2 Likes

power up

#define BUTTONPIN 4
...
nrf_gpio_cfg_sense_input(g_ADigitalPinMap[BUTTONPIN], NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); //wake from deep sleep

power down

sd_power_system_off();

However, the DCDC providing 3v3 to my peripherals remains powered on. Is there a way to shut it down?

How low did you go in current consumption with Xiao Ble Sense? 100uA is too high for me.

Can you share the code for sleep/wakeup with accelerometer on Xiao Ble Sense? Thanks

Can you please share full code? I want to wakeup Ble Sense on accelerometer interrupt.