I have written a code that generates interrupt on Double Tap on XIAO BLE Sense. If the number of interrupts is a multiple of 5, my XIAO BLE Sense goes to power off and turns back on upon another interrupt. The only issue was, after power off, the interrupt count resets to 0. Hence, I wanted to use the non- volatile flash. However, the count yet again resets to 0? How do I make sure that the count persists after power off?
#include "LSM6DS3.h"
#include "Wire.h"
#include <ArduinoBLE.h>
#include "QSPIFBlockDevice.h"
QSPIFBlockDevice root(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_1, MBED_CONF_QSPIF_QSPI_FREQ);
uint8_t* write_buffer;
uint8_t* read_buffer;
uint64_t sector_size_at_address_0 = 4096; //root.get_erase_size(0)
LSM6DS3 myIMU(I2C_MODE, 0x6A);
#define int1Pin PIN_LSM6DS3TR_C_INT1
uint8_t interruptCount;
uint8_t prevInterruptCount = 0;
char output[] = "";
// BLE service and characteristic UUIDs
const char* deviceServiceUuid = "xxxxx";
const char* deviceServiceCharacteristicUuid = "xxxxx";
BLEService service(deviceServiceUuid); // Custom service UUID
BLEStringCharacteristic characteristic(deviceServiceCharacteristicUuid, BLERead | BLENotify, 100);
String new_value = "";
//------------------------ Functions initialization ------------------------//
void setLedRGB(bool red, bool green, bool blue);
void goToPowerOff();
void setupDoubleTapInterrupt();
void int1ISR();
void setup() {
Serial.begin(9600);
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
setLedRGB(false, true, false); // set green led
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(); //interrupt on double tap set up
NRF_POWER->DCDCEN = 1; // Minimizes power when bluetooth is used
pinMode(int1Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);
Serial.println("init the spi flash...");
int ret = root.init();
if(ret) {
Serial.print("init error. err code=");
Serial.println(ret);
}
root.erase(0, sector_size_at_address_0);
write_buffer = (uint8_t*)malloc(sector_size_at_address_0);
memset(write_buffer, 0x00, sector_size_at_address_0);
root.program(write_buffer, 0, sector_size_at_address_0);
free(write_buffer);
read_buffer = (uint8_t*)malloc(sector_size_at_address_0);
memset(read_buffer, 0x00, sector_size_at_address_0);
root.read(read_buffer, 0, sector_size_at_address_0);
interruptCount = read_buffer[0];
free(read_buffer);
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
BLE.setLocalName("XIAO_BLE_Sense");
BLE.setAdvertisedService(service);
service.addCharacteristic(characteristic);
BLE.addService(service);
BLE.advertise();
Serial.println("BLE peripheral advertising...");
}
void loop() {
BLEDevice central = BLE.central();
Serial.print("\Iterrupt Counter: ");
Serial.println(interruptCount);
if (interruptCount > prevInterruptCount) {
Serial.println("\Interrupt received!");
Serial.print("Previous- ");
Serial.print(prevInterruptCount);
Serial.print("New- ");
Serial.println(interruptCount);
setLedRGB(true, false, false); // set red for interrupt
delay(200);
if (((interruptCount%5)==0)&&(interruptCount>0)) {
goToPowerOff();
}
}
if (!central.connected()){
setLedRGB(false, true, false); //set led green to indicate power on
}
else {
setLedRGB(false, false, true); // set led to blue to indicate BLE connection
itoa(interruptCount, output, 10);
characteristic.writeValue(output);
delay(100);
}
prevInterruptCount = interruptCount;
delay(500);
}
// -------------------- 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); }
}
// -------------------- System ------------------------- //
void goToPowerOff() {
setLedRGB(false, false, false);
// Read current interrupt count from flash
size_t data_size = sizeof(interruptCount);
// Check if data size fits within erase size
if (data_size <= sector_size_at_address_0) {
// Write interrupt count to flash
write_buffer = (uint8_t*)malloc(sector_size_at_address_0);
memset(write_buffer, 0x00, sector_size_at_address_0);
write_buffer[0] = interruptCount;
root.erase(0, sector_size_at_address_0); // Erase everything, else incorrect response?
root.program(write_buffer, 0, sector_size_at_address_0);
free(write_buffer);
// Read interrupt count from flash
read_buffer = (uint8_t*)malloc(sector_size_at_address_0);
memset(read_buffer, 0x00, sector_size_at_address_0);
root.read(read_buffer, 0, sector_size_at_address_0);
uint8_t storedCount = read_buffer[0];
free(read_buffer);
Serial.print("Interrupt stored at power off- ");
Serial.println(storedCount);
} else {
Serial.println("ERROR: Data size too large for erase sector!");
}
Serial.println("Going to System OFF");
delay(100); // Wait for settings to apply
NRF_POWER->SYSTEMOFF = 1;
}
// -------------------- Interrupts ------------------------- //
void setupDoubleTapInterrupt() {
// Double Tap Config
// High-performance seems to be needed
//myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x40); //ODR - 104 Hz, high-performance mode
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x60);
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x8E);// INTERRUPTS_ENABLE, SLOPE_FDS
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_THS_6D, 0x8C);
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT_DUR2, 0x7F);
myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x80);
myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x08);
}
void int1ISR()
{
interruptCount++;
}