Forum: Mikrocontroller und Digitale Elektronik STM32 FatFS elm chan


von jens (Gast)


Lesenswert?

Ich nutze die sd Lib von Elm Chan.
Ordner anlegen Textfile anlegen das geht alles,
aber wie kann ich in ein bestehendes Textfile noch twas reinschreiben 
das geht bei mir leider nich

vielleicht kann mir einer weiterhelfen
1
void Check_sd(void)
2
{
3
4
  if( SD_Detect() == SD_PRESENT )
5
    {
6
    UART_1_Send("-- SD card detected OK \r\n");
7
    }
8
    else
9
    {
10
      UART_1_Send("-- Please connect a SD card \r\n");
11
      while(SD_Detect()!=SD_PRESENT);
12
      UART_1_Send("-- SD card connection detected \r\n");
13
    //Delay(0xffffff);
14
    }
15
16
 
17
     f_mount(0,&fs);
18
  // f_mkdir("abc"); // Ordner "/abc" anlegen
19
  f_chdir("/abc");// in Ordner "/abc" wechseln 
20
21
  // in Ordner "/abc" "xxx.TXT"  Text file anlegen  
22
  res = f_open(&fsrc, "xxx.TXT" ,  FA_OPEN_EXISTING | FA_WRITE);
23
24
     if ( res == FR_OK )
25
     { 
26
      // Write buffer to file 
27
        for( a = 0; a < 1024; a++ )
28
        {
29
          res = f_write(&fsrc, textFileBuffer, sizeof(textFileBuffer), &br);
30
        }
31
32
       printf("xxx.TXT successfully created        \r\n");
33
34
      // close file 
35
      f_close(&fsrc);      
36
     }
37
     else if ( res == FR_EXIST )
38
     {
39
     UART_1_Send("xxx.TXT created in the disk      \r\n");
40
     }
41
42
43
  f_chdir("0:.."); //Zurück ins ROOT  
44
45
46
}

von Falk B. (falk)


Lesenswert?

@jens (Gast)

>Ich nutze die sd Lib von Elm Chan.

Me too!

>Ordner anlegen Textfile anlegen das geht alles,
>aber wie kann ich in ein bestehendes Textfile noch twas reinschreiben
>das geht bei mir leider nich

Öffnen und mit f_lseek ans Ende spulen. Siehe Doku.

von Tom A. (toma)


Lesenswert?

Hallo Leute,

habe mir jetzt mit Hilfe von Elm Chans eine SD-Karte an einen STM32F100 
angebunden. Das Ganze soll ein Datenlogger werden.

Die Anpassung an die Library war weit schwieriger als vielfach 
beschrieben, ich musste ordentlich debuggen und ändern um das Ganze zum 
laufen zu bringen. Keines der, von mir benutzten, Beispiele hat wirklich 
funktioniert.

Inzwischen läuft es, aber es gibt noch ein kleines Problem: Ich schreibe 
mit f_write(...) Datensätze, als Textzeilen, auf 2GByte SD-Karte. Alle 
512Bytes werden die Daten mit f_sync(.....) auf die Karte gesichert. 
Nachdem aber 32KByte auf die Karte geschrieben sind, gerät f_write aus 
dem Tritt und liefert kein FR_OK mehr zurück. Nachdem ich die Datei 
schließe und neu öffne geht es wieder. Dies passiert, zyklisch, alle 
32KByte. Ist kein großes Problem, aber lästig.

Kennt jemand das Problem und hat vielleicht eine Lösung?

Gruß. Tom

von Falk B. (falk)


Lesenswert?

@ Tom Amann (toma)

>Die Anpassung an die Library war weit schwieriger als vielfach
>beschrieben, ich musste ordentlich debuggen und ändern um das Ganze zum
>laufen zu bringen.

Das kann ich kaum glauben. Was hast du denn geändert?

>Inzwischen läuft es, aber es gibt noch ein kleines Problem: Ich schreibe
>mit f_write(...) Datensätze, als Textzeilen, auf 2GByte SD-Karte. Alle
>512Bytes werden die Daten mit f_sync(.....) auf die Karte gesichert.

Braucht man nicht, das läuft automatisch,

>Nachdem aber 32KByte auf die Karte geschrieben sind, gerät f_write aus
>dem Tritt und liefert kein FR_OK mehr zurück. Nachdem ich die Datei
>schließe und neu öffne geht es wieder. Dies passiert, zyklisch, alle
>32KByte. Ist kein großes Problem, aber lästig.

Klingt nach einer falschen Definition von Datentypen. Die sind nochmal 
direkt in der Datei integer.h drin. Es kann aber auch, und das ist 
deutlich wahrscheinlicher, ein Programmierfehler eben dieser Art 
ausserhalb des FATfs sein.

