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);
}