Light / Deep Sleep Current Comparison of XIAO_MG24 and XIAO_nRF52840

Yeah I didn’t do a great job cherry picking. I’ve tested this and it works. This is interesting, in this more contrived example the battery usage is actually higher. My multimeter is reading over 5mA when in deep sleep!

#include <ArduinoLowPower.h>
#include <EEPROM.h>
#include <LSM6DS3.h>

LSM6DS3 myIMU(I2C_MODE, 0x6A);

#define SLEEP_TIMEOUT 8000
#define SLEEP_DURATION 2000 // 2 sec
#define WAKE_STATE FALLING
#define WAKE_UP_BTN PA5
#define MINIMUM_TILT 9

// on board Flush SPI_1 pins
#define CS1 PA6   // (21)
#define CLK1 PA0  // (17), D17   
#define MOSI1 PB0 // (15), D15
#define MISO1 PB1 // (16), D16

// on board peripherals pins
#define IMU_EN PD5  // (19)
#define MIC_EN PC8  // (22)
#define VBAT_EN PD3 // (25)
#define RFSW_EN PB5 // (27)

// Flash commands
#define READ_DATA 0x03
#define WRITE_ENABLE 0x06
#define PAGE_PROGRAM 0x02
#define SECTOR_ERASE 0x20

uint32_t cause;
unsigned long startTimeoutTime = 0;

const int eeAddress = 0;
struct SavedState {
  int asleep;
  int baseAngleZ;
};

SavedState defaultState = {
  1,    // asleep
  90,   // baseAngleZ
};

SavedState appState;

//-----------------------------------------------------------------------------

// Flash functions
void sendSPI(byte data) {
  for (int i = 0; i < 8; i++) {
    digitalWrite(MOSI1, data & 0x80);
    data <<= 1;
    digitalWrite(CLK1, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLK1, LOW);
    delayMicroseconds(1);
  }
}

void writeEnable() {
  digitalWrite(CS1, LOW);
  sendSPI(WRITE_ENABLE);
  digitalWrite(CS1, HIGH);
}

//-----------------------------------------------------------------------------

void setup() {
  cause = GPIO_EM4GetPinWakeupCause();

  // on board flash pins
  pinMode(CS1, OUTPUT);
  pinMode(CLK1, OUTPUT);
  pinMode(MOSI1, OUTPUT);
  pinMode(MISO1, INPUT);
  digitalWrite(CS1, HIGH); 

  // on board peripherals OFF
  pinMode(IMU_EN, OUTPUT);
  pinMode(MIC_EN, OUTPUT);
  pinMode(VBAT_EN, OUTPUT);
  pinMode(RFSW_EN, OUTPUT);
  // digitalWrite(IMU_EN, LOW);
  digitalWrite(MIC_EN, LOW);   // MIC Power OFF
  digitalWrite(VBAT_EN, LOW);  // VBAT Power OFF
  digitalWrite(RFSW_EN, LOW);  // RFSW Power OFF

  myIMU.settings.gyroEnabled = 0;
  myIMU.settings.tempEnabled = 0;
  myIMU.settings.accelSampleRate = 208;
  myIMU.settings.accelFifoEnabled = 1;
  if (myIMU.begin() != 0) {
      // Serial.println("Device error");
  }

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(WAKE_UP_BTN, INPUT_PULLUP);

  EEPROM.get(eeAddress, appState);
  if (appState.baseAngleZ < 0) appState = defaultState;
}

void loop() {
  if (appState.asleep == 1) {
    // if the wake up cause was from the WAKE_UP_BTN pin, wake up and stay awake
    if (cause & GPIO_IEN_EM4WUIEN0) {
      wakeUp();
    // else, go back to sleep
    } else {
      enterStandbySleep();
    }
  }

  const float baseX = myIMU.readFloatAccelX();
  const float baseY = myIMU.readFloatAccelY();
  const float baseZ = myIMU.readFloatAccelZ();
  const int angleZ = atan2(baseZ, sqrt(baseX * baseX + baseY * baseY)) * 180 / PI;
  if (angleZ < appState.baseAngleZ - MINIMUM_TILT) {
    // if tilted, it should stay awake
    wakeUp();
  }

  digitalWrite(LED_BUILTIN, LOW); // LED on

  // wait 8 seconds before going to sleep
  if (startTimeoutTime > 0 && ((millis() - startTimeoutTime) > SLEEP_TIMEOUT)) {
    startTimeoutTime = 0;
    enterStandbySleep();
  }
}

void wakeUp() {
  startTimeoutTime = millis();
  appState.asleep = 0;

  // this stuff is commented out because I'm not sure if this is right or even helpful
  // digitalWrite(IMU_EN, HIGH); // IMU Power ON
  
  // Flash power up
  // digitalWrite(CS1, LOW);
  // sendSPI(0xAB);
  // digitalWrite(CS1, HIGH);
  // delayMicroseconds(30);
}

void enterStandbySleep() {
  // digitalWrite(IMU_EN, LOW); // IMU Power OFF
  digitalWrite(LED_BUILTIN, HIGH); // LED off
  appState.asleep = 1;
  EEPROM.put(eeAddress, appState);
  delay(10);

  // Flash Deep Power Down
  // writeEnable();
  // digitalWrite(CS1, LOW);
  // sendSPI(0xB9);
  // digitalWrite(CS1, HIGH);
  // delay(1);

  LowPower.attachInterruptWakeup(WAKE_UP_BTN, nullptr, WAKE_STATE);
  LowPower.deepSleep(SLEEP_DURATION);
}