von Jim M. (turboj)


Lesenswert?

Tom Amann schrieb:
> Nachdem aber 32KByte auf die Karte geschrieben sind, gerät f_write aus
> dem Tritt und liefert kein FR_OK mehr zurück. Nachdem ich die Datei
> schließe und neu öffne geht es wieder.

Bei 2GB Karten ist die Cluster Größe genau 32 KB. Das bedeutet das auf 
die FAT zugegriffwen wird, um einen neuen freien Cluster zu suchen.

Das darf eigentlich nur bei Kartenfehlern schief gehen. In Deinem Fall 
würde ich allerdings zuerst nach Software Fehlern beim Zugriff auf die 
Karte suchen.

von Tom A. (toma)


Lesenswert?

@Falk Brunner

SPI Schnittstelle in 16Bit-Mode geht gar nicht, im 8Bit-Mode ist Takt/16 
die max. Frequenz. Die Beispielfunktion wait_ready ist so geschrieben, 
daß sie nicht auf die Karte wartet. Und das warten auf das 
Übertragungsende der SPI-Transmit Funktion wartete nicht wirklich auf 
das Ende der Übertragung. Es waren noch ein paar andere Dinge, die mir 
jetzt nicht einfallen. Wie gesagt, es war nicht so einfach die 
Geschichte zum laufen zu kriegen. Hatte vor ein paar Jahren mit einem 
AVR und der Version 9 der Library schon etwas gemacht, das war deutlich 
einfacher, da mußte ich wirklich nur ein paar Einstellungen anpassen. 
Habe zum Versuch das PFF3 mit MCS51 probiert, lief auch rel. schnell, 
Aber mit FF11 und MCS51/STM32 zickt es.

@Jim Meba

Guter Tip. Damit wird es vermutlich zusammenhängen. Im Moment läuft es 
für das Projekt ausreichend, wenn ich mehr Zeit habe schaue ich mir das 
näher an.

Danke für eure Antworten, sie haben mir auch gezeigt, daß ich meinen 
Code nochmal genauer anschauen muß.

Gruß. Tom

von grundschüler (Gast)


Lesenswert?

Tom Amann schrieb:
> SPI Schnittstelle in 16Bit-Mode

Das pssiert wenn du 8-bit chan code (AVR) mit 16-bit-spi-code 
vermischst:
1
/*-----------------------------------------------------------------------*/
2
/* Wait for card ready                                                   */
3
/*-----------------------------------------------------------------------*/
4
5
static
6
int wait_ready (void)  /* 1:OK, 0:Timeout */
7
{
8
  BYTE d=0;
9
  UINT tmr;
10
  for (tmr = 5000; tmr; tmr--) {  /* Wait for ready in timeout of 500ms */
11
    rcvr_spi_multi(&d, 1);
12
    if (d&0xff == 0xFF) break;
13
    _delay_us(100);
14
  }
15
  return tmr ? 1 : 0;
16
}


  BYTE d=0; ist nur als byte angelegt, wird aber an spi als pointer 
übergeben und mit 16bit beschrieben. Das bringt den Speicher 
durcheinander.


Am besten neueste Version von Chan herunterladen und neu aufsetzen.

von Falk B. (falk)


Lesenswert?

@Tom Amann (toma)

>SPI Schnittstelle in 16Bit-Mode geht gar nicht,

Glaub ich nicht. Zumindest die Blockübertragung sollte auch in 16 Bit 
gehen.

> im 8Bit-Mode ist Takt/16
>die max. Frequenz.

Das ist dann eher ein Problem vom ARM, nicht vom FATfs. Und selbst wenn 
es deutlich langsamer ist, MUSS es solide funktionieren!

> Die Beispielfunktion wait_ready ist so geschrieben,
>daß sie nicht auf die Karte wartet.

Kaum ;-)

> Und das warten auf das
>Übertragungsende der SPI-Transmit Funktion wartete nicht wirklich auf
>das Ende der Übertragung.

Doch. Aber natürlich musst DU dafür sorgen, dass es mit DEINEM Prozessor 
zusammenpasst! Da hab ich beim ATXmega mal SEHR lange gesucht, am Ende 
war es wie zu 99,9% natürlich meine eigene Dämlichkeit!

Beitrag "Problem mit Micro-SD-Karte"

>Guter Tip. Damit wird es vermutlich zusammenhängen. Im Moment läuft es
>für das Projekt ausreichend, wenn ich mehr Zeit habe schaue ich mir das
>näher an.

Also mit SO einem massiven Fehler würde ICH nicht weitermachen! Du hast 
noch einen massiven Bug drin!

von Tom A. (toma)


Lesenswert?

Hallo Leute,

