ESP32 und SD card - dateTimeCallback() never called

OP #7850028
Lesenswert?

Hallo Zusammen,

ich habe hier ein Problem meine Dateien mit einer Timestamp zu versehen.

  • ESP32 (Waveshare ESP32-c6 zero), in der Arduino IDE 2.3.4 unter Linux als "ESP32C6 Dev Module"
  • Dazu ein simples SD card module via SPI angeschlossen.

Schreiben von Dateien auf die SD Karte klappt tadellos, aber alle haben immer das selbe Datum im Jahr 1980.

Stochern im Netz hat mich dann auf den dateTimeCallback() gebracht, aber irgendwie kriege ich das nicht ans Laufen.

Minimal Beispiel:

1
#include "SD.h"     // used for SDcard, version 3.1.1 for ESP32
2
#include "SPI.h"    // used for SDcard
3
#include <SdFat.h>  // testing datetime, SdFat lib v 2.3.0 from Bill Greiman, definiert auch FAT_TIME and FAT_DATE)
4

5

6
#define day   15
7
#define month 03
8
#define year  2025
9

10
#define hour    12
11
#define minute  20
12
#define second  58
13

14
const int SD_CS_Pin = 22; 
15

16
//------------------------------------------------------------------------------
17
// call back for file timestamps
18
void dateTime(uint16_t* date, uint16_t* time) {
19
   Serial.print("DEBUG >> CALLBACK CALLED!");
20

21
  // return date using FAT_DATE macro to format fields
22
  *date = FAT_DATE(year, month, day);
23
  // return time using FAT_TIME macro to format fields
24
  *time = FAT_TIME(hour, minute, second);
25
    
26
} // end-dateTime()
27
//------------------------------------------------------------------------------
28

29

30

31
void setup() {
32
  Serial.begin(115200);
33
  while (!Serial) {
34
    ; // Wait for Serial connection.
35
  }
36

37
  // Callback for SD card to add timestamp to files
38
  SdFile::dateTimeCallback(dateTime);
39

40
  if(!SD.begin(SD_CS_Pin)){
41
    Serial.println("SD begin() FAILED.");
42
    // return;
43
  } 
44

45
  File myFile = SD.open("/testFile.txt", FILE_WRITE);
46
  if(myFile.print("This is a test text.")){
47
    Serial.println("File sucessfully written.");
48
  }
49
  myFile.close();         /// close ile object
50

51
}
52

53
void loop() {
54
  // put your main code here, to run repeatedly:
55
}

Note: Normalerweise hole ich Datum und Zeit via GPS, aber um es hier zu vereinfachen hab ich die 6 Variablen einfach fix definiert.

Es dreht sich hier also vermutlich um die Zeile:

1
SdFile::dateTimeCallback(dateTime);

Mancherorts steht, man muss diese Zeile direkt vor das "open file" stellen. Andere schreiben es soll ins Setup vor "SD.begin()" und irgendwo stand auch, dass es einfach vor "file.close()" stehen muss, da die close() function den Trigger macht.

Wird erfolgreich gebaut, auch die Testdatei wird auf der SD angelegt, aber der Callback wird scheinbar nie getriggert. Ich stehe hier grade wieder mal etwas auf dem Schlauch.

Wer order was sollte den CB wann genau triggern? Ich brauche mal wieder einen Schubs in die richtige Richtung.

Danke schonmal vorab.

OP #7850033
Lesenswert?

Niklas G. schrieb:

1
#include "SD.h"     // used for SDcard, version 3.1.1 for ESP32
2
#include <SdFat.h>

Äh, sind das zwei verschiedene SD-Libraries?!

Ähhhmmm....ja? Vielleicht. Weiss ich noch nicht so genau...

Mein Verständnis war/ist, dass SD die SD Karte händelt (zB SD.begin() usw) und SdFat nur für das Datetime Zeugs zuständig ist.

Impliziert Deine Frage, dass ich nur die SdFat.h nehmen soll? (Nur die SD.h alleine geht jedenfall nicht, da ich dann einen Fehler bekomme, dass FAT_DATE und FAT_TIME undefiniert sind.)

PS: Wenn ich das recht überblicke, dann ist die SD.h mit dem Paket für das ESP32 board installiert worden. (Zumindest liegst sie in einem Unterpfad von $HOME/.Arduino/packages/ESP32/ ) Die SdFat habe als library installiert für FAT_DATE und FAT_TIME.

Persönliche Seite #7850034
Lesenswert?

P. Z. schrieb:

SdFat nur für das Datetime Zeugs zuständig ist.

P. Z. schrieb:

Die SdFat habe als library installiert für FAT_DATE und FAT_TIME.

Heißt also du sagst der SdFat Library, diesen Callback aufzurufen, wenn du mit der SdFat Library eine Datei anlegst. Dann nutzt du die SdFat Library aber nie wieder sondern legst stattdessen die Datei mit der SD-Library an, welche natürlich überhaupt nichts von SdFat und dem Callback weiß. Oder?!

OP #7850039
Lesenswert?

DANKE! (Musste echt schmunzeln. So wie Du es formuliert hast, war die Sache sofort klar! Didaktik +1000)

Wenn man es richtig macht, dann funktioniert es!!!

Funktionierendes Minimalbeispiel:

