SD Code on esp32 - I'm not sure what it means? Can anyone help please?

HI,

I've recently improved the write speed using a nano and I'd like to try the same thing on an esp32 I have. Unfortunately it's not a straight swap and I've found out some understanding of how the esp32 works has been needed.

All I'm trying to do is write accelerometer data to the SD card. To test it I wrote a little state machine using the nano, then tried the same thing on the esp32. Firstly I don't seem to be able to use Sdfat (that I know of, which I'm happy with for now). Secondly after looking at the SD_Test example I have to include a library called FS.h, which from what I understand is a filing system library. I've ended up completely confusing myself and not having a clue what is going on any more.

I really don't get what's going on in this part to be honest and what the arguments mean.

void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

After looking at some further examples online I noticed people weren't using the FS.h at all and just writing the code as you would for the Uno/Nano etc.

I gave it a go but for some reason the timer doesn't seem to be working on the esp32 version but there is not an issue on the nano version of the code.

So I it basically loops in Case 1 and never makes to to Case 2 to close the file.

I'd appreciate any help with this one as I just don't get it. It might just be that I've been looking at it too long. I feel like it's something obvious but just can't see it.

Thank you

Nano Code with SdFat.h, works fine

#include <Wire.h>
#include "SdFat.h"
#include "RTClib.h"
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>

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

// I2C
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

//SD Card
SdFat SD;
File dataFile;
const uint8_t SD_CHIP_SELECT = 10;

//SD Filename
char fileName[25];

//RTC2321
RTC_DS3231 rtc;
char DateAndTime[20];

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

//Millis Setup
unsigned long currentTime = 0;
unsigned long previousTime = 0;
unsigned long accelTime = 0;
const unsigned long sampleRate = 10;
const unsigned long recordPeriod = 60000;
const unsigned long timeStamp = 1000; //Stamp every 1 second

char accelX[7];
char accelY[7];
char accelZ[7];
char accelData[28];

int recordAccel = 0;

//=====================================================================

void setup(void) {

  Serial.begin(115200);

  //LIS3DH Accelerometer
  lis.begin(0x18);
  lis.setRange(LIS3DH_RANGE_4_G);   // 2, 4, 8 or 16 G!

  //RTC
  rtc.begin(); //Start RCT

  //SD Card
  SD.begin();
  SdFile::dateTimeCallback(dateTime); //timestamp file

}

//=====================================================================

void loop() {

  SM();

}

//=====================================================================


void SM() {

  switch (recordAccel) {

    case 0: //Open SD Card

      openCard();

      recordAccel = 1;

      break;


    case 1: //Record Data

      Accel();
      currentTime = millis();

      if (currentTime >= recordPeriod) {

        recordAccel = 2;

      }

      break;

    case 2: //Close SD card

      closeCard();

      break;
  }
}

void openCard() {

  getFileName();
  dataFile = SD.open(fileName, FILE_WRITE);

}

void closeCard() {

  dataFile.close();

}


void Accel() {

  sensors_event_t event;
  lis.getEvent(&event);

  dtostrf(event.acceleration.x, 5, 3, accelX);
  dtostrf(event.acceleration.y, 5, 3, accelY);
  dtostrf(event.acceleration.z, 5, 3, accelZ);

  sprintf(accelData, "%s,%s,%s", accelX, accelY, accelZ);

  if (dataFile) {

    //if (currentTime >= accelTime + sampleRate) {

    dataFile.println(accelData);

    //accelTime = currentTime;

    if (currentTime - previousTime >= timeStamp) {

      DateTime now = rtc.now();
      sprintf(DateAndTime, ",%02d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());

      dataFile.print(accelData);
      dataFile.println(DateAndTime);

      previousTime = currentTime;
    }
  }
}
//}

//=======================================================================

void getFileName() {

  DateTime now = rtc.now();
  sprintf(fileName, "Accel_%02d%02d%02d_%02d%02d.csv", now.year(), now.month(), now.day(), now.hour(), now.minute());
}

//=======================================================================

void dateTime(uint16_t* date, uint16_t* time) {
  //used for callback function for file timestamp

  DateTime now = rtc.now();

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(now.year(), now.month(), now.day());

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

Esp32 code with SD.h, not working, making me feel a little crazy. You'll notice the offending append function commented out because I just didn't get what was going on can changed it all to FILE_WRITE.

/*
   Connect the SD card to the following pins:

   SD Card | ESP32
      D2       -
      D3       SS
      CMD      MOSI
      VSS      GND
      VDD      3.3V
      CLK      SCK
      VSS      GND
      D0       MISO
      D1       -
*/
#include <Wire.h>
//#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "RTClib.h"
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>


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

// I2C
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

//SD Card
File dataFile;
//File file;
const uint8_t SD_CHIP_SELECT = 5;

//SD Filename
char fileName[25];

//RTC2321
RTC_DS3231 rtc;
char DateAndTime[20];

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

//Millis Setup
unsigned long currentTime = 0;
unsigned long previousTime = 0;
unsigned long accelTime = 0;
const unsigned long sampleRate = 10;
const unsigned long recordPeriod = 5000;
const unsigned long timeStamp = 1000; //Stamp every 1 second

char accelX[7];
char accelY[7];
char accelZ[7];
char accelData[28];

int recordAccel = 0;

//=====================================================================

void setup() {

  Serial.begin(115200);

  //LIS3DH Accelerometer
  lis.begin(0x18);
  lis.setRange(LIS3DH_RANGE_4_G);   // 2, 4, 8 or 16 G!

  //RTC
  rtc.begin(); //Start RCT
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  //SD Card
  SD.begin();


}

//=======================================================================

void loop() {

  SM();

}

//=======================================================================

void SM() {

  switch (recordAccel) {

    case 0: //Open SD Card

      openCard();

      currentTime = (esp_timer_get_time()/1000);

      recordAccel = 1;

      break;


    case 1: //Record Data

      Accel();


      if (currentTime >= recordPeriod) {

        recordAccel = 2;

      }

      break;

    case 2: //Close SD card

      closeCard();

      break;
  }
}

//=======================================================================

void openCard() {

  getFileName();
  dataFile = SD.open(fileName, FILE_WRITE);

}

//=======================================================================

void closeCard() {

  dataFile.close();

}

//=======================================================================

/*void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
  }*/

//=======================================================================

void Accel() {

  sensors_event_t event;
  lis.getEvent(&event);

  dtostrf(event.acceleration.x, 5, 3, accelX);
  dtostrf(event.acceleration.y, 5, 3, accelY);
  dtostrf(event.acceleration.z, 5, 3, accelZ);

  sprintf(accelData, "%s,%s,%s", accelX, accelY, accelZ);

  if (dataFile) {

    //if (currentTime >= accelTime + sampleRate) {

    dataFile.println(accelData);

    //accelTime = currentTime;

    if (currentTime - previousTime >= timeStamp) {

      DateTime now = rtc.now();
      sprintf(DateAndTime, ",%02d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());

      dataFile.print(accelData);
      dataFile.println(DateAndTime);

      previousTime = currentTime;
    }
  }
}
//}

//=======================================================================

void getFileName() {

  DateTime now = rtc.now();
  sprintf(fileName, "/Accel_%02d%02d%02d_%02d%02d.csv", now.year(), now.month(), now.day(), now.hour(), now.minute());
}

//=======================================================================

/*void dateTime(uint16_t* date, uint16_t* time) {
  //used for callback function for file timestamp

  DateTime now = rtc.now();

  // return date using FAT_DATE macro to format fields
   date = FAT_DATE(now.year(), now.month(), now.day());

  // return time using FAT_TIME macro to format fields
   time = FAT_TIME(now.hour(), now.minute(), now.second());
  }*/

In the Vano code you call millis() inside of case1 and exit to case2 with a certain value.

In the esp32 code, you call your millis equivalent in Case0 and never update the value again in Case1.
currentTime = (esp_timer_get_time()/1000);

TheArduino IDE for the ESP32 supports the millis() function, and you can use it like you do in the Nano.

Hi @cattledog, thanks for replying. I changed it to millis() and called it from within case 1, as per the Nano sketch. It's still not working. I decided to put a debug line in there to check the state and it seems it's in a boot loop....I'm not sure what this error means though...

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
State = 1
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d5c04  PS      : 0x00060930  A0      : 0x800d5c5c  A1      : 0x3ffb1ed0  
A2      : 0x3ffbff60  A3      : 0x3ffbfef0  A4      : 0x00000000  A5      : 0x3f400141  
A6      : 0x00000005  A7      : 0x00000003  A8      : 0x00767363  A9      : 0x3ffb1ec0  
A10     : 0x00000013  A11     : 0x3ffbff03  A12     : 0x00000013  A13     : 0x0000ff00  
A14     : 0x00ff0000  A15     : 0xff000000  SAR     : 0x00000014  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x0076736f  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xfffffffa  

ELF file SHA256: 0000000000000000

Backtrace: 0x400d5c04:0x3ffb1ed0 0x400d5c59:0x3ffb1ef0 0x400d1013:0x3ffb1f10 0x400d10fc:0x3ffb1f70 0x400d111f:0x3ffb1f90 0x400d6265:0x3ffb1fb0 0x40086a7d:0x3ffb1fd0


So you can see it gets to State = 1, then just repeats the above message in the console. No idea what this means or how to fix it to be honest.

That error is usually for an illegal memory write attempt. It may be related to the file name.
SD.h does not support long file names. They need to be limited to 8.3 format. So this is the first thing to fix.

char fileName[25];

void getFileName() {

  DateTime now = rtc.now();
  sprintf(fileName, "/Accel_%02d%02d%02d_%02d%02d.csv", now.year(), now.month(), now.day(), now.hour(), now.minute());
}

Second, try and run one of the standard SD library examples for the esp32. Can you do that successfully?

You may want to install the esp32 exception decoder for more information about the error.

https://github.com/me-no-dev/EspExceptionDecoder

1 Like

That was exactly it mate! I'm so used to SdFat it didn't even occur to me! Thanks very much.

Just a quick test and I'm at a solid 635Hz. I'm sure there is room for improvement but I'm only looking for 100Hz (200 absolute max). Some times it's just the small things.

One thing I've not been able to get to work is dtostrf() then sprintf()...yet it will let me concat a String and print as a c_str(). This is something for tomorrow now I think as I need to switch off for a while. Thanks again

#include <Wire.h>
#include<SPI.h>
#include "FS.h"
#include "SD.h"
#include "RTClib.h"
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>

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

// I2C
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

//SD Card
#define SD_CS = 5;
File dataFile;
File file;

//RTC2321
RTC_DS3231 rtc;
DateTime now = rtc.now();
char DateAndTime[30];

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

String timeStamp;
String accelData;
String accelData_TS;
float accl_X;
float accl_Y;
float accl_Z;

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

unsigned long currentTime = 0;
unsigned long previousTime = 0;
const unsigned long recordSamplePeriod = 20000;
const unsigned long timeStampPeriod = 1000;

//=====================================================================

void setup() {

  Serial.begin(115200);
  Wire.begin();

  //LIS3DH Accelerometer
  lis.begin(0x18);
  lis.setRange(LIS3DH_RANGE_4_G);   // 2, 4, 8 or 16 G!

  //RTC
  rtc.begin(); //Start RCT

  //SD Card
  SD.begin();

  dataFile = SD.open("/datafile.csv", FILE_WRITE);
  Serial.println(F("SD Open"));
}

//=====================================================================

void loop() {

  //dataFile = SD.open("/datafile.csv");

  currentTime = millis();

  if (currentTime <= recordSamplePeriod) {

    logSDCard();

  }

  else {

    dataFile.close();

    Serial.println(F("SD Close"));

  }
}

//=======================================================================

// Write the sensor readings on the SD card

void logSDCard() {

  //read accel data

  sensors_event_t event;
  lis.getEvent(&event);

  //reformat infomation

  accl_X = event.acceleration.x;
  accl_Y = event.acceleration.y;
  accl_Z = event.acceleration.z;

  accelData = String(accl_X) + "," + String(accl_Y) + "," + String(accl_Z) + "\r\n";


  if (currentTime - previousTime >= timeStampPeriod) { //doesn't work - date and time make no sense.

    sprintf(DateAndTime, "%02d/%02d/%02d,%02d:%02d:%02d\r\n", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());

    file.print(DateAndTime);
    dataFile.print(DateAndTime);
    previousTime = currentTime;

  }

    dataFile.print(accelData.c_str());


}

You don't need to convert and concatenate the float values of accl_X,Y and Z.

The stream class operation .print will send the characters of the float. Try this

//dataFile.print(accelData.c_str());
dataFile.print(accel_X);
dataFile.print(',');
dataFile.print(accel_Y);
dataFile.print(',');
dataFile.println(accel_Z); //should append \r\n

If the .println statement does not terminate as you want, then you can be more explicit

dataFile.print(accel_Z);
dataFile.print("\r\n");
1 Like

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.