danke für die Tips. Bin sicher noch ein paar Bugs im SD-Kartenprogramm 
zu haben, aber es läuft und verrichtet seine Arbeit. Die restlichen 
Fehler werde ich auch noch finden.

Habe den Effekt jetrzt näher untersucht. Wenn ich f_sync nicht aufrufe, 
tritt der Effekt nicht auf, aber dann ist mir die Gefahr von 
Datenverlust zu groß. Im Moment baue ich Datensätze per Software auf und 
speichere sie auf Karte. Ein Datensatz besteht aus 64Bytes, diese 
Datensätze schreibe ich mit f_write auf Karte. Sind acht dieser 
Datensätze zusammen (8 * 64 = 512Bytes) übernehme ich sie mit f_sync 
dauerhaft auf die Karte.

Habe bei ElmChan gelesen, daß f_sync zur übernahme der Daten auf Karte 
ist, funktioniert wie f_close, aber ohne die Datei zu schließen. 
Synchronisiere ich nicht, sind die Daten nicht übernommen und bei 
Stromausfall, Kartenentnahme oder Ähnlichem sind sie weg. Habe das, auch 
mit großen Datensätzen schon getestet. Ohne f_close oder f_sync sind die 
Daten futsch.

Das ist für einen Datenlogger nicht optimal, wenn nach Wochen oder 
Monaten Aufzeichnung, die Daten durch einen Stromausfall weg wären.

Der Fehler hängt tatsächlich mit der Clustergröße zusammen. Habe eine 
Karte jetzt mit 64kByte Clustergröße formatiert, nun tritt der Fehler 
zyklisch alle 64kBytes auf

Hier die STM32 Version von "wait_ready"  aus den FF11-Beispielen:

/*---------------------------------------------------------------------- 
-*/
/* Wait for card ready 
*/
/*---------------------------------------------------------------------- 
-*/
static int wait_ready (  /* 1:Ready, 0:Timeout */
  UINT wt      /* Timeout [ms] */
)
{  BYTE d;

  Timer2 = wt;
  do {  d = xchg_spi(0xFF);
/* This loop takes a time. Insert rot_rdq() here for multitask 
envilonment. */
  } while (d != 0xFF && Timer2);  /* Wait for card goes ready or timeout 
*/
  return (d == 0xFF) ? 1 : 0;
}

Bei meinen Karten kann ich lange warten, bis sie auf 0xFF mit etwas 
anderem als 0xFF antworten, solange vorher nicht wenigstens ein CMD0 
gesendet wurde. Ist sicher gewollt, daß die Funktion, ohne voriges 
Kommando, als reine Zetverzögerung arbeitet.
----------------------------------------

Auch hier gibt es Probleme. Das Übertragungsende am auswerten des 
BSY-Flag zu erkennen funktioniert nicht zuverlässig. Es am RXE- oder 
TXE-Flag festzumachen funktioniert gar nicht. Warte ich, nach der 
Flagprüfung, noch in einer kleinen Schleife, oder prüfe das BSY-Flag 
erst auf "0" und danach auf "1" geht es tadellos. Ich verwende den 
STM32F100C8T6

static BYTE xchg_spi ( BYTE dat)  /* Data to send */
{  SPIx_DR = dat;
   while (SPIx_SR & _BV(7)) ;
   return (BYTE)SPIx_DR;
}

Aber wie gesagt, es funktioniert inzwischen ganz gut. Mich stören nur 
die Schreibfehler an der Clustergrenze mit f_sync!

P.S. Habe eben wieder eine Testdatei mit 20000 Datensätzen, zu je 64Byte 
(1,28MByte) erfolgreich geschrieben. Bei stündlicher Aufzeichnung 
(Klimadaten) wäre das ein Zeitraum von 833 Tagen.

Gruß. Tom

von Tom A. (toma)


Lesenswert?

Hallo Leute,

bevor ihr jetzt Zeit verschwendet, ich habe den vermutlich 
verantwortlichen Fehler gefunden.

Hatte in der ursprünglichen Version von "wait_ready" den Rückgabewert
  return (d == 0xFF) ? 1 : 0;
zum testen durch ein
  return (1);
ersetzt, und das stand da immer noch.

Jetzt funktioniert zwar gar nichts mehr, aber nun muß ich nur noch 
herausfinden, was ich sonst noch "verbessert" hatte und wieder auf 
Ursprung zurückschreiben.

Vielen Dank für eure Mühe, ich werde vom Ergebnis berichten.

Gruß. Tom

P.S. ohne die Aläufe hier nochmal zu besprechen, hätte ich den Fehler 
sicher nicht so schnell gefunden.

von Falk B. (falk)


Lesenswert?

@Tom Amann (toma)

