Hello everyone,
My name is Paul and I am currently working on a project, where i want to measure accelerations while toothbrushing.
The device i built consists of a ESP32 connected to an IMU(Lsm6ds3) and RTC(DS3231) connected via I2C and a micro sd adapter connected via SPI. The system is powered by a CR123a 3V lithium battery.
The ESP32 goes into deepsleep between the measurements to save battery. To wake up the ESP32 i configured the IMU so that if motion exceeds a certain value it generates an interrupt to wake the ESP up and start measuring.
To get a sufficient sampling frequency i am using a FIFO buffer on the IMU so i only need to write the Data to the SD card in big chunks.
Generally everything works fine but when testing the device i run into some problems time to time..
Sometimes everything works as a charm and i get a txt with the current boot number as a name. Thats how i already collected toothbrushing data over 2 weeks ![]()
But then most of the time it stops wokring at some point. For troubleshooting i am currently testing everything with usb connection and looking at the SD data afterwards.
First of all here is my code (if something is not clear please let me know!)
#include "SparkFunLSM6DS3.h"
#include "Wire.h"
#include "SPI.h"
#include "FS.h"
#include "SD.h"
#include "WiFi.h"
#include "RTClib.h"
#include <Preferences.h>
Preferences preferences;
RTC_DS3231 rtc;
LSM6DS3 myIMU(I2C_MODE, 0x6B);
RTC_DATA_ATTR int booter = 0;
RTC_DATA_ATTR int reseter = 0;
char fileName[10];
uint8_t int1Status = 0;
uint8_t saver = 0;
void setup( void ) {
//Settings for the IMU:
myIMU.settings.gyroEnabled = 1; //Can be 0 or 1
myIMU.settings.gyroRange = 2000; //Max deg/s. Can be: 125, 245, 500, 1000, 2000
myIMU.settings.gyroSampleRate = 833; //Hz. Can be: 13, 26, 52, 104, 208, 416, 833, 1666
myIMU.settings.gyroBandWidth = 200; //Hz. Can be: 50, 100, 200, 400;
myIMU.settings.gyroFifoEnabled = 1; //Set to include gyro in FIFO
myIMU.settings.gyroFifoDecimation = 1; //set 1 for on /1
myIMU.settings.accelEnabled = 1;
myIMU.settings.accelRange = 16; //Max G force readable. Can be: 2, 4, 8, 16
myIMU.settings.accelSampleRate = 833; //Hz. Can be: 13, 26, 52, 104, 208, 416, 833, 1666, 3332, 6664, 13330
myIMU.settings.accelBandWidth = 200; //Hz. Can be: 50, 100, 200, 400;
myIMU.settings.accelFifoEnabled = 1; //Set to include accelerometer in the FIFO
myIMU.settings.accelFifoDecimation = 1; //set 1 for on /1
myIMU.settings.tempEnabled = 1;
//Non-basic mode settings
myIMU.settings.commMode = 1;
//FIFO control settings
myIMU.settings.fifoThreshold = 100; //Can be 0 to 4096 (16 bit bytes)
myIMU.settings.fifoSampleRate = 200; //Hz. Can be: 10, 25, 50, 100, 200, 400, 800, 1600, 3300, 6600
myIMU.settings.fifoModeWord = 6; //FIFO mode.
// //Error accumulation variable
uint8_t errorAccumulator = 0;
uint16_t errorsAndWarnings = 0;
uint8_t dataToWrite = 0; //Temporary variable
Serial.begin(115200); // start serial for output
delay(100); //relax...
Serial.println("ESP came out of reset.\n");
//store the number of boots in Flash memory and assign its value to a volatile integer "booter".
//The boot counter "reseter" is a seperate volatile counter, that goes to 0 once the ESP32 looses power or is resetet
preferences.begin("my-app", false);
unsigned int counter = preferences.getUInt("counter", 0);
counter++;
booter = counter;
Serial.printf("Current counter value: %u\n", counter);
Serial.printf("Current booter value: %u\n", booter);
Serial.printf("Current reseter value: %u\n", reseter);
preferences.putUInt("counter", counter); // Store the counter to the Preferences
preferences.end(); // Close the Preferences
//Start the RTC and programm the time of code upload to it if it is the first boot of the ESP32
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
}
if(booter == 1 ){
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
setupSDCard();
setupIMU();
}
void setupSDCard(){
if(!SD.begin()){
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
return;
}
}
void setupIMU(){
Wire.begin();
Wire.setClock(800000L);
if( myIMU.begin() != 0 ){
Serial.println("Problem starting the sensor");
Serial.println(myIMU.begin());
}
else{
Serial.println("Sensor started.");
}
uint8_t dataToWrite = 0; //Temporary variable
Serial.println("Configuring FIFO");
myIMU.fifoBegin();
Serial.println("fifo Begin done");
Serial.println("Clearing out the FIFO...");
myIMU.fifoClear();
Serial.println("Fifo clear");
}
void int1ISR()
{
int1Status++;
}
void saveSD() //if button is pushed saver is updated
{
saver++;
}
void loop(){
float temp; //This is to hold read data
uint16_t tempUnsigned;
//get the current Date
DateTime now = rtc.now();
int day=now.day();int month=now.month(); int year=now.year();int hour=now.hour();int minute=now.minute();int second=now.second();
//create a txt with the bootcount number as name
snprintf(fileName, 9, "/%03d.txt", reseter);
File file = SD.open(fileName ,FILE_APPEND);
//print the boot number and number of resets in the file for troubleshooting
file.print(reseter);file.print(". Reset_boot, ");file.print(booter);file.print(". Boot:\n");
file.print("Recording started at:\n");
file.print(day);file.print(".");file.print(month);file.print(".");file.print(year);file.print(" - ");
file.print(hour);file.print(":");file.print(minute);file.print(","); file.print(second);file.print("\n ");
file.print("Time in millis;Gx;Gy;Gz;X;Y;Z\n");
attachInterrupt(digitalPinToInterrupt(15), saveSD, RISING); // interrupt to stop the programm later to allow the SD beeing pulled after file is closed
File file = SD.open(fileName ,FILE_APPEND); // open the txt
int milli = millis();
while(millis()-milli <5000){ //set recording time
while( ( myIMU.fifoGetStatus() & 0x8000 ) == 0 ) { //let the FIFO bee filled to threshold
};
while( ( myIMU.fifoGetStatus() & 0x1000 ) == 0 ) { //as long as fifo is not emptied loop and write the IMU data(3Gyro & 3Axis) from FIFO
file.print(millis());file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");
temp = myIMU.calcAccel(myIMU.fifoRead());
file.print(temp);file.print(";");file.print("\n ");
}
tempUnsigned = myIMU.fifoGetStatus();
Serial.print("Outside of Fifo");Serial.print("\n");
if(saver>0){ //if button is pushed the file is closed and the SD stopped so it can be removed without data loss
file.print("The recording stopped save!\n");
Serial.println("stopping logging");
file.close();
delay(500);
SD.end();
Serial.println("SD out");
delay(1000);
esp_deep_sleep_start();
}
}
myIMU.fifoClear(); // clear out and stop the FIFO
myIMU.fifoEnd();
file.print("recording stoppedt");
file.print("\n");
file.close(); //close the file
detachInterrupt(digitalPinToInterrupt(15)); //remove the Interrupt for the SD removal before deep sleeping
Serial.println("Going to sleep");
delay(500);
SD.end(); //end the SD card to reduce current consumption
myIMU.writeRegister( LSM6DS3_ACC_GYRO_TAP_CFG1, 0x00 ); //Settings for the IMU to generate interrupt if motion is over threshold
myIMU.writeRegister( LSM6DS3_ACC_GYRO_WAKE_UP_DUR, 0x00 );
myIMU.writeRegister( LSM6DS3_ACC_GYRO_WAKE_UP_THS, 0x01 );
myIMU.writeRegister( LSM6DS3_ACC_GYRO_MD1_CFG, 0x20 );
myIMU.writeRegister( LSM6DS3_ACC_GYRO_CTRL2_G, 0x00 );
attachInterrupt(digitalPinToInterrupt(13), int1ISR, RISING); //Set pin 13 to detect interrupt from IMU
reseter++; //update volatile counter
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13,1); //allow external wake up and go to sleep
esp_deep_sleep_start();
}
What i already found out is, that sometimes within the FIFO loop the Programm gets stuck for some time(maybe 5-10sek) but continues afterwards and restarts again. If this happens there is no data written to the SD anymore, even if i can see the system booting up and running several times in the monitor..
I know that writing to SD can cause quite some pain and i looked some probems up, but couldnt find something, that would explain this behaviour. If the System starts booting up again it should at least create new files again or?
I am thankfull for any kind of help or critisism.
