Forum: Mikrocontroller und Digitale Elektronik ESP32 und SD card - dateTimeCallback() never called


von P. Z. (patric_z)


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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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

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

von P. Z. (patric_z)


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.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


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?!

von P. Z. (patric_z)


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.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


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 ;-)

von Rüdiger B. (rbruns)


Lesenswert?

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

von P. Z. (patric_z)


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.

von P. Z. (patric_z)


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.

von P. Z. (patric_z)


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

: Bearbeitet durch User
von P. Z. (patric_z)


Lesenswert?

FYI

P. Z. schrieb:
>
1
File file = SD.open(path, FILE_APPEND);     // << SD.h definition
2
File file = SD.open(path, O_APPEND);        // << SdFat.h definition

... bin grade noch etwas verwirrt, 'manchmal' gehts auch mit FILE_APPEND 
und der SdFat.h.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.