>Datensätze schreibe ich mit f_write auf Karte. Sind acht dieser
>Datensätze zusammen (8 * 64 = 512Bytes) übernehme ich sie mit f_sync
>dauerhaft auf die Karte.

Wozu? Das macht FATfs allein, denn es hat einen 512 Byte Puffer.
Aber selbst mit f_sync darf es keinen Fehler bei 32kB geben.

>mit großen Datensätzen schon getestet. Ohne f_close oder f_sync sind die
>Daten futsch.

Logisch, weil der Eintrag im FAT dann nicht vollständg ist.

>Der Fehler hängt tatsächlich mit der Clustergröße zusammen. Habe eine
>Karte jetzt mit 64kByte Clustergröße formatiert, nun tritt der Fehler
>zyklisch alle 64kBytes auf

Hmmm.

>Hier die STM32 Version von "wait_ready"  aus den FF11-Beispielen:

Das wait_ready ist nicht das Problem, mit hoher Wahrscheinlichkeit aber 
dein xchg_spi(0xFF); Hier muss man aufpassen, wann die Übertragung 
WIRKLICH beendet ist. Und man muss aufpassen, dass man mit ggf. 
vorhandenen FIFOs sich nicht ins Knie schießt (siehe mein Beitrag!)

>Bei meinen Karten kann ich lange warten, bis sie auf 0xFF mit etwas
>anderem als 0xFF antworten, solange vorher nicht wenigstens ein CMD0
>gesendet wurde. Ist sicher gewollt, daß die Funktion, ohne voriges
>Kommando, als reine Zetverzögerung arbeitet.

Das funktioniert schon, aber nur, wenn der SPI-Zugriff sauber ist! Da 
hab ich mich auch lange selber veralbert.

>Auch hier gibt es Probleme. Das Übertragungsende am auswerten des
>BSY-Flag zu erkennen funktioniert nicht zuverlässig.

Klingt stark nach dem oben geschilderten Problem!

>Aber wie gesagt, es funktioniert inzwischen ganz gut.

FALSCH! Es ist immer noch ein ELEMENTARER Fehler drdin!

> Mich stören nur
>die Schreibfehler an der Clustergrenze mit f_sync!

EBEN!

>P.S. Habe eben wieder eine Testdatei mit 20000 Datensätzen, zu je 64Byte
>(1,28MByte) erfolgreich geschrieben. Bei stündlicher Aufzeichnung
>(Klimadaten) wäre das ein Zeitraum von 833 Tagen.

Und warum gibt es jetzt keinen Fehler? Was hast du geändert?

von Falk B. (falk)


Lesenswert?

@ Tom Amann (toma)

>Hatte in der ursprünglichen Version von "wait_ready" den Rückgabewert
>  return (d == 0xFF) ? 1 : 0;
>zum testen durch ein
>  return (1);
>ersetzt, und das stand da immer noch.

AUA!

>Jetzt funktioniert zwar gar nichts mehr, aber nun muß ich nur noch
>herausfinden, was ich sonst noch "verbessert" hatte und wieder auf
>Ursprung zurückschreiben.

Nimm FATfs frisch aus dem Archiv und mach es neu!
Man muss nur die alleruntersten Funktionen zum SPI-Zugriff anpassen, 
sonst NICHTS! Lies meinen Beitrag!

von Falk B. (falk)


Lesenswert?


von Tom A. (toma)


Lesenswert?

Hallo Leute,

nachdem ich noch ein paar meiner "Verbesserungen" entfernt habe, sieht 
es so aus als würde es laufen. Im Moment erzeuge ich grad eine große 
Datei (50000 Datensätze) unter Debug-Bedingungen. Am Filepointer kann 
ich erkennen, daß jetzt die Clustergrenze fehlerfrei überwunden wird.

Hier meine Version der Sende-/Empfangs-Routine für STM32:

static BYTE xchg_spi (BYTE dat)    // Daten senden/empfangen
{ SPI1->DR = dat;
  while(!(SPI1->SR & 0x0080));   // hinzugefügt (dann funktioniert es)
  while(SPI1->SR & 0x0080);       // urprünglich (reicht nicht)
  return SPI1->DR;
}

Die ursprüngliche Routine hat nur das Busy-Flag auf gesetzt geprüft, 
damit wurde zu früh abgebrochen. Jetzt prüfe ich zuerst auf ein 
gelöschtes und anschließend auf ein gesetztes Busy-Flag und nun wird 
wirklich bis zum Übertragungsende gewartet.

Ein Blick auf den Versucht zeigt, es geht jetzt langsamer, aber die 
LED's blinken regelmäsiger :)

Danke euch allen, jetzt habe ich die Zeit mir den Beitrag von Falk 
durchzulesen - danke.

Gruß. Tom

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.