1
//#include "SD.h"     // << AUSKOMMENTIERT
2
#include "SPI.h"    // used for SDcard
3
#include <SdFat.h>  // testing datetime, SdFat lib v 2.3.0 from Bill Greiman, also defines FAT_TIME and FAT_DATE)
4

5
#define day   15
6
#define month 03
7
#define year  2025
8

9
#define hour    12
10
#define minute  20
11
#define second  58
12

13
const int SD_CS_Pin = 22; 
14

15

16
SdFat SD;     // <<< HIER das Objekt SD definieren, weil SD.h auskommentiert wurde.
17

18
//------------------------------------------------------------------------------
19
// call back for file timestamps
20
void dateTime(uint16_t* date, uint16_t* time) {
21
   Serial.print("DEBUG >> CALLBACK CALLED!");
22

23
  // return date using FAT_DATE macro to format fields
24
  *date = FAT_DATE(year, month, day);
25
  // return time using FAT_TIME macro to format fields
26
  *time = FAT_TIME(hour, minute, second);    
27
} // end-dateTime()
28
//------------------------------------------------------------------------------
29

30
void setup() {
31
  Serial.begin(115200);
32
  while (!Serial) {
33
    ; // Wait for Serial connection.
34
  }
35

36
  // Callback for SD card to add timestamp to files
37
  SdFile::dateTimeCallback(dateTime);
38

39
  if(!SD.begin(SD_CS_Pin)){
40
    Serial.println("SD begin() FAILED.");
41
    // return;
42
  } 
43

44
  // SdFile.open("/testFile.txt", FILE_WRITE);
45

46
  File myFile = SD.open("/testFile.txt", FILE_WRITE);
47
  if(myFile.print("This is a test text.")){
48
    Serial.println("File sucessfully written.");
49
  }
50
  myFile.close();         /// close ile object
51

52
}
53

54
void loop() {
55
  // put your main code here, to run repeatedly:
56
}

Wie oben geschrieben wurde, muss der Callback des SD-Karten-Objekts natuerlich "im Bilde" sein. In dieser Version ist "SD" nicht mehr ein Objekt aus der SD.h, sondern ein Objekt aus der SdFat.h

Danke an Niklas für den Schubs. Bzw den Tritt in den Hintern. ;) Danke.

Persönliche Seite #7850045
Lesenswert?

P. Z. schrieb:

DANKE! (Musste echt schmunzeln. So wie Du es formuliert hast, war die Sache sofort klar! Didaktik +1000)

Ups, allerdings fällt mir gerade auf dass dein Ansatz sowieso gar nicht so abwegig war, denn ich habe gefunden:

The SD.h 0022 library is a wrapper for an old version of SdFat. The Arduino developers did not choose to expose timestamp callback support in their wrapper.

Den Callback bei SdFat einzustellen ist also eigentlich korrekt, aber anscheinend hat die Arduino-SD-Library das SdFat irgendwie intern und man kann den Callback dort nicht setzen. Indem du dein eigenes SD-Objekt anlegst ganz ohne die Arduino-Library geht es wieder.

Super ;-)

OP #7850055
Lesenswert?

Interessant.

Das könnte erklären warum es vereinzelt Beispiele im Netz gab die angeblich liefen, meiner ersten Version aber sehr ähnlich sahen.

Ich vermute es gibt da draussen verschiedene SD.h Varianten. Verschiedene Plattformen, verschiedene Implementationen.

Eigentlich mag ich ja nicht an den Libraries rumfummeln, aber vielleicht ist das mal so ein Fall wo es sich lohnt. Denn, auch wenn das oben jetzt geht. Wenn ich den Ansatz in mein eigentliches Projekt übersetzen will, hab ich wieder andere Probleme:

Bestimmte Funktionen fehlen in der SdFat.h scheinbar. (z.B. cardType(), totalBytes(), cardSize() ). Und bei den Pointeroperationen auf die Datei klemmt es nun auch... da muss ich jetzt mal noch was weiter bohren.

Aber Dein eigentlicher Hinweis war Gold wert. Ich hab mir einfach noch zu wenige Gedanken darüber gemacht, was welche Lib bei der SD-Karte was genau tut.

OP #7850059
Lesenswert?

Rüdiger B. schrieb:

Also bei mir stimme Datum auf der SD Karte, ich arbeite mit sd.h time.h und ntp.h als Libarys. Also vielleicht mit time.h dir RTC des ESP32 setzen.Oder mit GPS setzen: https://github.com/espressif/arduino-esp32/issues/1444

Hast Du ein Code-Sample? Welche SD.h benutzt Du?

Die Zeit aus GPS rauszuholen ist nicht mein Problem. Das klappt prima. Meine SD.h für den ESP32 scheint jedoch den Callback nicht zu triggern.

OP #7850065
Lesenswert?

Ich lass das mal hier.

Wichtiger Hinweis, falls andere da auch drueber stolpern: Die Libraries verwenden verschiedene Defines fuer READ/WRITE/APPEND.

Bei der SD.h geht es so:

1
File file = SD.open(path, FILE_APPEND);     // << SD.h definition

Bei der SdFat.h geht es so:

1
File file = SD.open(path, O_APPEND);        // << SdFat.h definition

Siehe auch: https://arduino.stackexchange.com/questions/65888/arduino-sd-card-open-file-modes-append-overwrite

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren