Hi! Thanks for testing my code that really helped. I have much more rudimentary method for detecting amps (see photo) but I tweaked my setup and picked apart my code. I think by using daCoders “combination” code for waking up the xiao sense from sleep and adding a delay(10) to my loop i have decreased the amps needing during awake and sleep function (I am now getting ~20-30 microamps during sleep). Again this is with non-mbed boards and using a rechargeable Lithium Cr2020 battery to detect foot steps per minute with the BLE sensor on your shoe. thanks again!
#include <LSM6DS3.h>
#include <nrf52840.h>
#include <Wire.h>
#include <bluefruit.h>
#include <Adafruit_LittleFS.h>
LSM6DS3 myIMU(I2C_MODE, 0x6A); //I2C device address 0x6A
long previousMillisSLEEP = 0; // last time steps checked level was checked, in ms
long currentMillisSLEEP = 0;
long previousMillisSTEPS = 0;
long previousSteps = 0;
long cadence = 0;
long previouscadence = 0;
float accX, accY, accZ, gX, gY, gZ;
int stepCount = 0;
bool UPDATED = false;
long currentMillisSTEPS = 0;
long changeInMilllisSTEPS = 0;
int stepcountforcadenceaverage = 0;
int totalcandenceforaverage = 0;
bool xbool = false;
int countdetect = 0;
const int SMOOTHING_WINDOW_SIZE = 80; // # samples
int _samples[SMOOTHING_WINDOW_SIZE]; // the readings from the analog input
int _curReadIndex = 0; // the index of the current reading
int _sampleTotal = 0; // the running total
int _sampleAvg = 0; // the average
bool CONNECTEDtoble = false;
BLEService RSC = BLEService("1814");
BLECharacteristic RSCcharac = BLECharacteristic("2A53");
void setupAccelerometer()
{
// Start with LSM6DS3 in disabled to save power
myIMU.settings.gyroEnabled = 0;
myIMU.settings.accelEnabled = 0;
myIMU.begin();
/* Values from the application note */
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x60); // Turn on the accelerometer
// ODR_XL = 416 Hz, FS_XL = ±2 g
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x8E); // Enable interrupts and tap detection on X, Y, Z-axis
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_THS_6D, 0x8C); // Set tap threshold
myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT_DUR2, 0x7F); // Set Duration, Quiet and Shock time windows
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
return;
}
void setupWakeUpInterrupt()
{
// Initially the system kept turning back on after system_off. Through trial and error
// added the accelerator power down and that fixed the issue
myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x00); // Power down the accelerometer
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x00); // Disable double-tap interrupt
// Set up the accelerometer for Wake-up interrupt.
// Per the application note, use a two step set up to avoid spurious interrupts
// Set up values are from the application note, and then adjusted for minimum power
myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_DUR, 0x00); // No duration
myIMU.writeRegister(LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x02); // Set wake-up threshold
myIMU.writeRegister(LSM6DS3_ACC_GYRO_TAP_CFG1, 0x80); // Enable interrupts and apply slope filter; latch mode disabled
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x70); // Turn on the accelerometer
// ODR_XL = 833 Hz, FS_XL = ±2 g
delay(4); // Delay time per application note
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0xB0); // ODR_XL = 1.6 Hz
myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL6_G, 0x10); // High-performance operating mode disabled for accelerometer
myIMU.writeRegister(LSM6DS3_ACC_GYRO_MD1_CFG, 0x20); // Wake-up interrupt driven to INT1 pin
// Set up the sense mechanism to generate the DETECT signal to wake from system_off
pinMode(PIN_LSM6DS3TR_C_INT1, INPUT_PULLDOWN_SENSE);
return;
}
void setup()
{
//Serial.begin(9600); // open the serial port at 9600 bps:
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, HIGH);
setupAccelerometer();
// Minimizes power when bluetooth is used
NRF_POWER->DCDCEN = 1;
Bluefruit.begin();
Bluefruit.setName("RUNSTREAM002");
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
setupRSC();
startAdv();
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.autoConnLed(false);
Bluefruit.Advertising.addService(RSC);
// Include Name
Bluefruit.Advertising.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void setupRSC(void)
{
RSC.begin();
RSCcharac.setProperties(CHR_PROPS_NOTIFY);
RSCcharac.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
RSCcharac.setFixedLen(8);
RSCcharac.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
RSCcharac.begin();
}
void connect_callback(uint16_t conn_handle)
{
CONNECTEDtoble = true;
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, HIGH);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_RED, LOW);
CONNECTEDtoble = false;
(void) conn_handle;
(void) reason;
}
void cccd_callback(uint16_t conn_hdl, BLECharacteristic* chr, uint16_t cccd_value)
{
// Check the characteristic this CCCD update is associated with in case
// this handler is used for multiple CCCD records.
if (chr->uuid == RSCcharac.uuid) {
if (chr->notifyEnabled(conn_hdl)) {
//Serial.println("Heart Rate Measurement 'Notify' enabled");
} else {
//Serial.println("Heart Rate Measurement 'Notify' disabled");
}
}
}
void loop()
{
delay(10);
// goToPowerOff();
if(CONNECTEDtoble == true){
previousMillisSLEEP = currentMillisSLEEP;
/////////////////////
accX = myIMU.readFloatAccelX();
accY = myIMU.readFloatAccelY();
accZ = myIMU.readFloatAccelZ();
gX = myIMU.readFloatGyroX();
gY = myIMU.readFloatGyroY();
gZ = myIMU.readFloatGyroZ();
//long magnitudeAcc = ((accX * accX) * (accY * accY) * (accZ * accZ));
//long magnitudeGyro = ((gX * gX) * (gY * gY) * (gZ * gZ));
countdetect++;
// subtract the last reading:
_sampleTotal = _sampleTotal - _samples[_curReadIndex];
// read the sensor value
_samples[_curReadIndex] = gY;
// add the reading to the total:
_sampleTotal = _sampleTotal + _samples[_curReadIndex];
// advance to the next position in the array:
_curReadIndex = _curReadIndex + 1;
// if we're at the end of the array...
if (_curReadIndex >= SMOOTHING_WINDOW_SIZE) {
// ...wrap around to the beginning:
_curReadIndex = 0;
}
// calculate the average:
_sampleAvg = _sampleTotal / SMOOTHING_WINDOW_SIZE;
if (xbool == false && _sampleAvg < -170 )
{
xbool = true;
}
else if (xbool == true && _sampleAvg > -170 )
{
xbool=false;
currentMillisSTEPS = millis();
changeInMilllisSTEPS = currentMillisSTEPS - previousMillisSTEPS;
updateSteps();
previousMillisSTEPS = currentMillisSTEPS;
//Serial.print("A SIGNIFICANT EVENT*******!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
currentMillisSTEPS = millis();
changeInMilllisSTEPS = currentMillisSTEPS - previousMillisSTEPS;
if (changeInMilllisSTEPS > 3000)
{
cadence = 0;
displayData();
previousMillisSTEPS = currentMillisSTEPS;
}
}//end if connected
long currentMillisSLEEP = millis();
// if 1800000ms (3 minutes) have passed, check the steps level:
if ((currentMillisSLEEP - previousMillisSLEEP >= 60000) && CONNECTEDtoble==false) {
goToPowerOff();
}
}
// //https://gitlab.utu.fi/tujupan/DTEK8081_source_codes/-/blob/15585c783735d98663ada2352cd9dc0f8c61e880/examples/ble_peripheral/ble_app_rscs/main.c
void updateSteps() {
// bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
// bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
// bool is_running; /**< True if running, False if walking. */
// uint16_t inst_speed; /**< Instantaneous Speed. */
// uint8_t inst_cadence; /**< Instantaneous Cadence. */
// uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
// uint32_t total_distance;
if (UPDATED == false) {
UPDATED = true;
cadence = 60000 / changeInMilllisSTEPS;
if(cadence>(previouscadence*2) && previouscadence>10){
//do nothing
}else{
if(stepcountforcadenceaverage >= 3)
{
cadence = totalcandenceforaverage/stepcountforcadenceaverage;
stepcountforcadenceaverage = 0;
totalcandenceforaverage = 0;
displayData();
}
else
{
stepcountforcadenceaverage = stepcountforcadenceaverage+1;
totalcandenceforaverage = totalcandenceforaverage +cadence;
}
previouscadence=cadence;
}
}
if (UPDATED == true) {
delay(100);
UPDATED = false;
}
}
void displayData() {
int running;
if (cadence > 70) {
running = 3;
} else if (cadence > 60) {
running = 2;
} else if (cadence > 0) {
running = 1;
} else {
running = 2;
}
uint8_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
//static uint8_t data[4] = {0, 0, 0, 0};
data[0] = 3; //location. of foot. pod
//data[1] = 0; // lowByte(CurrentSpeed);
data[2] = running; //0 nothing 1=walk 2=running
data[3] = cadence; //step count
//data[4] = 0;
data[5] = 0; //always 0
//data[6] = 0;
data[7] = stepCount / 10;
RSCcharac.notify(data, 8); //convert number to hex); // and update the stepcount level characteristic
}
void goToPowerOff()
{
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_RED, HIGH);
// Setup up double tap interrupt to wake back up
setupWakeUpInterrupt();
NRF_POWER->SYSTEMOFF=1; // Execution should not go beyond this
}