Forum: Projekte & Code MMC SD library FAT16 FAT32 read write


von Sucher (Gast)


Lesenswert?

Hallo
ich möchte diesen Thread nicht verwässen und habe deshalb einen neuen 
Thread gestartet.
Wie sieht es mit der Lebensdauer der Karte aus, wenn man pro Sekeunde 
kleine Einheiten schreibt?
Ist das unsinnig?
Wie sollte man da vorgehen?

MfG
Achim

siehe ==>Beitrag "SD Card GPS Logger optimieren?"

von Daniel (Gast)


Lesenswert?

Hallo.

@Onit
Da ein '\n' halt auch nur ein Char/Byte ist, wird da schon nix doppelt 
gezählt..

@Sucher
Bei meiner Lib werden halt immer 512 Bytes zwischengespeichert, da auch 
immer 512 Bytes direkt auf die Karte müssen. Daher ist die Langlebigkeit 
genau so, als wenn ein Pc auf die Karte schreibt...Nur das der 
vielleicht noch bisschen mehr Puffert als es mit einem MC möglich ist..


Grüße Daniel

von Sucher (Gast)


Lesenswert?

Hallo

@Daniel das heißt, wenn ich kleinere Einheiten als 512 Byte schreibe 
wird das in deinem Interface gepuffert? Muss man da beim Schreiben dann 
die Bytegrenzen (512 Byte Blockung) als Anwender beachten?
Es wird also solange gepuffert bis 512 Byte erreicht sind. Wenn ich nun 
einen String schreibe der über die 512 Byte geht wird dann ein 512 Byte 
String auf die SD Karte geschrieben und der Rest gepuffert? Wenn nur 
gepuffert wird ist der Schreibvorgang schneller, als wenn eine 
Blockgrenze überschritten wird und auf die SD geschrieben wird. Wie 
lange dauert dann dieser Aufruf (klar Proz abhängig)?

Wird bei jedem Blockschreiben die FAT auf der SD Karte aktualisiert? 
Falls ja wäre das  ja der kritische Punkt mit dem "kaputt" gehen der SD 
Karte, oder wird nur beim Schließen des Files aktualisiert?

Fragen über Fragen...

Vielen Dank
Achim

von Daniel R. (zerrome)


Lesenswert?

Hallo Sucher,

ja richtig. In der Lib gibt es einen 512Byte Puffer. Ist dieser voll, 
wird die Karte mit diesen Bytes beschrieben.

Erst bei ffclose() erfährt der Dateieintrag und die Fat eine 
Aktualisierung. Es werden immer freie Cluster in einer Reihe gesucht, 
ist diese Anzahl voll, so werden diese auch schon in der Fat verkettet. 
Wird erst zum Problem, wenn die Fat total fragmentiert ist...

Eine Datei bei FAT-Dateisystemen ist Quasi in 3 Teile aufgeteilt:
1. Datei Eintrag mit Name,länge usw in einem Ordner.
2. FAT Einträge
3. Die Daten selber

Siehe auch: http://www.mikrocontroller.net/articles/AVR_FAT32

Wer mag kann mit "int i=file.cntOfBytes;" abfragen wie viele Bytes in 
dem Puffer schon geschrieben sind. Bei 512 wird auf die Karte 
geschrieben...

Wie lange jetzt genau das schreiben eines 512Byte Blocks dauert müsste 
man mal testen :)
Ebenso wie lange es dauert neue freie Cluster aus der Fat zu suchen oder 
solche Cluster zu verketten...

Grüße Daniel

von Sucher (Gast)


Lesenswert?

Hallo

@Daniel noch ne Frage(n): Kann man beim Öffnen ne Dateigrösse angeben, 
dass die entsprechenden Cluster gleich vekettet werden, ohne dass man da 
explizit reinschreibt?

Oder geht das mit ffseek übers Dateiende hinaus...wird dann reserviert, 
oder darf bei ffseek der Offset nicht übers Dateiende rausgehen?

Gibts dafür ne andere Möglichkeit?

Vielen Dank
Achim

von Daniel R. (zerrome)


Lesenswert?

Moin,

also ffseek() darf auf keinen Fall über das Dateiende hinaus. Gilt nur 
für innerhalb einer Datei, bis zum letzten Byte.

Also vorher die Datei Größe bestimmen? Wieso?
Wäre schon machbar, mir erschließt sich aber nicht der Grund wieso man 
das machen sollte.
Wenn es um Geschwindigkteit geht, einfach dafür sorgen, dass die Fat 
nicht fragmentiert ist. dann könnten bis zu 65000 Cluster am Strück mit 
Daten voll gemacht werden, bevor diese verkettet werden müssen (müsste 
man nur 2 Zahlen in der Lib ändern).

Mal mit Zahlen:

4 Sektoren Pro Cluster.
512 Bytes Pro Sektor.
65000 Cluster.

Macht 126,95 Mega Bytes am Stück, ohne etwas mit der Fat oder dem 
Dateieintrag machen zu müssen :)

Bei 65000 Clustern, die in der Fat verkettet werden müssen, müssen 508 
Fat Sektoren geschrieben werden, macht 206096 Bytes. Also etwa 254 
KBytes. Die bekommt man so in etwa 2 Sekunden beschrieben...

Grüße Daniel

von Sucher (Gast)


Lesenswert?

Hallo

@Daniel ich bin eben dabei die einzelnen Implementierungen abzuklopfen.
In der Implementierung von Roland Riegel wird sowas diskutiert, dass man 
am Anfang gleich einen großen File allokiert weil sonst das Anfügen 
lange dauert.
zB.:Beitrag "Re: MMC/SD-Karte mit FAT16 an AVR"

Ich muß halt mal damit spielen und Erfahrungen sammeln...

Vielen Dank
Achim

von Daniel R. (zerrome)


Lesenswert?

Hi Achim,

den Code von Roland versteh ich teilweise nicht genau.
Aber generell dauert es halt ein bisschen die Fat zu updaten und neue 
freie Cluster zu suchen.
Zuerst hatte ich da auch eine etwas sperrige Methode. Jetzt geht das 
total schnell, wenn halt die Fat nicht groß fragmentiert ist.

Wenn du da irgendwo Vorteile/Nachteile siehst, könnte man das ja mal 
zusammen tragen und als Vergleich ins Wiki stellen...

Grüße Daniel

PS: hab mich da oben bei einer Ziffer vertan, muss natürlich 260096 
Bytes heißen^^

von Johannes N. (strangeman)


Lesenswert?

Ich habe noch ein Problem. file.length ist bei mir negativ (-492). Es 
ist aber eine Datei geöffnet und ich kann ganz ordentlich daraus lesen.

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Hallo,

sehr seltsam. Wie kommst du denn auf -492 ?
Weil eigentlich dachte ich das ein "unsigned long int length" (siehe 
fat.h) niemals negativ werden kann.
Lässt du dir das vielleicht falsch anzeigen?
Nimm mal die neue Version, vielleicht wirds dann besser.

Hab jetzt auch die bekannten Bugs beseitigt.

Es gibt 2 neue Schalter in der fat.h.

1. OVER_WRITE
Gibt an ob die Datei überschreiben Funktionalität mit Kompiliert wird.
Da wenn überschrieben wird auch immer der zu überschreibende Sektor 
geladen werden muss, ist meine Empfehlung "OVER_WRITE 0" zu setzen und 
auf überschreiben zu verzichten.

2.MAX_CLUSTER_IN_ROW
Gibt an wie viele verkette bzw. leer Cluster für eine Datei gesucht 
werden, maximaler Wert, 65 534.

Grüße Daniel

von Johannes N. (strangeman)


Lesenswert?

Inzwischen habe ich es herausgefunden: warum der unsigned long int nun 
negativ war weiß ich nicht, aber deine Lib hat mir die Datei 4GB groß 
gemacht, obwohl die Karte nur einen GB hat... nun gehts aber.

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Hallo,

ja das mit der Dateigröße ist mir dann doch noch klarer geworden. Unter 
Umständen waren auf file.length noch alte Daten vom durchsuchen von 
alten Ordnern... hatte da aufgrund von Codegröße alles mögliche gekürzt 
^^

Da überschreiben von Daten so kompliziert ist und deshalb relativ 
langsam, gibt es 2 Funktionen zum schreiben, die über den schon 
erwähnten Schalter OVER_WRITE in fat.h wahlweise mit ein Kompiliert 
werden können.

Der Code ist diesmal wirklich stabil, da ich ausgiebig Zeit zum testen 
hatte.
Anregungen und Tipps immer willkommen.

Als Anhang die neue Version mmc-0.5.3

Es ist dringend zu empfehlen, entweder die Version mmc-0.4.8 oder die 
neue zu benutzen !

Grüße Daniel

von Daniel R. (zerrome)


Lesenswert?

Wiki auch geupdatet. Vor allem "Interne Technik"

http://www.mikrocontroller.net/articles/AVR_FAT32

von Sucher (Gast)


Lesenswert?

Hallo

@Daniel mal ne blöde Frage "Wann wird eine FAT fragmentiert"?

..doch nur wenn ich eine Datei schließe ne neue öffne und schreibe 
schließe und die alte Datei öffne und was dran hänge...

oder eine Datei lösche und ne neue mit verschiedener Größere schreibe?

Macht es da nicht Sinn (meine oben gestellte Frage) dass man beim Öffnen 
oder seek die Deitei auf eine bestimmte grösse aufblähen kann ohne 
reinzuschreiben?

MfG
Achim

von Daniel R. (zerrome)


Lesenswert?

Hallo Achim,

eine Fat fragmentiert, wenn man Daten löscht. weil da wo vorher die 
Cluster einer Datei in der Fat verkettet waren, nun Cluster frei sind.

Die von Dir beschriebenen Probleme sind dann nur die Folge draus...

Das Problem ist, ich möchte die Lib so allgemein wie möglich halten. 
Natürlich müsste man, wenn etwas sehr Zeitkritisch ist testen und ggf. 
die Lib anpassen.

Oder sogar alles auf eine spezielle Gegebenheit umschreiben und zusammen 
kürzen. Mir geht da z.B. eine Einzige Funktion durch den Kopf, die eine 
ganze komplett vordefinierte Datei schreibt oder ähnliches...

Das mit dem vorher allozieren wäre garkein Problem, nur ich gehe mal 
davon aus, nicht vorher zu wissen wie lang eine Datei wird.

Vielleicht baue ich noch ein, dass man beim schreiben immer mindestens 
MAX_CLUSTERS_IN_ROW freie bekommt. Und/Oder eine Funktion, die die 
letzte Datei in der Fat ermittelt und erst danach mit schreiben anfängt.

Grüße Daniel

von Kricke (Gast)


Lesenswert?

Hallo,

ich versuche gerade den Code zu verwenden, leider ohne den gewünschten 
Erfolg. Ich habe die letzte Version benutzt und momentan sieht mein Code 
so aus:

[c]

int main (void)
{
  //wdt_enable(WDTO_1S);

  sei();

  initUart();
  sendEOL();
  uartPutS("Serveur de temps");
  sendEOL();

  if(mmc_init() == 0)
  {
    uartPutS("SD-Card Inizialisation failed.");
    sendEOL();
    while(1) {};
  }

  uartPutS("SD-Card initialized.");
  sendEOL();

  if (fat_initfat() == 0)
  {
    uartPutS("FAT initialized.");
    sendEOL();

    char datei[12]="test.txt";

    fat_str(datei);

    switch (ffopen(datei ))
    {
      case 1:
      {
        uartPutS("Existing file opened.");
        sendEOL();
      }
      case 2:
      {
        uartPutS("New file created and opened.");
        sendEOL();
      }
      default:
      {
        uartPutS("Cannot create or open file.");
        sendEOL();
      }
    }

    ffwrites((char*)"Hallo Datei :)");
    ffwrite(0x0D);
    ffwrite(0x0A);

    uartPutS("Data written to file.");
    sendEOL();

    ffclose();
    uartPutS("File closed.");
    sendEOL();
  }

  while(1) {};
}

[\c]

Die Initialisierung klappt, nur beim ffopen() bzw genauer in der Routine 
unsigned char fat_loadFileDataFromDir(char name[]) hängt der Prozessor 
sich auf. Nach meinen bisherigen Nachforschungen sind die ausgelesenen 
Sektoren alle '0' und der Prozessor hängt. Auf dem SPI-Bus ist nichts 
mehr los. Was mich wundert: Die Karte wird als FAT32 erkannt, auch wenn 
sie auf FAT16 formatiert wurde. Ich habe sowohl FAT32 als auch 16 
ausprobiert und auch SUPERFLOPPY geändert, ohne Erfolg.

Hat jemand eine Idee, woran es liegt?

von Kricke (Gast)


Lesenswert?

Ok, die Initialisierung läuft irgenwie auch nicht: Selbst ohne Karte 
läuft mmc_init() durch... :-(

von Daniel R. (zerrome)


Lesenswert?

Hallo,
also besser ist sowas für mmc_init() :
1
while (mmc_init() !=0){
2
  ;  
3
  }

Da es sein kann das es etwas dauert bis die Karte "anspringt".
Sieht sonst OK aus.
Vielleicht mal den SPI Takt bisschen runter setzen.
Wie hast du die Karte angeschlossen?

Grüße Daniel

von Kricke (Gast)


Lesenswert?

Der SPI-Takt liegt bei etwa 120kHz, die Karte ist direkt an einen 
Atmega644p angeschlossen, der mit 3,3V läuft. Ein Pull-Up an DO ist 
dran.

Deinen obigen Vorschlag habe ich schon umgesetzt, aus der Schleife kommt 
der Controller bzw. die Karte nicht raus. Ich lese mir mal die 
Bedienungsanleitung meines Logigports durch...

von Daniel R. (zerrome)


Lesenswert?

Mit mmc_init() hatte ich bis jetzt nur Probleme, wenn die Kabel zur 
Karte zu lang waren, aber bei 120KHz dürfte das kein Problem sein.

Vielleicht mal andere Karten ausprobieren, Schaltung überprüfen sonst 
hab ich keine Ahnung wieso die mmc_init() nicht durchläuft.

Hm über was wird die Karte mit Strom versorgt? Da können Peaks bis zu 
60mA auftreten, und Ripple auf der Versorgungsspannung ist auch 
schlecht...

Mach doch mal ein Foto von der Schaltung :)


Grüße Daniel

von Kricke (Gast)


Lesenswert?

Hallo Daniel,

vielen Dank fuer die Tipps. Auf so einen Mist muss man erst einmal 
kommen: Der SD-Kartenhalter von ALPS hatte an zwei Pads keinen 
Kontakt... Da der groesstenteils geschlossen ist, kam man da nicht ran. 
Das ganze hat lich jetzt eine 2GB-Karte gekostet, aber die sind ja 
guenstig inzwischen.

Jetzt habe ich gerade meine erste Datei angelegt und beschrieben. Wenn 
der Rest auch so gut laueft, waere das sehr cool. Danke fuer die 
Bibliothek. :-)

von Daniel R. (zerrome)


Lesenswert?

Hi,
schön, dass es jetzt klappt,
schade das ne Karte drauf gegangen ist ^^
Aber sowas kurbelt ja die Konjunktur an :)

Grüße Daniel

von Emperor_L0ser (Gast)


Lesenswert?

Moin, ich bin grade dabei deine Bibliothek zu testen. Ich habe hier 3 
SD-Karten liegen (1x 128MB, 1x 256 MB von toshiba und 1x 2GB von san 
disk), allerdings gibt es Probleme beim Schreiben. Mein Prozessor ist 
ein AT90CAN128, welcher mit 3,3V läuft und vom internem Takt versorgt 
wird.

Hier eine genauere Fehlerbeschreibung:
-Lesen geht.
-Löschen von Dateien geht.
-Anlegen einer nicht vorhandenen Datei geht nur jedes 2. mal, wobei die 
Funktion nie zurückkehrt, egal ob eine Datei auf der SD-Karte angelegt 
wurde oder nicht.
-Schliessen einer Datei, bei der sich Daten geändert haben geht nicht, 
es werden also nie Daten geschrieben.

Alle Schreibversuche auf die SD-Karten enden damit, dass der Prozessor 
sich dauerhaft mit der SD-Karte unterhält, welcher Befehl übers SPI 
läuft kann ich leider nicht sagen.

Die SD-Karten habe ich zwischendurch immer wieder mit Windows auf FAT32 
formatiert. Die Einstellung SUPERFLOPPY habe ich sowohl gesetzt, als 
auch nicht gesetzt probiert.

Eine genauere Beschreibung kann ich mangels JTAG-Interface leider nicht 
geben.

mfg Emperor_L0ser

von daniel (Gast)


Lesenswert?

Hallo,
hast du irgendwo den Code geändert?
Wie rufst du die Funktionen auf?

Versuchst du zu überschreiben? Dann muss "OVER_WRITE 1" und "WRITE 1" 
gesetzt sein.

Grüße Daniel

von daniel (Gast)


Lesenswert?

ach äh welche Version benutzt du? 0.5.3 ?

von Emperor_L0ser (Gast)


Lesenswert?

Moin,
ja ich habe den Code geändert, dies beschränkt sich allerdings darauf, 
dass ich alle Variablendefinitionen aus den for-Schleifen entfernt und 
an den Anfang der Funktion gepackt habe (ANSI-C99 Standard, mein avr-gcc 
meckerte). Der AT90CAN128 ist von den Definitionen mit dem ATMega128 
kompatibel, ich musste dort nichts ändern.
Ich verwende Version 0.5.3 und die Dateien, die dort nicht enthalten 
sind (main.c, mmc.c und mmc.h) verwende ich aus 0.5.2. Aufrufen tu ich 
nur die Funktionen, welche in der Beispiel-Funktion der main.c sind.
Write ist die ganze Zeit auf 1, sonst sind die Funktionen ja garnicht 
vorhanden. OVER_WRITE habe ich sowohl gesetzt als auch ungesetzt 
versucht.

mfg Emperor_L0ser

PS: ich verwende nicht die Makefile, meine Befehle, wie für alle meine 
Projekte:

if avr-gcc -O2 -mmcu=at90can128 -DF_CPU=1000000 ./*.c
then
        avr-objcopy -O ihex -R .eeprom a.out flash.hex
        avrdude -p c128 -e -c pony-stk200  -U flash.hex
        exit 1
fi

von daniel (Gast)


Lesenswert?

Hallo,

da liegt das Problem, es gibt Funktionen, da muss man noch Code 
ergänzen, damit man die Definitionen nach oben schreiben kann.

Versuch mal dem avr-gcc "-std=gnu99" beizubringen. Dann einfach die 
Original fat.c und file.c dann läufts...

Grüße Daniel

von Emperor_L0ser (Gast)


Lesenswert?

Ich hab es jetzt so gemacht, wie du gesagt hast und es läuft, schonmal 
Danke dafür. Den ersten Teil deiner Antwort versteh ich nicht ganz. Ich 
würd vor allem den Code gerne auch so schreiben, dass er ANSI-C Konform 
ist, da ich ja nicht weiss, ob ich drei Jahren noch den GCC-Compiler 
verwende.

mfg Emperor_L0ser

von Daniel R. (zerrome)


Lesenswert?

Ich bin es von C# und Java gewöhnt überall Variablen zu definieren und 
Deklarieren, is schön bequem, aber is halt kein ANSI-C von 1986...
Eigentlich sollte jeder halbwegs gute Compiler auch ANSI/ISO-C99 können, 
egal.

Hab grad den Code nicht vor Augen, aber man müsste Teile umschreiben, 
damit man die Definitionen an den Anfang der Funktionen setzen kann. 
Musst dir mal genau anschauen was da gemacht wird.

Grüße Daniel

von elral (Gast)


Lesenswert?

Hallo Daniel,

ich habe die Lib zwar noch nicht getestet, scheint aber recht 
interessant für mich zu sein.
Ich frage mich allerdings, wie ich den Inhalt des Directories weiter 
verarbeiten kann. Eine Ausgabe auf die serielle Schnittstelle hilft mir 
nicht weiter (ffls), da ich es auf einem direkt angeschlossenen Display 
ausgeben möchte. Aus einem anderen Beispiel kenne ich zwei folgende 
Funktionen:
* Ermittlung der Anzahl der Directory Einträge
* Ermittlung des Namens des x-ten Directory Eintrages
Können die beiden Funktionen mit den bereits vorhandenen gebildet 
werden? Ich habe da nach Durchsicht Deiner Funktionen aber noch keinen 
Ansatzpunkt gefunden. Wäre es aufwendig, diese beiden Funktionen noch 
einzubringen? Ggf. könnte ich auch Tips gebrauchen, wie das anzugehen 
wäre. Für mich wäre das aber recht zeitaufwendig, da ich in C noch nicht 
so firm bin. Würde ich aber versuchen anzugehen.

Danke und Grüße

Ralf

von daniel (Gast)


Lesenswert?

Hallo Ralf,

wäre nicht sonderlich schwierig.
Mit den beiden vorhandenen Funktionen könnte man so etwas schon 
realisieren, komme ich aber momentan nicht dazu.
Als Hinweis wenn du da selber schonmal was machen willst, "lsRowsOfClust 
(unsigned long int start_sec)" geht durch alle Zeilen eines Clusters, ab 
dem Sektor start_sec. "ffls(void)" geht dann durch alle Cluster eines 
Ordners. Somit hat man beide logischen Strukturen abgearbeitet...

Will man jetzt wissen an welcher "Zeile" welcher Eintrag steht, müsste 
man einen Zähler haben, der von lsRowsOfClust hochgezählt wird, bis man 
an gewünschter Zeile ist.

Will man wissen wie viele Einträge es gibt, würde es reichen anstatt 
einer Ausgabe einfach mit zu zählen, wie viele Einträge ausgegeben 
werden würden.

Grüße Daniel

von elral (Gast)


Lesenswert?

Hallo Daniel,

vielen Dank, Anzahl der Dateien (über ffls) sollte wirklich gar kein 
Problem sein. Das andere muss ich mal sacken lassen :)
Werde ich mir die Tage mal anschauen.

Grüße

Ralf

von Michael P. (protactinium)


Lesenswert?

Moin,

die Lib hat mir viel Arbeit erspart. Habe sie ohne größere 
Schwierigkeiten auf einen MSP430 portieren können. Mir ist dabei nur 
eine Sache aufgefallen. Die Initialisierung der FAT erfolgt ja in 
Abhängigkiet ob "SUPERFLOPPY" 0 oder 1 gesetzt ist. Es ist aber schlecht 
vorherzusagen ob in das fertige Gerät eine Karte eingesetzt wird, die 
ein Superfloppy ist oder aber eine Partition enthält.

Habe die Initialisierung mal so geändert, das automatisch ermittelt wird 
ob ein Superfloppy vorliegt.

1
  //Sektor 0 lesen
2
  if(0==SDC_Read_Block(SDC_READ_SINGLE_BLOCK, 0, 512))
3
  {
4
    vSecOfFirstPartition = (char*)&secOfFirstPartition;
5
    //Startsektor bestimmen
6
    *(char*)vSecOfFirstPartition++=fat.sector[454];
7
    *(char*)vSecOfFirstPartition++=fat.sector[455];
8
    *(char*)vSecOfFirstPartition++=fat.sector[456];
9
    *(char*)vSecOfFirstPartition++=fat.sector[457];
10
    //Prüfung ob man schon im VBR gelesen hat (0x6964654d = Medi)
11
    if(secOfFirstPartition==0x6964654d)
12
      return fat_loadFatData(0);  //Superfloppy liegt vor
13
    else
14
      //FAT-Daten aus dem ersten Sektor der Partition lesen
15
      return fat_loadFatData(secOfFirstPartition);
16
  }
17
  return (1);

Wenn man also eine Karte ausliest und man ist gleich im VBR, dann liest 
man ja innerhalb dieses Abschnittes: "Datentr„ger entfernenÿ 
Medienfehlerÿ Neustart: Taste drcken". An den Positionen 454 - 457 
steht "Medi", was der Sektoradresse 1768187213 entspricht. Diese 
Sektoradresse gibt es bei keiner bisher verfügbaren SD - Karte, weshalb 
man damit auf Superfloppy prüfen kann.

mfg
Michael

von Daniel R. (zerrome)


Lesenswert?

Hallo, sehr schön.

Hatte ich auch immer mal vor das einzubauen, bin aber nicht dazu 
gekommen.
Wird in die nächste Version aufgenommen.

Grüße Daniel

von siegmar (Gast)


Lesenswert?

Hallo Michael,

hab auch schon daran gedacht die Lib auf den MSP430 zu portieren.
Leider noch keine Zeit gehabt.
Hast Du vor, die an den MSP430 angepaßte Lib zu veröffentlichen ?
Noch einen schöne Tag
MfG
Siegmar

PS: Nochmals: Tolle Arbeit von Daniel !!!!!

von zerrome (Gast)


Lesenswert?

Hallo zusammen,

das mit dem veröffentlichen für MSP wird wohl nix werden ^^

Anzupassen wären aber ja eigentlich nur die mmc low level Routinen.
Also die SPI Geschichten.
Hab leider keine Ahnung vom MSP daher schwer abzuschätzen wie viel 
Arbeit das wirklich ist...

Grüße Daniel

von Michael P. (protactinium)


Lesenswert?

Moin,

die meiste Arbeit haben die Routinen für das Lesen und Schreiben der 
SD-Karte gemacht (wegen neu schreiben und so). Bei den FAT- und 
Dateifunktionen habe ich erstmal nur die Void-Pointer (die ICC430 
Version die ich nutze kann damit nicht um), die ganzen Zählvariablen 
angepasst und natürlich die Funktionsaufrufe der Low-Level-Routinen 
geändert. Eben um zu sehen ob es funktioniert. Und es funtkioniert.

Weitere Anpassungen sind sicherlich noch möglich, mach ich irgendwann 
auch noch.

Michael

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

hier mal eine neue Version, gab da noch Bugs...
Zudem ist die SPI schreiben Routine schneller geworden.
Generell kompakterer Code.

Viel Spaß damit :)

Grüße Daniel

von Daniel R. (zerrome)


Lesenswert?

Ach ja, Wiki auch aktualisiert...

http://www.mikrocontroller.net/articles/AVR_FAT32

von Daniel R. (zerrome)



Lesenswert?

Und hier noch der Wiki Artikel als PDF, zum offline lesen :)

von Steffen K. (steffen3)


Lesenswert?

Hallo,
zuerst einmal ein Dank an Daniel dafür, dass er seinen Code hier 
veröffentlicht hat. Ich möchte sein Beispiel nun bei mir lauffähig 
bekommen, es funktioniert aber nicht. Auf der UART-Ausgabe sehe ich, 
dass nach mmc_init() nichts mehr passiert, es muss also ein Fehler in 
fat_initfat() auftreten. Ich verwende eine microSD Karte mit 128MB, die 
ich per Windows als FAT formatiert habe. Wo müsste ich wohl ansetzen um 
den Fehler zu finden?

von Daniel R. (zerrome)


Lesenswert?

Hallo,

wie ist denn die Karte am Controller angeschlossen?
Hast Du etwas am Code geändert?

Du siehst auf dem Terminal "Boot..." und das OK fehlt? Man sollte wenn 
alles richtig initialisiert wird ja "Boot...OK" sehen. Wenn das OK fehlt 
hängt sich das Programm tatsächlich beim Fat auslesen auf. Interessant 
wäre da der Sektor 0 der Karte.
Oder Du könntest einfach mal probieren ob es FAT32 Formatiert klappt, 
ich glaube bei Windows bedeutet nur Fat FAT16 und sonst halt FAT32.

Grüße Daniel

von Steffen K. (steffen3)


Angehängte Dateien:

Lesenswert?

Da ich einen atmega328p verwende, habe ich die mmc.h verändert.
CLK von der Karte habe ich über einen HEF4050 mit SCK am µC verbunden, 
DI auch über HEF4050 an MOSI, CS mit pull-up über HEF4050 an PB1 und DO 
mit pull-up direkt an MISO. An anderen Stellen habe ich nichts im Code 
verändert. Ja es erscheint wirklich nur Boot... . Im Anhang ein Bild vom 
Sektor0, nach dem Versuch darauf zu schreiben.

von Daniel R. (zerrome)


Lesenswert?

Hallo,
also die Karte ist unpartitioniert. Versuch mal folgenden Code, damit 
man feststellen kann ob es an der fat_initfat() liegt oder schon 
woanders hakt.
1
void main(void){
2
  char tmp[10];
3
4
  uinit();
5
6
 
7
  uputs((unsigned char*)"\nBoot");
8
9
  while (mmc_init() !=0){ ;}  
10
  
11
  uputs((unsigned char*)"... ");    
12
13
  fat_loadFatData(0); // läd fat daten
14
15
  
16
  ultoa(fat.rootDir,tmp,10);
17
  uputs(tmp);      
18
  uputc(' ');
19
20
  utoa(fat.secPerClust,tmp,10);
21
  uputs(tmp);      
22
23
}

Jetzt müsste wenn alles funktioniert, "Boot...2 2" zu sehen sein.
Wenn dem so ist muss ich mir die fat_initfat() nochmal genauer 
anschauen.
Wenn nicht, liegt das Problem irgendwo ganz anders. Da würde ich eher 
auf ein Hardware Problem schließen.
Im Datenblatt von dem HEF4050 steht nichts von Versorgungsspannung ab 2 
Volt wie bei dem HC4050, was bei niedrigeren Frequenzen vielleicht noch 
klappt aber dann nach der Karten Initialisierung mit vollem SPI speed 
nicht mehr...

Grüße Daniel

von Steffen K. (steffen3)


Lesenswert?

Als Ausgabe erhalte ich "Boot..." und manchmal "Boot... 0 0" und einmal 
wurde sogar die txt-Datei erstellt, es liegt also an der Hardware. Eine 
2Gb Karte habe ich damit wohl schon zerstört, zumindest reagiert Windows 
nicht mehr, wenn ich die Karte einlege. Aber das die Karte 
unpartitioniert ist verstehe ich nicht, habe es im Arbeitsplatz per 
Rechtsklick und dann auf Formatieren formatiert. Ich werde dann mal die 
74HC4050 von reichelt bestellen und alles neu aufbauen. Schonmal danke 
für die schnelle Hilfe.

von Daniel R. (zerrome)


Lesenswert?

Mir ist noch keine einzige Karte kaputt gegangen bei meinen Tests. Ich 
nehmen aber auch immer sofort den Strom weg, wenn was unvorhergesehenes 
passiert.

Unpartitioniert ist ja nicht unformatiert. Keine Ahnung warum Windows 
mal ne Partition erstellt und mal nicht. Glaube bei kleineren Karten 
wird nicht partitioniert und bei größeren schon.

Du könntest aber auch mal den SPI speed runter setzen und schauen ob es 
dann mit deiner Hardware stabiler läuft.
Einfach in der mmc.c in der Funktion mmc_init () die Zeilen
1
  //SPI Bus auf max Geschwindigkeit
2
  SPCR &= ~((1<<SPR0) | (1<<SPR1));
3
  SPSR = SPSR|(1<<SPI2X);

auskommentieren.

Bei deiner Karte die nicht mehr funktioniert, könnte es sein das die 
mehr als 3,3 Volt abbekommen hat? Mach doch mal ein Foto von der 
Schaltung :)


Grüße Daniel

von Steffen K. (steffen3)


Lesenswert?

Es liegt tatsächlich an dem Speed der SPI, habe es wohl etwas zu frei 
aufgebaut^^, aber jetzt funktioniert es endlich . DANKE;-)

von Daniel R. (zerrome)


Lesenswert?

Schön das es jetzt läuft :)

von Max P. (eizo)


Lesenswert?

Unterstützt das Programm auch Software SPI oder muss man den Hardware 
SPI nutzen?

von Steffen K. (steffen3)


Lesenswert?

ich glaube nur hardware SPI, aber eine software SPI kann man relativ 
leicht implementieren.

von Steffen K. (steffen3)


Angehängte Dateien:

Lesenswert?

ungetest stelle ich hier mal die software SPI rein.

von Steffen K. (steffen3)


Angehängte Dateien:

Lesenswert?

Dieses Mal hoffentlich ohne Fehler.

von Johannes N. (strangeman)


Lesenswert?

Hallo mal wieder!

Ich bastel im Moment wieder mit dem SD-Code rum. Soweit alles in 
Ordnung. Allerdings ist file.seek bei mir immer Null. Das darf aber 
eigentlich nicht sein. Mein Code:
######################################################################## 
#
int main(void) {

  char *tag;
  char *value;
  char s[10];

  lcd_init();
  lcd_clear();

  sd_init();

  lcd_clear();

  tag = malloc(30);
  value = malloc(30);

  char mfile[] = "testdat.txt";
  fat_str(mfile);
  ffopen(mfile);

  // Länge der Datei ausgeben
  lcd_string("L: ");
  lcd_string(itoa(file.length, s, 10));
  lcd_set_cursor(0,1);
  // Position ausgeben
  lcd_string("S: ");
  lcd_string(itoa(file.seek, s, 10));
  _delay_ms(2000);


  while (file.seek <= file.length) {
    tag[0] = '\0';
    value[0] = '\0';

    lcd_clear();
    tpx_read_tag(tag, value);
    lcd_string("T: ");
    lcd_string(tag);
    lcd_string("; S: ");
    lcd_string(itoa(file.seek, s, 10));
    lcd_set_cursor(0,1);
    lcd_string("V: ");
    lcd_string(value);
    _delay_ms(1000);
  }


  ffclose();

  while(1);

  return 0;
}
######################################################################## 
#
tpx_read_tag ist eine funktion von mir, die eine Art pseudo-xml 
realisiert nach dem Muster <tagname=wert>.
Ich brauche file.seek, damit das Auslesen irgendwann mal aufhört.

Noch etwas, ich bekomme warnings:
"./sd/fat.c:96: warning: left shift count >= width of type"

Bis denn dann,
StrangeMan

PS: Am Software-SPI wäre ich auch sehr interessiert! =)

von Daniel R. (zerrome)


Lesenswert?

Hallo,

also so ist file.seek nicht gedacht.
Es wird beim lesen garnicht verwendet. Wenn du bis zum Datei Ende lesen 
möchtest ist die schnellste Variante:
1
unsigned long int seek=file.length;
2
3
do{
4
5
   code zum lesen...
6
7
}while(--seek);

Da so nur geprüft wird ob seek==0 ist als Abbruchbedingung...

Zu dem angesprochenen warning, das hab ich auch, allerdings "nur" beim 
avr-gcc, dem normalen gcc macht das nix. Also hat keine Probleme gemacht 
bei mir. Und den left shift muss man so machen...

Grüße Daniel

von Johannes N. (strangeman)


Lesenswert?

Und wenn ich in dem Moment gar nicht weiß, wo sich der "Cursor" in der 
Datei befindet?
Hmm, da bleibt mir wohl nichts übrig als mir eine globale Variable zu 
machen, die mitloggt, wo ich bin.

von Daniel R. (zerrome)


Lesenswert?

Wie wäre es mit der Variablen seek aus meinem Beispiel?

Ich habe extra darauf verzichtet in ffread() eine 32 Bit variable wie 
file.seek bei jedem einzelnen Byte das gelesen wurde zu ändern...das 
würde bremsen! Besser ist es da die Laufindex Variable (aus dem Beispiel 
eben, seek) beim Aufruf von ffread() zu benutzen.

Wozu genau willst du denn die exakte Position in der Datei wissen?

Und wie gesagt, was spricht gegen die Variable seek?

Grüße Daniel

von StrangeMan (Gast)


Lesenswert?

Hmm, ich hab ein Menüsystem, was auf Basis oben genannter 
Pseudo-XML-Tags die Menüeinträge ausließt. Wenn ich eine Funktion habe, 
die nur einen Tag auslesen soll, dann hat die ja keine Ahnung, wo in der 
Datei sie auszulesen beginnt, wenn ich sie aufrufe. Sie darf aber 
dennoch nicht über das Dateiende hinauslesen. Wenn ich das so amche, wie 
im Code oben, dann kann es ja sein, dass sie erst beim 100ertsten Byte 
anängt zu lesen, weil der "Cursor" da grade war. Dann würde sie 100 
Bytes üebr das Dateiende hinauslesen. Was da bei rauskommt habe ich 
schon gesehen... Zufallsdatan - mehr oder weniger.
Aber ich habs jetzt so gelöst, dass ich einfach mitlogge, wo ich bin. 
Bei jedem ffread() oder ffseek() aktualisiere ich meine globale Varable 
eben.

Das Geschwindigkeitsproblem ist natürlich ein Argument. Aber eventuell 
kann man so eine Seek-Variable als Compilerschalter mit einbauen. Dann 
kann man's aktivieren, wenn es benötigt wird. Ich denke, für komplexere 
Dinge ist sowas schon von Nöten.

StrangeMan

von Daniel R. (zerrome)


Lesenswert?

Ok, überlege ich mal wie man sowas elegant machen kann.

Du könntest ja aber einfach file.seek benutzen anstelle deiner globalen 
variable. Wie das dann mit der Geschwindigkeit aussieht müsste man mal 
sehen. ffseek() updatet dir file.seek ja auch wenn du vor oder zurück 
spulst. Kleines Beispiel:
1
for(file.seek=0;file.seek<file.length;file.seek++){
2
3
//code zum lesen...
4
//eventuell sogar ffseek() da dies ja file.seek auch updatet...
5
6
}

Grüße Daniel

von Johannes N. (strangeman)


Angehängte Dateien:

Lesenswert?

Hallo mal wieder.

Ich hab die mcc.c/mcc.h von Ulrich Radig rausgekramt und den 
Software-SPI-Modus von ihm wieder übernommen. Allerdings ... naja, es 
klappt nicht, und ich weiß nicht, obs an meiner Hardware oder am Code 
liegt. Ich hab meine Version der mcc.c mal angehängt. Eigentlich kann 
man ja nichts falsch machen. Offensichtilich aber doch...

StrangeMan

von Johannes N. (strangeman)


Angehängte Dateien:

Lesenswert?

Ohje, entschuldigt. Die Zeile, in der der Hardware-SPI eingerichtet 
wird, gehört natürlich entfernt. (nach Zeile 50: stattdessen
1
  #if SPI_Mode
2
3
    //Aktiviren des SPI - Bus, Clock = Idel LOW
4
5
    //SPI Clock teilen durch 128
6
7
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1); //Enable SPI, SPI in Master Mode  
8
9
  #endif
 einfügen).

Anbei auch noch meine mmc.h. Die Pins habe ich in einer anderen 
headerdatei. Sie sind
1
#define SD_INSIDE_PORT         PORTA
2
#define SD_INSIDE_PIN         PINA
3
#define SD_INSIDE_DDR         DDRA
4
#define SD_INSIDE_Pin         PA0
5
6
#define SD_WRITEPROT_PORT       PORTA
7
#define SD_WRITEPROT_PIN       PINA
8
#define SD_WRITEPROT_DDR       DDRA
9
#define SD_WRITEPROT_Pin       PA2
10
11
#define SD_PORT            PORTA
12
#define SD_P_IN            PINA
13
#define SD_DDR            DDRA  
14
15
#define SD_DI            PA3    
16
#define SD_DO            PA6    
17
#define SD_SCK            PA1  
18
#define SD_SS            PA7

Grüße,
StrangeMan

von FlipFlop (Gast)


Lesenswert?

Ich könnte mir vorstellen, dass es am Timing liegt, da überhaupt keine 
delays in der SOFT-SPI sind, vielleicht einfach mal ein paar Pausen 
einfügen.

von Johannes N. (strangeman)


Lesenswert?

Ja, danke, das klappt. Da die Routinen so bei Ulrich Radig wohl auch 
gehen, dachte ich, das wär in Ordnung so.
Damit geht's erstmal:
1
//############################################################################
2
3
//Routine zum Empfangen eines Bytes von der MMC-Karte 
4
5
unsigned char mmc_read_byte (void)
6
7
//############################################################################
8
9
{
10
  unsigned char Byte = 0;
11
#if SPI_Mode  //Routine für Hardware SPI
12
  SPDR = 0xff;
13
  while(!(SPSR & (1<<SPIF))){};
14
  Byte = SPDR;
15
16
#else      //Routine für Software SPI
17
  for (unsigned char a=8; a>0; a--) //das Byte wird Bitweise nacheinander Empangen MSB First
18
    {
19
20
    SD_PORT &=~(1<<SD_SCK); //erzeugt ein Clock Impuls (Low) 
21
    _delay_us(1);
22
    if (bit_is_set(SD_P_IN,SD_DI) > 0) //Lesen des Pegels von MMC_DI
23
        {
24
        Byte |= (1<<(a-1));
25
        }
26
      else
27
        {
28
        Byte &=~(1<<(a-1));
29
        }
30
    SD_PORT |=(1<<SD_SCK); //setzt Clock Impuls wieder auf (High)  
31
    _delay_us(1);
32
    }
33
#endif
34
  return (Byte);
35
}
36
37
38
//############################################################################
39
//Routine zum Senden eines Bytes zur MMC-Karte
40
void mmc_write_byte (unsigned char Byte)
41
//############################################################################
42
{
43
#if SPI_Mode    //Routine für Hardware SPI
44
  SPDR = Byte;   //Sendet ein Byte
45
  while(!(SPSR & (1<<SPIF))) //Wartet bis Byte gesendet wurde
46
  {
47
  }
48
#else      //Routine für Software SPI
49
  for (unsigned char a=8; a>0; a--) //das Byte wird Bitweise nacheinander Gesendet MSB First
50
  {
51
    _delay_us(1);
52
    if (bit_is_set(Byte,(a-1))>0)  //Ist Bit a in Byte gesetzt
53
        {
54
        SD_PORT |= (1<<SD_DO); //Set Output High
55
        }
56
      else
57
        {
58
        SD_PORT &= ~(1<<SD_DO); //Set Output Low
59
        }  
60
    SD_PORT &= ~(1<<SD_SCK);  //erzeugt ein Clock Impuls (LOW)
61
    _delay_us(1);
62
    SD_PORT |= (1<<SD_SCK); //setzt Clock Impuls wieder auf (High)
63
  }
64
  SD_PORT |= (1<<SD_DO);  //setzt Output wieder auf High  
65
#endif
66
}
Ob das Timing so ideal ist, sei dahingestellt. Ich werde nochmal die 
Spezifikationen anschauen, aber das mache ich später.

Danke,
StrangeMan

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Neue Version !

Überarbeitete mmc.c und Optimierung des Codes.

Jetzt auch Multiblock Operationen möglich. Wird allerdings nicht von 
allen Karten unterstützt, daher optional als define wählbar.

Neuere Doku wird nachgereicht.
Wird wie immer hier nachzulesen sein: 
http://www.mikrocontroller.net/articles/AVR_FAT32


Grüße Daniel

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

So,
hier noch die Version als AVR-Studio 4.17 Projekt.

Grüße Daniel

von Michael Z. (incunabulum)


Angehängte Dateien:

Lesenswert?

Daniel,

ich hab mir heute mal die neue Version deiner Lib zu Gemüte geführt. Wie 
auch die alten Versionen funktioniert das auf einem zur Zeit in der 
Mache befindlichen Alleskönner-Board wie geschmiert. Super Arbeit!

Und - wie bereits letztes Jahr - ich hab mal wieder ein paar Ideen, die 
die Lib noch besser machen könnten. Für mich natürlich :-)

1) Sinnvolle Rückgabewerte
Viele Methoden geben unsigned chars für Statusinformationen zurück. 
Sowas in etwa:
1
 if(2==ffopen("TEST    TXT")) { ... }
Hier würde ich mir defines wünschen, die eben diese Statusinformationen 
sprechend bezeichnen. Sowas z. B.
1
 #define MMC_FILE_NEW 2 
2
 if(MMC_FILE_NEW == ffopen("TEST    TXT")) { ... }

Gibt es eigentlich eine Doku für diese Return-Values?

2) Uart-Funktionen per Config einstellen
Das hatte ich mir ja schon oben gewünscht, da ich ansonsten jedesmall 
die Sourcen ändern muss.

3) Status-Signale der SD-Card
Bei den meisten Kartenslots kann man neben den wichtigen Pins auch 
auslesen, ob eine Karte eingelegt ist und ob diese schreibgeschützt ist. 
Wär doch schön, wenn wie die Lib von Roland Riegel, das auch 
berücksichtigt werden könnte.

Alle Config-Optionen in eine separate Config-Header-Datei geschrieben 
sieht dann so aus, wie im Anhang zu finden. Die SPI-Pins etc. ziehe ich 
mir aus einer globalen Hardware-Header für SPI. Die Defines für die 
Statusinformationen könnten wohl auch woanders hin.

cu, Michael

von Daniel R. (zerrome)


Lesenswert?

Hallo,
bin immer offen für Anregungen :)

-1.) Mich hat es Tatsache auch schon öfters genervt das man einer 2 
nicht ansieht was es genau bedeutet... werde ich ändern.

Störend ist nur, dass z.B. folgendes "define TRUE 1" 2 Byte Ram frisst 
wenn man "TRUE" irgendwo im Code nutzt. Mir war nie die Idee gekommen 
"define TRUE '1'" zu machen :) ist dann nur ein 1 Byte ...

-2.) Da fällt mit keine tolle Lösung ein, na ja mal sehn...

-3.) Ich hab so nen Kartenslot nicht, daher kann ich das schlecht 
testen, müsste mir mal so nen Slot besorgen :)

Software SPI möchte ich dann auch noch mich rein packen ins nächste 
Release.


Grüße Daniel

von Winne (Gast)


Lesenswert?

Wie wäre es "True" als Bit  anzulegen

gegebenenfalls mehrere Bitvarriablen/konstanten zu einem Byte zu fassen?

von Michael Z. (Gast)


Lesenswert?

Moin Daniel,

> Störend ist nur, dass z.B. folgendes "define TRUE 1" 2 Byte Ram frisst
> wenn man "TRUE" irgendwo im Code nutzt. Mir war nie die Idee gekommen
> "define TRUE '1'" zu machen :) ist dann nur ein 1 Byte ...

Ist dem wirklich so? Bis heute dachte ich, dass defines nur durch den 
Präprozessor verwendet zum ersetzen herangezogen werden und erst danach 
der compiler einspringt...

Zum Uart:
Für dich relevant sind ja nur 3 Infos zum Uart. Include-Statement, 
uputs, uputc. Ich (als Freund der #defines würde das dann wieder per 
config-Option lösen. Also:
1
#define UART_INCLUDE  /path/uart.h
2
#define UART_UPUTS uputs
3
#define UART_UPUTC uputc
und dann im Code die ensprechenden defines statt der echten Namen 
verwenden.

Zu 3 - Status Info:
Hier müsste man überlegen, wie weit man wirklich dies durchgängig 
implementieren will. Reicht es, wenn man entsprechende Methoden zum 
Abtesten anbietet, den eigentlichen Test aber dann den Nutzer 
durchführen lässt? Oder nur bei mmc_init()? Oder sollen alle Lese- bzw. 
Schreiboperationen jeweils isAvailable4() oder isProtected() aufrufen? 
Letzteres eher nein, so würde ich denken.

cu, Michael

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Hallo,
hier mal ein kleines Update. Der Code ist nur auf anständige Return 
Werte umgestellt. Keine Funktionalen Änderungen.

>Ist dem wirklich so?
Ich dachte immer das wenn man "#define KONSTANTE 1" macht, wird das als 
Integer behandelt bei der Erzätzung im Code durch den 
Präprozessor...deshalb hab ich die defines jetzt einfach mal alle als 
chars gemacht, kann ja nicht schaden ^^

Zum Uart, zufriedener jetzt ?

Hast Du so einen Slot und wärst eventuell bereit die Funktionen zu 
schreiben und testen? Ich nehme die dann in die Lib auf. Stimme da 
nämlich bei Deine Überlegungen zu.

@Winne
Das müsste man ja dann als struct machen, und ich weiß nicht mehr warum, 
aber das ist wohl nicht so toll...
Vielleicht weiß da ja einer warum ?!?

Grüße Daniel

von Michael Z. (incunabulum)


Lesenswert?

Moin Daniel

> hier mal ein kleines Update. Der Code ist nur auf anständige Return
> Werte umgestellt. Keine Funktionalen Änderungen.

Wunderbar. Genau so etwas meinte ich. Wie sieht es bei ffopen im 
OVERWRITE Modus aus? Wird hier auch OPENED_TO_WRITE zurückgeliefert?

> Zum Uart, zufriedener jetzt ?

Fast :-) Die Defines wie auch eine globale COnfig-Datei sind klasse. 
Fehlt nur noch, dass die Quellen mmc.c und file.c auf die neue 
uart-syntax angepasst werden :)


> Hast Du so einen Slot und wärst eventuell bereit die Funktionen zu
> schreiben und testen? Ich nehme die dann in die Lib auf. Stimme da
> nämlich bei Deine Überlegungen zu.

Ich hab so einen Slot und ja, ich könnte dies ausprobieren und 
entsprechend implementieren. Das ganze würde dann über zwei Funktionen 
in mmc.h / mmc.c implementiert werden. Nämlich:
- u08 mmc_present()
- u08 mmc_protected()

Diese kann der User nach belieben selber aufrufen. Ausserdem werden 
diese in mmc_init() mit aufgenommen. Sollte keine Karte vorhanden sein 
bzw (bei write-Funktionalität)  diese schreibgeschützt sein, so werden 
entsprechende Status-Codes zurückgeben. Das ganze wird natürlich per 
#define abschaltbar :-) Und je nachdem, ob write-Support drin ist oder 
nicht, werden nur die erforderlichen Methoden kompiliert.

Da ich nur am WoE zum Testen komme kann das ganze aber doch 2 bis max. 3 
Wochen dauern. Geht halt nicht schneller

cu, Michael

von Michael M. (mikmik)


Lesenswert?

Erstmal danke für die Lib, funkt sehr gut bei mir. Nur eines, was es 
vielleicht Anfängern erleichtern könnte:
In der mmc.h steht:

#if defined (_AVR_ATmega16_)
  #define SPI_DI    6  //Port Pin an dem Data Output der MMC/SD-Karte 
angeschlossen ist
  #define SPI_DO    5  //Port Pin an dem Data Input der MMC/SD-Karte 
angeschlossen ist
...

Der Satz "Port Pin an dem Data Output der MMC/SD-Karte angeschlossen ist 
" drückt, denk ich, das Gegenteil von dem aus, was er sagen soll. Weil 
SPI_DI ("Data in") der MOSI pin ist, also der Data Output vom Master und 
nicht von der Karte. Vice versa für SPI_DO.

Vielleicht kann man einfach MOSI/MISO/SCK/.... in die Comments 
schreiben.
Nur so als Vorschlag.
Danke nochmal,
mik

von StrangeMan (Gast)


Lesenswert?

Naja, ich dachte da ist der DataIn der Karte gemeint. Aber MOSI/MOSI 
wäre sicherlich eindeutiger.
Eine globale Configdatei würde ich auch befürworten. Ich habe sie mir 
für mein Projekt selbst angelegt, weil ich da sehr viele verschiedene 
Defines habe, die ich zentral editieren können will. Wenn man auch in 
diesem Code hier eine globale Configdatei macht, ließe sich deren 
Include-Anweisung einfach rauskommentieren um eine eigene Configdatei zu 
erwenden.

StrangeMan

von Michael M. (mikmik)


Lesenswert?

HAllo, falls es wer brauchen kann, oder vielleicht kann man es überhaupt 
in die Lib aufnehmen: habe ein file-exists geschrieben:

für die file.c
1
unsigned char ffexists( unsigned char name[]){
2
  unsigned char file_flag=fat_loadFileDataFromDir(name);    
3
  if( file_flag==0 ){return 1;}  //Datei existiert!
4
else {return 0;}
5
}

und für die file.h
1
 extern unsigned char ffexists( unsigned char name[]);

have fun,
MM

von Daniel R. (zerrome)


Lesenswert?

Hallo, zusammen.

@Michael Z. (incunabulum)
Ja wäre cool wenn du das so machst mit dem Slot. Eilt auch nicht so ...

@StrangeMan (Gast)
Die mmc-0.5.5.1.zip hat schon eine solche config.h

@ Michael M. (mikmik)
Du benutzt nicht die Version mmc-0.5.5.1.zip ?
Da ist zwar die Dokumentation in der mmc.h noch nicht auf MISO/MOSI usw 
umgestellt aber mit den defines ist es einfach übersichtlicher

Man könnte das noch etwas verkürzen:
1
unsigned char ffexists( unsigned char name[]){
2
  return fat_loadFileDataFromDir(name);    
3
}

Und als Abfrage:
1
if(TRUE==ffexists((unsigned char*)"MAIN    C  "){
2
3
   irgendwas machen
4
}

Da das ja aber eigentlich nur eine Zeile ist und man sich wenn man das 
direkt machen würde wie z.B :
1
if(TRUE==fat_loadFileDataFromDir((unsigned char*)"MAIN    C  "){
2
3
   irgendwas machen
4
}

auch eine Funktionsaufruf spart hatte ich das nicht extra geschrieben :)
Ist zwar fragwürdig ob man bei sowas sparen muss aber egal.


Grüße Daniel

von Daniel R. (zerrome)


Lesenswert?

Ach ja, was mir da noch einfällt,
wenn man im Überschreibenmodus eine Datei öffnet bekommt man auch 
OPENED_TO_READ zurück. Es gibt die Datei ja schon die man überschreiben 
möchte. Wenn man sich einmal für OVER_WRITE entschieden hat, kann man 
wild in der Datei rumschreiben...

Grüße

von Michael Z. (incunabulum)


Angehängte Dateien:

Lesenswert?

Moin Daniel,

hier also die entsprechende Erweiterung deiner Lib. Status-Pins (card 
present, card protected) werden nun berücksichtigt, so entsprechend in 
config.h aktiviert. Die wichtigen Änderungen meinerseits findest du nach 
dem Tag // mz:

Die eigentliche Konfiguration erfolgt in mmc.h unten. Dort werden die 
Pins etc. entsprechend gesetzt. Das ist fast 1:1 von Roland Riegel 
kopiert. In mmc.c sind dann die entsprechendne Methoden definiert und in 
mmc_init() eingebunden.

Anmerkungen:

0) Ich habe einige zusätzliche Return-Werte mittels Define gesetzt. Das 
macht die Lib imho lesbar. Fehlt nur noch die Doku :-)

1) FALSE sollte immer (int) 0 sein. Ansonsten ist ein Test über 
if(someBoolMethod()) nicht möglich, sondern es wird immer ein expliziter 
Vergleich if(true==...) benötigt.

2) defines: Ich habe mal alle Defines umgeändert, so dass diese immer 
als Präfix MMC_ aufweisen. Dies ist gängige Syntax, da man hierdurch im 
Code zumindest erraten kann, welches Define für was herangezogen wird. 
Oder wüsstest du, woher WRITE kommt, so diese Directive in  main() 
vorkommt?

2b) OPENED_TO_READ und OPENEND_TO_WRITE sind imho nicht ganz korrekt. 
Siehe die Problemtatik bem überschreiben. Ergo habe ich diese wieder 
unbenannt zu MMC_FILE_NEW, MMC_FILE_EXISTS. Das trifft die Tatsache 
besser, denke ich.

Comments?

cu, Michael

von Daniel R. (zerrome)


Lesenswert?

Hallo,
ja sieht soweit gut aus.
In der SdCard.h ist das c++ ? Da steht was von namespace ?!?
Hatte jetzt noch nicht die Zeit mir alles mal genauer zu Gemüt zu 
führen, mache ich aber heute Abend.

Zu den defines,
FILE_NEW und FILE_EXISTS find ich gut.
Allerdings hast du ja jetzt alle defines in MMC_xxx umbenannt. Bringt 
also genau so viel wie gar kein Präfix, oder hab ich da was falsch 
verstanden? Außerdem gibt es defines die in allen Dateien vorkommen wie 
z.B. MMC_WRITE (alias WRITE) auf was sollte man sich da jetzt festlegen?
Werde das aber aufgreifen und mal sehen ob man das nicht noch etwas 
bessert ordnen kann.
Generell, wenn man etwas in Großbuchstaben sieht ist es ein define und 
die sind immer in der config.h, das ist doch auch schonmal was :)

Danke für die Hilfe und Mitarbeit.

Grüße Daniel

von Michael Z. (incunabulum)


Lesenswert?

Moin Daniel,

ja, da ich komplett mit C++ entwickel, ist die SdCard.h ein einfacher 
Wrapper für CPP. Das kannst du also ignorieren. Dieser packt die ganze 
MMC-Funktionen in einen eigenen Namespace und verwendet eine 
Methodenbennenung, wie ich sie sonst verwende. Also Camel-Case anstatt 
Unterstriche.

> Zu den defines,
> Allerdings hast du ja jetzt alle defines in MMC_xxx umbenannt. Bringt
> also genau so viel wie gar kein Präfix, oder hab ich da was falsch
> verstanden?

Ich glaube ja. Nem mal an, dass du zwei Libs verwendest. a) Deine MMC 
und b) eine EEPROM Lib. Beide definieren ein #define WRITE. Solltest du 
nun in main() beide Libs importieren, so hast du das Problem, dass WRITE 
aus der mmc oder der EEPROM lib kommen kann. Weiterhin kann es sein, 
dass diese auch noch mit unterschiedlichen Werten definiert ist. Und 
dann?

So, wie ich deine Lib sehe, wird das Problem nicht auftreten, da eben 
config.h nur von den mmc-headern und sourcen und nicht von "extern" 
included wird. Dennoch finde ich es für den Fall, dass dies aus 
"Dummheit" doch jemand machen sollte, eine gute Idee, die Quelle durch 
das MMC_ Präfix deutlich zu machen.

> Außerdem gibt es defines die in allen Dateien vorkommen wie
> z.B. MMC_WRITE (alias WRITE) auf was sollte man sich da jetzt festlegen?

Äh, das Präfix MMC bedeutet (imho) nicht, dass diese aus der MMC.h 
stammt, sondern dass es ein define aus deiner mmc-lib ist. So hab ich 
mir das jedenfalls gedacht :-)


> Generell, wenn man etwas in Großbuchstaben sieht ist es ein define und
> die sind immer in der config.h, das ist doch auch schonmal was :)

Jenau :)

> Danke für die Hilfe und Mitarbeit.

Ich will ja auch was :-) Nämlich die Funktionen die ich brauch und zwar 
ohne manuelles Merging bei folgenden Versionen

cu, Michael

von Matze N. (hupe123)


Lesenswert?

Hi,

ich wollte eben die neuste Version der SD-Kartenroutine ausprobieren und 
bin erschrocken!
Warum ist eine UART Routine mit in das Gefecht eingewoben worden?! Macht 
das Sinn?
Ich verpacke doch auch nich in eine UART-Routine ein I²C, nur weil ichs 
kann.
Das is doch am Thema vorbei, ober sehe ich das Falsch?

Gruß

von Daniel R. (zerrome)


Lesenswert?

Hallo,
bin immer noch nicht dazu gekommen mir alles anzusehen, aber so viel 
wurde ja auch nicht geändert...

>Warum ist eine UART Routine mit
>in das Geflecht eingewoben worden?!
>Macht das Sinn?

Wie meinst du das ?

Es sind ja in der config.h nur defines dazugekommen, mit denen man seine 
eigene uart lib einbinden kann...

Grüße Daniel

von Matze N. (hupe123)


Lesenswert?

Aber warum generell UART in einer SD-Karten-Routine?
Soll diese Routine nicht nur und ausschließlich für SD-Karten sein?
Das bläht das ding nur unnötig auf und wer eine UART überwachung haben 
will, der kann das doch auch selber, z.b. in seine main.c, schreiben. 
Ich wundere mich bloß warum in der file.c in zeile 210 plotzlich der 
dateiname ausgegeben werden soll. wenn ich an meinen UART-Pins aber 
andere bausteine angeschlossen hab als ein max232, dann kriege ich 
dadurch probleme!

deswegen: warum diese feste UART einbindung?

von Daniel R. (zerrome)


Lesenswert?

Stimmt schon, müsste nicht unbedingt rein, aber das ist als Beispiel 
gedacht.
Die meisten werden wohl den UART angeschlossen haben um sich z.B. mal 
Debug Ausgaben zu machen, oder für Bootloader.
Mach "MMC_SMALL_FS TRUE" und du bist den UART los.
Funktionen wie ffls, also anzeigen von Dateien eines Verzeichnisses, 
leben nunmal von der Ausgabe auf eine Anzeige, in diesem Fall die 
UART...

Grüße Daniel

von Matze N. (hupe123)


Lesenswert?

Naja, aber für eine allgemeingütige routine sollte sie doch so allgemein 
wie möglich gahalten sein, oder?

von Daniel R. (zerrome)


Lesenswert?

Aber wie soll man denn den Fall ffls umschiffen? Geht numnal nicht ohne 
Ausgabe. Vorschläge?

von Matze N. (hupe123)


Lesenswert?

Man könnte die Dateinamen mit der Anzahl n und die Größe in zwei Arrays 
schreiben, z.B. dateien[n*8], groesse[n] und die zwei per Pointer 
zurückgeben.
Dann kann man, wie man will, sich sie per UART, LCD oder sonstwie 
ausgeben lassen:
1
for (int i=0;i<8,i++) uart_putc(dateien[i]);
 wäre der erste dateiname
1
for (int i=11;i<19,i++) uart_putc(dateien[i]);
 wäre der zweite dateiname
usw.

die größe natürlich äquivalent.

oder man schreibt die funktion so um, daß´sie immer nur einen dateinamen 
zurück gibt, beim nächsten aufruf den zweiten, ... nachdem der letzt 
ausgegeben wurde eine NULL zurückkgibt.
Für die Dateigröße eine zweite funktion, die das selbe macht.

Damit wären die speicherfressenden arrays von meiner ersten idee 
umgangen und man kann die rückgabewerte auf LCD, UART etc ausgeben.

grußm
matze

von Matze N. (hupe123)


Lesenswert?

oh, ich wollte eben mal das sample compilieren. ich bekomme fehler:

Compiling: main_simple.c
avr-gcc -c -mmcu=atmega32 -I. -gdwarf-2   -O2 -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -mcall-prologues 
-ffreestanding  -Wall -Wstrict-prototypes -Wa,-adhlns=main_simple.lst 
-std=gnu99 -DF_OSC= -MD -MP -MF .dep/main_simple.o.d  main_simple.c -o 
main_simple.o
In file included from main_simple.c:23:
SdCard.h:16: error: expected '=', ',', ';', 'asm' or '__attribute__' 
before 'SdCard'
make.exe: *** [main_simple.o] Error 1

zusätlich meckert er bei
1
uputs((unsigned char*)"\nBoot");
wenn man das
1
(unsigned char*)
 weg nimmt, klappts.

von Daniel R. (zerrome)


Lesenswert?

Ja, der  Michael Z. (incunabulum)
hat da ein paar Dinge in dem Projekt gelassen die nicht so 
funktionieren. Die "Offizielle" Version ist noch diese:

http://www.mikrocontroller.net/attachment/58218/stable-mmc-0.5.5.1.zip

bzw. für Windows Benutzer :

http://www.mikrocontroller.net/attachment/57495/AVR-Studio_stable-mmc-0.5.5.zip

Den Vorschlag die UART quasi in die main.c auszulagern, werde ich denke 
ich aufgreifen, in der nächsten Version. Wie im einzelnen muss man mal 
sehen.

von Daniel R. (zerrome)


Lesenswert?

Hm, je mehr ich darüber nachdenke je besser gefällt mir das mit dem 
auslagern der UART.

Das auslagern würde ja auch das Problem lösen, an die mitgelieferte 
uart.c/uart.h gebunden zu sein. Man könnte dann ja einfach seine eigene 
in der main.c includen...

von Matze N. (hupe123)


Lesenswert?

Genau so isses.

Mal nebenbei: die UART routine läuft auch auf meinem ATmega128 nich... 
die register heißen anders...

von Arne Z. (Gast)


Lesenswert?

Hallo Daniel,

erstmal danke für die tolle Lib von dir. Habe sie getestet, sie 
funktioniert wunderbar.
Nun hätte ich gerne eine ganz kleine Ergänzung in der mmc.h:
statt "#if defined (_AVR_ATmega32_)"
#if defined (_AVR_ATmega32_) || (_AVR_ATmega16_)
weil ich mich erst gewundert habe, wieso es zu fehlern bei meinem 
ATmega16 kam.

Weiterhin hätte ich die Frage, ob du mir sagen kannst, wieviele Zyklen 
der "ffclose()"-Befehl inklusive der Unterfunktionsaufrufe braucht. Ich 
würde das ja selber machen, leider kann ich aber mit assembler nichts 
anfangen (die Sprünge in die Unterfunktionen usw. erkenn/versteh ich 
nicht).
Die Frage habe ich, weil ich derzeit Daten auf die Karte schreibe 
(ffwrites()), und erst bei Knopfdruck den ffclose()-Befehl ausführe. 
Wenn aber die Spannungsversorgung zusammenbricht, möchte ich auch 
ffclose durchführen (damit ich die Daten auf der Karte sehe) und daher 
brauche ich die Zyklenzeit zur Berechnung meiner Kondensatoren in meinem 
Spannungsregler.

Hoffe das passt hier hin, gehört ja zu deiner Lib, aber hat halt nicht 
direkt damit zu tun.

Gruß
Arne

von Patrick (helipaddi)


Lesenswert?

Guten Morgen,

muss erstmal ein gorßes Lob an Daniel los werden, die Lib läuft bei mir 
einwandfrei! Mit den Libs von Roland Riegel etc. bin ich hingegen nicht 
zurecht gekommen...

Habe aber trotzdem noch eine Frage:
Wäre es möglich, abzufragen wie viel Speicher auf der SD Card nocht 
vorhanden ist? Werde mir gleich im Code von Roland mal ansehen wie er 
das abfragt.

Gruß,
Patrick

von Daniel R. (zerrome)


Lesenswert?

Hallo zusammen,

@ Arne Z. (Gast)
Das mit dem define, wird aufgenommen, kein Problem.

Die genaue Taktzahl ist schwer zu bestimmen, da sie von mehreren 
Parametern abhängt.
Wenn z.B. 256 Cluster am Stück frei waren und du bei ffclose alle 
beschrieben hast (aber nicht darüber hinaus !) müssen die ja noch 
verkettet werden.
Das macht dann zwei Schreiboperationen von 512 Byte Blöcken in der FAT 
aus. Dazu kommt noch das erneute Suchen der Datei im Verzeichnis, was je 
nach Größe des Verzeichnisses und Lage der Datei im Verzeichnis immer 
unterschiedlich lange dauert. Dann noch schreiben von 512 Bytes um den 
Datei Eintrag zu updaten.
Die Zeit für die Schreiboperationen ist nicht wirklich das Problem, aber 
die Zeit für das suchen von Dateien schon...
Am besten du ermittelst das Empirisch indem du einen Timer laufen lässt 
und verschiedene Szenarien durchspielst.

@Patrick Franken (helipaddi)

Ja ist möglich, man müsste ja nur alle leeren Cluster Nummern in der FAT 
zählen, diese mit der Anzahl der Sektoren/Cluster multiplizieren und 
schon hätte man das Ergebnis.

Hab momentan leider nicht so viel Zeit, aber werde ich einbauen.
Oder du schaust mal wie weit du kommst und schreibst das, dann nehme ich 
es auf :)
Die Funktion "unsigned long int fat_getNextCluster(unsigned long int 
oneCluster)" ist da dein Freund.

Spätestens nächste Woche hab ich massig Zeit.

Grüße Daniel

von Arne Z. (theich)


Lesenswert?

(nun nichtmehr Gast, sondern angemeldet)
Hallo Daniel,
danke für deine Antwort. Dann werde ich wohl mal verschiedene Szenarien 
bauen und die Zeiten überprüfen, so dass ich meinen Kondensator 
berechnen kann.

Und dann hab ich noch zwei Fragen: und zwar habe ich derzeit eine 
Funktion, die vor main() läuft, die die Datei öffnet und ans Ende geht. 
Dann wird in der main() alle 1sek bis 8 Stunden in der Datei einen 
Messwert aufgezeichnet. Erst wenn ich den Stop-Knopf drücke, wird 
ffclose ausgeführt. Gehen meine Daten verloren, wenn ich zu lange kein 
ffclose ausführe, oder aktualisiert ffclose nur das fat und verkettet? 
(also die Daten sind physisch auf der Karte, nur man sieht sie nicht)

Weiterhin gibt es eine Methode, wenn ich Daten geschrieben habe, aber 
nicht ffclose ausgeführt habe, die SD-Karte zu "reparieren", so dass 
meine Daten sichtbar werden?

Danke schonmal,
Arne

von Daniel R. (zerrome)


Lesenswert?

Hallo,
ja die Daten sind physikalisch auf der Karte. Allerdings nur in 512 Byte 
Blöcken.

Wenn du weißt, es passiert 8 Stunden nix, wäre ein ffclose zwischendurch 
ja nicht so schlimm.

Soweit mir bekannt ist, gehen Dateisysteme davon aus, dass Cluster die 
zu einer Datei gehören immer aufsteigend gesucht werden. Daher habe ich 
es so gemacht, dass die Datei schon beim öffnen Physikalisch angelegt 
wird, also mit Dateieintrag und Startcluster. Die freien Cluster die für 
die Datei dann verkettet werden, werden ab dem Startcluster der Datei 
gesucht.
Das bietet den PC Data-Recovery Tools die Möglichkeit der Datenrettung. 
Obwohl so einmal mehr der Dateieintrag geschrieben werden muss, am Ende 
ja auch wegen der Dateigröße. Funktioniert allerdings nur zuverlässig 
bei einer Datei...

Grüße Daniel

von geb (Gast)


Lesenswert?

Hallo Daniel!
Erst mal hochachtung vor deiner Arbeit. Hab den Code für den 
ADUC7024(ARM) portiert.Nach fast 2 Wochen teilweise frustrierender 
Arbeit,Schuld sind die Arschlöcher von SD-Karten Herstellern, die keine 
vernünftigen Datenblätter herausgeben, läuft das Ganze nun einigermaßen.
Allerdings sind da 2 Punkte, die mich noch etwas beschäftigen:

1.)Nach dem Schreiben eines Sektors(Zeit: ca. 2ms) gibt die Karte 
innerhalb eines Bytes 0xE5 (Daten akzeptiert) aus.Danach geht Data out 
der SD auf 0(busy) und bleibt dort für gut 5ms.Während dieser Zeit,kann 
man keine Kommandos an die Karte senden,sondern muß warten, bis Data out 
1 wird. Damit komm ich auf einen Zyklus von ca. 7ms für 512Bytes = ca 
70KB/s.Nicht gerade berauschend.Ich hab dann noch eine SanDisk Ultra II 
2GB probiert, die ging dann mit ca. 110KB/s(busy-Phase war deutlich 
kürzer). Frage: wie kommen die Leute auf 150KB/s und mehr? Mach ich was 
falsch?

2.)Es gibt bei mir das Problem, wenn ich immer das selbe File öffne, 
Daten hinzufüge und wieder schließe,dass auf einmal falsche Sektoren 
beschrieben werden,und das File für den PC unleserlich wird. 
Interessanterweise tritt das erst bei einer Filelänge > 0x1000000 (16MB) 
auf. Mit 1x öffnen, schreiben und schließen hab ich aber auch schon 50MB 
files erzeugt,die der PC lesen konnte. Nach einem rudimentären Debug 
könnte der Fehler in ffseek liegen,kanns aber noch nicht genauer 
festmachen.
Gesehen hab ich in diesem Tread noch nichts,was auf ein solches Problem 
hinweist.Möglicherweise ist's aber auch noch nicht aufgefallen,oder ich 
hab beim portieren Mist gebaut.

Ach ja, die verwendete Version ist 5.4,die Karten sind FAT16 formatiert.

Grüße Gebhard

von Daniel R. (zerrome)


Lesenswert?

Hallo,

@ geb (Gast)
Hast du die Karte über SPI angeschlossen? Wenn ja mit welcher 
Geschwindigkeit? Ich habe hier MMC Karten (die sind meist bisschen 
schneller als SD) die machen 200KBytes/sec schreibend und 270KBytes/sec 
lesend. Das bei 10 mhz SPI Takt und im nicht  überschreiben Modus.

Bei der Version 5.4 gab es tatsächlich ein Problem in ffseek im 
Zusammenhang mehrfachem anlegen von Dateien. Nimm am besten die 5.5.1 
von hier 
http://www.mikrocontroller.net/attachment/58218/stable-mmc-0.5.5.1.zip 
,ist aber auch schwer zu sagen ob da nicht vielleicht doch auch beim 
portieren was falsch gelaufen ist. Wenn du magst, poste doch mal deine 
geänderten Routinen, dann kann man mal drüber schauen :)

So schönen Wahl Sonntag noch :)

von StrangeMan (Gast)


Lesenswert?

Hallo!

Mir ist aufgefallen, dass, wenn ich innerhalb eines Interrupts eine 
Datei öffne, sich das Programm nach dem Interrupt resetet. Komisch.
Ich hab's umgangen, indem ich einen Funktionszeiger eingerichtet habe, 
der im Interrupt auf die auszuführende Funktion (die, die die Datei 
öffnet) gesetzt wird. Das Hauptprogramm prüft in einer Endlosschleife 
verschiedene Dinge, und führt dabei immer mal diese Funktion aus. Damit 
verlagere ich dieses Öffnen ins Hauptprogramm und die Probleme sind weg.

Ich hab aber keine Ahnung, warum sich der AVR da resetet... Irgendwas 
mit dem Stack oder so? Wie gesagt, das reseten passiert am Ende der ISR.

StrangeMan

von Werner B. (werner-b)


Lesenswert?

!!!Aua!!! das tut weh!

von geb (Gast)


Lesenswert?

Hallo Daniel!

Mein Geschwindigkeitsproblem liegt an der langen busy Phase der SD 
Karte.
Reine Schreibdauer ca. 2ms/sektor, busy ca. 5ms(lt. 
Oszilloscope).Sicher,die max. 3,24Mhz SPI Takt sind auch nicht gerade 
berauschend, da hat sich Analog Device nicht gerade mit Ruhm bekleckert.

Ich werd jetzt mal die Vers. 5.5.1 portieren, und wenn das wirklich 
stabil läuft,hab ich die Idee, das fread und fwrite als Statemachine 
auszuführen und die SPI interruptgesteuert zu verwenden. Damit könnten 
diese Funktionen im Hintergrund laufen und würden nur mehr minimale 
Prozessorzeit beanspruchen(die meiste Zeit wird ja jetzt eigentlich nur 
gewartet).

Grüße Gebhard

von Arne Z. (theich)


Lesenswert?

Huhu,

Ich habe nun mal gemessen, wie lange ein ffclose() dauert. Dabei kam ich 
auf Werte zwischen
216.664 und 378.200 Takte (bei ATMega 16 @ 16MHz).
Im Durchschnitt lag ich bei 260.000 Takten (der große Wert war wohl ein 
statistischer "Ausrutscher" ^^).

Die Werte änderten sich zwar immer, aber ob die Karte nun voll war, oder 
komplett leer, hatte irgendwie keinen Einfluss.

Daniel, weißt du zufällig, ob das realistische Werte sein können?
Hast du evtl. noch eine Idee für einen "Worst Case" Fall?

Gruß
Arne

von geb (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Hab die Vers. 5.5.1 für ADUC702x(ARM7) portiert und läuft soweit 
fehlerfrei.
Weiters hab ich in mmc.c eine Unterstützung für SDHC Karten eingebaut 
und die Schreibperformance durch verkürztes warten auf das Ende der 
"busy" Phase verbessert.
Mit den SanDisk Ultra-Karten(SD 2GB und SDHC 4GB)  kann ich jetzt doch 
150kB/s schreiben, bei 3,24 MHz SPI clock(gähn).
Ich stell mal mein mmc.c hier rein zum testen.

Grüße Gebhard

von Daniel R. (zerrome)


Lesenswert?

Hallo zusammen.

@ Arne Z. (theich)

Also ich müsste da selbst mal ein bisschen messen um das zu sehen. Nur 
rein theoretisch müsste die Zeit um eine Datei zu finden abhängig von 
der Anzahl der Dateien sein die in dem Verzeichnis sind. Je mehr Dateien 
umso länger die Such Zeit.
Sagen wir mal man kann mit 200 KBytes/s lesen, das macht dann ungefähr 
400 Sektoren und somit 6400 Datei Einträge (weil 16 pro Sektor). Ist die 
gesuchte Datei jetzt die letzte, also Datei Nummer 6400, dauert es 
mindestens 1 Sekunde um diese zu finden. Man muss die ja aber bei 
ffclose finden, um den Datei Eintrag zu updaten, das ist das Dilemma.
Bei deinen Werten habe ich raus, 0,01625 Sekunden also 16,25 ms. Ist 
jetzt zwar ne Milchmädchen Rechnung, aber das würde Pi mal Daumen so 6-7 
Sektoren bedeuten, also ungefähr 112 Dateien durchsuchen....Oder 
weniger, wenn vorher noch paar Daten Sektoren geschrieben wurden.
Mach mal ein Verzeichnis mit sagen wir 2000 Dateien (kleinen Dateien) 
und ändere dann die zuletzt drauf geschriebene ab. Da müsste sich der 
Overhead des Suchens deutlicher bemerkbar machen :)

@ geb (Gast)

Äh verkürztes warten? Kannst du dazu etwas mehr sagen, bitte.
Unterstützung für SDHC klingt auch gut. Ich werde mir deinen Code mal 
genauer anschauen :)



PS:
Hat nich mal irgendwer Lust eine FAQ auf 
http://www.mikrocontroller.net/articles/AVR_FAT32 zu machen, wo man mal 
so alle Try-and-Error-zum-Erfolg Sachen zusammen trägt? Schön wären ja 
auch alle möglichen mmc.c/mmc.h für unterschiedliche Plattformen. Bei 
mir geht nächste Woche das Semester wieder los => wenig Zeit...


Grüße Daniel

von Arne Z. (theich)


Lesenswert?

Hiho,

@Daniel,
habe nun mal 2000 Dateien im Bereich von 1-10KB auf die SD-Karte 
geschrieben, als letztes die Datei, in der ich schreiben möchte. Nun kam 
ich auf Werte von 7.645.224 bis 10.433.112 Takten.
Wow, dafür habe ich meinen Kondensator nicht ausgelegt, also darf in 
meinem Verzeichnis keine andere Datei vorhanden sein, damit ich unter 
880.000 Takten bleibe.
---
Übrigens, wenn das Semester los geht, hat man doch gerade viel Zeit, 
erst zum Ende hin wird es immer knapp (zumindest ist/war es bei mir so)
---
Gruß
Arne

von Daniel R. (zerrome)


Lesenswert?

Hallo.
Ja die Werte sehen realistisch aus, leider.
Es gibt bei Conrad 1F bis 5 Volt Goldcaps für um die 2 Euro, auch in 
kleiner Bauform. Davon ein paar und das zeug läuft Minuten lang noch :)

Wenn du jetzt 2000 Verzeichnisse mit nur einer Datei drin hast, wird das 
auch nicht besser (nur als Beispiel), eher schlechter. Große 
Betriebssysteme indizieren deshalb Dateien, um nur Indizes vergleichen 
zu müssen, wie bei Datenbanken...
Man könnte vielleicht auch das suchen etwas beschleunigen indem man z.B. 
nur den ersten Buchstaben der Datei überprüft und erst wenn der stimmt 
weitere Buchstaben. Da mach ich mir mal Gedanken dazu...

Zeit hab ich leider nie genug und dieses Semester wird noch schlimmer...

Grüße Daniel

von geb (Gast)


Lesenswert?

Noch ein spassiges Problem ist mir in Verbindung von meinem mmc.c 
aufgefallen:

Nach dem Schreiben des letzten sektors (file_Update) warte ich nicht bis 
die Karte nicht mehr busy ist.(Der Wert 0xE5 als "Daten akzeptiert" ist 
das Letzte was ich von der Karte lese.)
dieser letzte Sektor wird bei manchen Karten z.B. Kingston nicht mehr 
ins Flash geschrieben. Damit wird das fclose unwirksam und die letzten 
geschriebenen Daten (seit letztem öffnen der Datei) gehen verloren.
Offenbar brauchen diese Karten in der busy-Phase den Clock um die Daten 
aufs Flash zu speichern. Sandisk-Ultra Karten haben dieses Problem 
interessanterweise nicht.

Abhilfe: letzten sektor bei file-update 2x schreiben, oder hier extra 
busy Phase abwarten.

Grüße Gebhard

von Kai J. (tairon)


Lesenswert?

Hallo Daniel,

ich hab ein kleines Problem beim Schreiben von Daten auf SD-Karte.
Ich möchte eine Datei erstellen, Daten rein schreiben, Datei schließen.
In gewissen zeitlichen Abständen möchte ich diese Datei wieder öffnen, 
weitere Daten anhängen und Datei wieder schließen.
Beim Erstellen der Datei und beim Speichern des ersten Datensatzes 
klappt auch alles wunderbar. Will ich Datei jedoch zum Anhängen von 
weiteren Daten mit
ffstatus = ffopen(file_name);
erneut öffnen, liefert ffopen als Rückgabewert 2 (datei muss angelegt 
werden) obwohl sie bereits existiert. Die Daten werden dann auch nicht 
in die Datei geschrieben. Es sind nur die Daten des ersten 
Schreibzugriffs vorhanden.
Ich benutze die AVR-Studio Version 0.5.5

Gruß Kai

von Daniel R. (zerrome)


Lesenswert?

Hallo.

@ geb (Gast)
Man muss doch eh pollen ob die Karte busy ist oder nicht. Damit sendet 
man doch schon takte...
Orientier Dich da doch an der orginal mmc.c.

Meinst du mit file-update die Funktion flushFileData() ? Wenn ja, die 
ist nur für den internen Gebrauch in der file.c. Der User sollte die 
nicht benutzen, na ja vielleicht zu Test Zwecken...

@  Kai J. (tairon)
Das klingt seltsam. Wie sieht der String auf file_name aus?
Zeig doch mal den Code mit dem du zuerst die Datei beschreibst. Hast du 
irgendwo etwas am Code geändert?

Grüße Daniel

von Kai J. (tairon)


Lesenswert?

Hallo Daniel,

hier der Code:
erstmaliges Öffnen der Datei:
1
  unsigned char   file_name[12]="DATA    TXT";
2
3
  // SD-Karte initialisieren
4
  uart1_puts("Boot");
5
6
  while (mmc_init() !=0){       // rückgabewert 0 dann ist karte initialisiert
7
    nop();
8
  }
9
10
  uart1_puts("...");
11
12
  if(0==fat_loadFatData()){      // rückgabewert 0 dann sind die fat daten bekannt
13
14
    uart1_puts("Ok\r\n");      // wenn auf dem terminal "Boot... OK" zu lesen ist, ist init ok. jetzt kann man schreiben/lesen
15
16
  } 
17
18
  // Datei öffnen
19
  ffstatus = ffopen(file_name);
20
21
  ffwrites(data);

Nach dem Schreiben der Daten schließe ich die Datei wieder.

Um weitere Daten in der Datei zu speichern, benutze ich folgenden Code
1
  // Datei öffnen
2
  ffstatus = ffopen(file_name);
3
4
        ffwrites(data);
5
6
        ffclose();

Geändert habe ich nichts, außer dass ich meine eigene UART-Routine 
benutze, auch in file.c. Vielleicht hängts daran. das werde ich noch mal 
testen.

von Gast (Gast)


Lesenswert?

Du musst mit ffseek(file.length) ans Ende der Datei gehen.

von Kai J. (tairon)


Lesenswert?

Das hab ich gemacht. Ich bekomm aber vorher schon bei
ffstatus = ffopen(file_name);
eine 2 als Rückgabewert und nicht eine 1.
Ich schätze aber es liegt an meiner UART Routine. Ich benutze die 
Library von Peter Fleury.

von Gast (Gast)


Lesenswert?

Moin,

habe mir einen Code geschrieben, um zu sehen wie lang ein ffseek() 
(5.5.1) braucht.
Die Datei "1M.TXT" ist 10240 bytes groß, auf einer 1GB FAT32 Karte.
1
  while (second < 60) {
2
    uputc(ffopen("1M      TXT"));
3
    uputs("S");
4
    ffseek(file.length);
5
    uputs("D");
6
    ffclose();
7
  }

Beim ffseek knallts. Ich sehe das "rS", das "D" aber nicht mehr. Bei 
einer Dateigröße von 1024 bytes funktioniert der Code tadellos.

Irgendjemand eine Idee?

von Daniel R. (zerrome)


Lesenswert?

Hallo,

@ Kai J. (tairon)
Kann ich irgendwie nicht nachvollziehen wieso die Uart lib daran schuld 
sein soll. Du hast aber mindestens auch noch "#define SMALL_FILE_SYSTEM" 
geändert, sonst geht nämlich ffwrites nicht.

@ Gast (Gast)
Ok, teste ich mal. Mit wie vielen Sektoren/Cluster ist denn das 
Formatiert, damit ich gleiche Voraussetzungen habe ?

Grüße Daniel

von ffseek-Problem (Gast)


Lesenswert?

@Daniel:

Sind 8 Sektoren/Cluster. Ich habe das Problem jetzt schon auf die 
Funktion
1
void fat_getFatChainClustersInRow( unsigned long int offsetCluster)

einschränken können.

Ablauf:

file.c (ca. Zeile 163): fat_getFatChainClustersInRow(fat_getNextCluster( 
file.lastCluster )) ;

fat_getNextCluster( file.lastCluster ) klappt soweit, geht dann in 
fat_getFatChainClustersInRow() und hängt sich da irgendwo auf.

von ffseek-Problem (Gast)


Lesenswert?

In der fat_loadSector knallt's, sobald er in die if() Bedingung springt.
1
  if(sec!=fat.currentSectorNr){ // nachladen noetig
2
#if (WRITE==TRUE)
3
    if(fat.bufferDirty==1) {
4
      fat.bufferDirty=0; // buffer kann nicht dirty sein weil wird geschrieben
5
      mmc_write_sector(fat.currentSectorNr,fat.sector); // schreiben von sektor puffer
6
      //fat_writeSector(fat.currentSectorNr);
7
    }
8
#endif
9
    mmc_read_sector(sec,fat.sector);  // neuen sektor laden
10
    fat.currentSectorNr=sec; // aktualisiert sektor nummer (nummer des gepufferten sektors)
11
    return TRUE;
12
  }

Spasseshalber habe ich mir die Variable sec mal angeschaut. Im 
Fehlerfall steht in ihr irgendein Müll. Der verursacht wohl den freeze.

von geb (Gast)


Lesenswert?

@Daniel
Das ist eben der springende Punkt,in meiner mmc.c polle ich nach einem 
sektor-write nicht auf busy,sondern bereite schon die nächsten daten zum 
Schreiben vor. Auf "busy" wird dann beim nächsten write-command 
gepollt,in der Hoffnung dass das blöde Ding in der Zwischenzeit die 
Daten schon mal geflasht hat. ==>funktioniert bei Sandisk tadellos und 
erhöht die Schreibrate um 40%,bei Kingston bringts nichts(ohne CLK 
offenbar kein flashen).Schon sehr interessant, wie unterschiedlich die 
SD Karten sind.

Grüße Gebhard

von ffseek-Problem (Gast)


Lesenswert?

1
void *bytesOfSec;
in
1
unsigned long int fat_getNextCluster(unsigned long int oneCluster){

Lieg ich jetzt voll daneben, oder wo alloziierst Du Speicher für die 
Variable bytesOfSec?

von Daniel R. (zerrome)


Lesenswert?

Hm, wenn der falsche Sektor geladen wird, geht natürlich nix mehr 
(fat_loadSector).

Das ist ja keine Variable, sondern ein void Pointer, der zuerst mal auf 
nix zeigt, dann aber auf bytesOfSec=&fat.sector[j] , also auf eine 
bestimmte char Adresse im Puffer für einen Sektor.
Von dieser "Start Adresse" wird jetzt je nach FAT Typ auf 2 oder 4 Byte 
Größe gecastet.
Mit was Kompilierst du den Code? ich hab da mit dem GCC für linux und 
dem AVR-GCC keine Probleme. Kann das irgendwie nicht richtig 
reproduzieren, werde da aber mal genauere Tests machen. Bis jetzt kann 
ich leider keinen Fehler finden...



@ Gebhard
Ich glaube es ist SD Spezifikation das die Karte "CLK hörig" ist, ist 
also ein Geschenk, das es mit Sandisk funktioniert...

Grüße Daniel

von ffseek-Problem (Gast)


Lesenswert?

@Daniel:

gcc 3.4.6 AVR-CrossPack.

Ich lasse mir vor jedem return in fat_getNextCluster den Wert von 
bytesOfSec ausgeben mit:
1
    putNum(*(unsigned long int*)bytesOfSec, 'w');
Die Funktion macht nix anderes als den übergebenen Wert (unsigned long 
int) als Tausender, Hunderter etc. auszugeben. Das 'w' dient der 
Unterscheidung. Die Ausgabe schaut so aus:

w00135
w00136
w00137
w00138
w00139
w�P15
w�P15

Die letzten beiden Werte sind IMHO keine korrekten Werte.

von ffseek-Problem (Gast)


Lesenswert?

@Daniel probier das Ganze doch bitte mal mit einer 102400 byte großen 
Datei.

dd if=/dev/random of=1M.TXT bs=512 count=200

von Daniel R. (zerrome)


Lesenswert?

Joa, hab ich.
Auch mit nem image von ner Karte mit 8 Sektoren/Cluster.
Wo hast du den 3.4.6 Compiler her?

So, hab mal folgendes:

1. Mit Linux Kompiliert, Fat-resource als "/dev/mmcblk0" eingebunden und 
mit der Lib 5.5.1 getestet. Ohne Probleme.

2. Mit Linux Kompiliert und Fat-resource als Image einer Karte 
eingebunden. Mit Lib 5.5.1, ohne Probleme.

Kannst du Vielleicht ein Image der Karte machen und mir schicken, damit 
ich mit der gleichen Karte testen kann, aber anderen Kompilern usw.?

Grüße Daniel

von ffseek-Problem (Gast)


Lesenswert?

Okay, das Problem scheint nur aufzutauchen, wenn ich eine Datei lesen 
will, die am PC erstellt wurde. Wenn ich eine entsprechend große Datei 
mit der Lib generiere, ist alles ok.

von ffseek-Problem (Gast)


Lesenswert?

Der gcc war in dem AVR-GCC package für den Mac.
http://www.obdev.at/products/crosspack/index-de.html

Das ganze läuft auf nem Atmega8.

von Daniel R. (zerrome)


Lesenswert?

Das ist mal seltsam.
Ist die Datei die du dann mit der Lib erstellt hast, denn auf dem Pc 
lesbar usw.?

Was definitiv nicht geht ist eine mit Linux Formatierte Karte, da Linux 
aus welchem Grund auch immer das Root-Dir, wenn es nur 1 Cluster groß 
ist nicht mit 0xfffffff0 abschließt sondern anders.

Mein Interesse an einem Image der Karte besteht immer noch.


Grüße Daniel

von Daniel R. (zerrome)


Lesenswert?

Benutzt man zufällig auf dem Mac auch das Tool mkfs.vfat zum FAT 
formatieren?

von ffseek-Problem (Gast)


Lesenswert?

Die Datei ist am PC lesbar, ja. Der einzige Unterschied ist, dass ich 
bei einer auf dem Atmega erstellten Datei "0FFFFFFF" als bytesOfSec 
sehe, und bei der am Mac erstellten das Ganze zwei mal. D.h. die 
Funktion wird unnötigerweise nochmal aufgerufen.

Auf dem Mac macht das die GUI :).
Und die führt den Befehl newfs_msdos mit Optionen aus.

von Arne Z. (theich)


Lesenswert?

Huhu,

ich habe noch mal eine kleine Frage:
Und zwar möchte ich gerne in einer geöffneten Datei, Werte lesen und 
danach wieder ans Ende schreiben, mein Programmablauf sieht wie folgt 
aus:
ffopen(datei); -> ffseek(file.length); -> 1 bis x-mal ffwrites(werte); 
-> ffseek(file.seek+fat.cntOfBytes - (68*100)); (ist die Stelle der 
Datei, von der ich lesen möchte) -> 100-mal ffread() ->
ffseek(file.seek+fat.cntOfBytes);
Mein Problem ist nun, dass er mit dem letzten ffseek nicht an die 
richtige Stelle geht, damit ich weiter schreiben kann.
Gibt es nun eine Möglichkeit ohne ffclose() mit gefolgten ffopen(datei), 
an die richtige Stelle der Datei zu kommen, damit ich weiter 
hineinschreiben kann? Also quasi "Fat aktualisieren / file.length 
aktualisieren" ohne neue die Datei zu schließen+öffnen?

Grüße
Arne

von ffseek-Problem (Gast)


Lesenswert?

So, habe mir das Ganze nochmal genauer angeschaut. Der ffseek() hängt 
hier:

mmc.c, mmc_read_sector(...):
1
  while (mmc_read_byte() != 0xFE){};
Komischerweise bekommt er nur 0xFE zu lesen.

von Werner B. (werner-b)


Lesenswert?

ffseek-Problem schrieb:
> So, habe mir das Ganze nochmal genauer angeschaut. Der ffseek() hängt
> hier:
>
> mmc.c, mmc_read_sector(...):
>
>
1
>   while (mmc_read_byte() != 0xFE){};
2
>
> Komischerweise bekommt er nur 0xFE zu lesen.

Sieht nach Compiler bzw. Linker Problem aus.

Versuche einmal ein "make clean" und dann ein "make".

Wenn's danach immer noch nicht geht, versuche eine andere 
Toolchain/WinAVR Version.

von ffseek-Problem (Gast)


Lesenswert?

make clean bringt nichts. Habe mal gcc 4.3.2 genommen. Auch keine 
Änderung.
Ein Stack-Overflow kann es nicht sein, da die Funktion, so wie ich das 
sehe, vorher mehrfach problemlos betreten und wieder verlassen wird.

@Daniel:
Wie erstelle ich das Image der SD, und wie soll ich es Dir zukommen 
lassen?

von Daniel R. (zerrome)


Lesenswert?

Hallo zusammen.
Ich habe momentan leider echt viel um die Ohren, komme aber 
wahrscheinlich dieses Wochenende trotzdem dazu da nochmal etwas 
nachzuforschen.

@  Arne Z. (theich)

Du müsstest "#define OVER_WRITE TRUE" machen und dann zwischen schreiben 
und lesen die Dateilänge merken, damit du nach dem lesen ein seek dahin 
machen kannst.
Ungefähr so:
ffopen(datei); -> ffseek(file.length); -> 1 bis x-mal ffwrites(werte);
-> unsigned long int tmp=file.seek+fat.cntOfBytes; 
->ffseek(file.seek+fat.cntOfBytes - (68*100)); (ist die Stelle der
Datei, von der ich lesen möchte) -> 100-mal ffread() ->
ffseek(tmp);-> weiter schreiben an Dateiende.
Das müsste klappen.


@  ffseek-Problem (Gast)

Ich bräuchte als Image einfach eine Datei, in der alle Sektoren der 
Karte stehen, bzw alle Bytes. Ich mache solche Images meistens mit 
WinHex. Bei einer 1GB Karte wäre es aber wohl am besten nicht alle 
Sektoren in die Datei zu packen, sondern nur die die mit Daten belegt 
sind. Also von Sektor 0 bis zu dem letzten Sektor mit Daten...
Wie groß wird diese Datei dann bei dir? Geht die noch per Mail?

Grüße Daniel

von ffseek-problem (Gast)


Lesenswert?

@Daniel:

Ich habe die ersten 10000 Sektoren mit WinHex gebackupt. Liegen hier:
http://rapidshare.com/files/290862233/1gb_10000sect.whx.html

Sind ca. 5MB.

Danke Dir für die Mühe!

von Daniel R. (zerrome)


Lesenswert?

@ffseek-problem (Gast)

Image ist soweit Ok. Habe jetzt noch nicht auf realer Hardware getestet, 
mach ich aber gleich. Das sieht aber alles soweit Ok aus. Auf Linux mit 
dem gcc geht es problemlos, was schonmal bedeutet, das der Code an sich 
keinen Fehler verursacht.
Kann dann eigentlich nur am Compiler oder der Hardware liegen.

War die Karte auch schon so formatiert bei diesen Tests 
Beitrag "Re: MMC SD library FAT16 FAT32 read write" ?

Bei dem jetzigen Image sind die Cluster [124-148] belegt, mach in Summe 
25. Das macht bei 8 Sec/Clust 102400 Bytes. Das kommt alles hin. Die 
Cluster sind in der Fat auch richtig verkettet und Terminiert...

Grüße Daniel

von ffseek-Problem (Gast)


Lesenswert?

@ Daniel:

Ich habe auch noch ein paar Tests gemacht und folgendes festgestellt:
Es ist egal, ob ich die Karte auf einem Mac oder einem Windows Rechner
formatiere. Und es ist egal, ob die Datei als einzige auf der Karte 
existiert
oder schon andere Dateien physisch vor der Datei liegen.

Ich weiß jetzt leider nicht mehr, wie die Karte bei den Tests, die Du 
meinst, formatiert war. Es sollte aber wegen meiner vorhin beschriebenen 
Beobachtung unwichtig sein.

Ich habe inzwischen auch mal eine andere SD-Karte probiert, und das 
ganze wegen Stack-Bedenken auf einen Mega32 portiert. Immer mit dem 
gleichen Resultat.

Die Hardware möchte ich als Fehlerquelle ausschließen, da Sie nach der 
Spec von SanDisk aufgebaut ist. Ich werde als nächstes das Ganze mal mit 
WinAVR kompilieren und testen. Kannst Du mir sagen welche Version Du 
nutzt?

von ffseek-problem (Gast)


Lesenswert?

Negativ. Auch wenn ich es mit WinAVR unter Windows mache gibt es immer 
den gleichen Fehler. Habe auch auf von 8MHz auf 4MHz heruntergetaktet. 
Kein Unterschied.

von ffseek-Problem (Gast)


Lesenswert?

Vielleicht hilft Dir das noch weiter.

Im Fehlerfall ist bei FAT32:

- in der Funktion fat_getNextCluster():
i = 0x001FFFFF (2097151 dezimal)
fat.fatSec = 0x00000119 (281 dezimal)

- in der Funktion fat_loadSector(), die ja im Anschluss mit i + 
fat.fatSec aufgerufen wird
sec = 0x00200118 (2097432 dezimal)

Bei einer Speicherkarte mit 1 GB hab ich Brutto (1024  1024  1024) 
Byte / 512 (Byte / Sektor) = 2097152 Sektoren.

Wenn ich das also richtig sehe, versucht der anschließende 
mmc_read_sector() auf einen Sektor (2097432) zuzugreifen, der gar nicht 
mehr existiert, da die Speicherkarte nur 2097152 Sektoren hat.
Kann das sein?

von Daniel R. (zerrome)


Lesenswert?

Da bin ich langsam ratlos, weil mit dem Image das du hochgeladen hast 
habe ich keine Probleme. Poste doch mal bitte deinen ganzen Code.

von ffseek-Problem (Gast)


Lesenswert?

Eine Sache noch. Stimmt dein file.lastCluster? In dem Teil von file.c 
(ffseek)
1
  while( offset>=512 ){                  /** suchen des sektors in dem offset ist  **/
2
    sec++;                      // da byte nicht in diesem sektor ist, muss hochgezählt werden
3
    offset-=512;                  // ein sektor weniger in dem das byte sein kann
4
    file.seek+=512;                  // file.seek update, damit bei ffclose() die richtige file.length herauskommt
5
    fat.cntSecs-=1;                  // damit die zu lesenden/schreibenden sektoren stimmen
6
    if ( 0==fat.cntSecs ){                // es müssen mehr sektoren der datei gesucht werden
7
/* !!! HIER lass ich mit file.lastCluster ausgeben !!! */
8
      fat_getFatChainClustersInRow(fat_getNextCluster( file.lastCluster ) );  // nachladen von clustern in der chain
9
      sec=fat.startSectors;            // setzen des 1. sektors der neu geladenen, zum weitersuchen !
10
    }         
11
  }

Z.B. ist es einmal 0x01333231 = 0d20132401.

Hm, ziemlich kompliziert die ganze Sache :D.

von Daniel R. (zerrome)


Lesenswert?

Zeig mal bitte deine ganze Funktion in der du da die Datei öffnest liest 
usw...

von ffseek-Problem (Gast)


Lesenswert?

1
int main(void) {
2
  /* init fuer uart etc... */
3
4
  uputs("\r\n\r\nWaiting...\r\n");
5
6
  while (mmc_init() == FALSE) {
7
  }
8
9
  if (fat_loadFatData() == FALSE) {
10
    while (1) {
11
    }
12
  }
13
14
  mySize = 0;
15
  while (mySize < 60) {
16
    uputs("main ffopen\r\n");
17
    ffopen("1M      TXT");
18
    uputs("main ffseek\r\n");
19
    ffseek(file.length);
20
    uputs("main ffclose\r\n");
21
    ffclose();
22
    uputs("main ffclose done\r\n");
23
    mySize++;
24
  }
25
  while(1);
26
}

von Daniel R. (zerrome)


Lesenswert?

Das Problem ist, es gibt verdammt viele Möglichkeiten wie das was schief 
gehen kann. file.lastCluster wird in fat_getFatChainClustersInRow() 
gesetzt...
Wenn ich jetzt halt deine genaue Anwendung der Lib sehen könnte, hätte 
ich das Image und hätte somit alles genau so wie du. Dann wohl auch den 
gleichen Fehler.

^^ huch zu langsam ;)

von ffseek-Problem (Gast)


Lesenswert?

Achso...

AVR Memory Usage
----------------
Device: atmega8

Program:    7218 bytes (88.1% Full)
(.text + .data + .bootloader)

Data:        990 bytes (96.7% Full)
(.data + .bss + .noinit)

Sollte ich mir wegen letzterem Sorgen machen? Immerhin hatte ich das 
Problem auch bei einem Mega32, der ja 2K RAM hat.

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Sorry, aber das läuft bei mir durch.

Als Anhang die Ausgabe...

von Daniel R. (zerrome)


Lesenswert?

>Data:        990 bytes (96.7% Full)
>(.data + .bss + .noinit)

Ist schon ziemlich eng. Mach doch die Ausgaben kürzer wie z.B

> uputs("main ffclose done\r\n");

zu uputs("mcd\n"); oder so

von ffseek-Problem (Gast)


Lesenswert?

Okay, ich habe jetzt mal den kompletten Unterbau (mmc, file, fat) 
ersetzt durch den aus der 0.5.5.1 Lib. Nur die main() habe ich so 
gelassen. Keine Änderung. Ausgabe:

Waiting...
main ffopen
main ffseek

Das war's.

Program:    6182 bytes (75.5% Full)
(.text + .data + .bootloader)

Data:        686 bytes (67.0% Full)
(.data + .bss + .noinit)

von ffseek-Problem (Gast)


Lesenswert?

../mmc/fat.c: In function `fat_loadRowOfSector':
../mmc/fat.c:104: warning: left shift count >= width of type

Kommt das bei dir auch?

von siegmar (Gast)


Lesenswert?

Hi Jungs,
verfolge mit Spannung euer Problem.
Vielleicht doch ein Hardwareproblem.
Bricht eventuell die Versorgungsspg zusammen ???
Sollteste mal mit einem DSO überprüfen.
Noch viel Spaß
Gruß
Siegmar

von Daniel R. (zerrome)


Lesenswert?

Da bin ich platt. Wohnst du zufällig in der Nähe von Köln?
Die Datei ist auf jeden Fall auch vorhanden?
Lass dir mal die Rückgabewerte der Funktionen ffopen(), ffseek() und 
ffclose() anzeigen.

von Daniel R. (zerrome)


Lesenswert?

>../mmc/fat.c: In function `fat_loadRowOfSector':
>../mmc/fat.c:104: warning: left shift count >= width of type

Ja ist aber nur ein Warning und nicht so wild. Das muss so.

Was der " siegmar (Gast) " da schreibt is mir auch schonmal durch den 
Kopf gegangen. Wie ist die Stromversorgung bei der Schaltung?

von ffseek-Problem (Gast)


Lesenswert?

100nF direkt am SD-Slot, 200uF in der Nähe des µC.

von ffseek-Problem (Gast)


Lesenswert?

ffopen() sagt 'r'. ffseek ist void, zum ffclose komm ich garnicht :).
Köln ist ein schönes Stück weg :/.

von siegmar (Gast)


Lesenswert?

Du solltest messen, ob die Spg. zusammenbricht.
Diese Möglichkeit muß Du sicher ausschließen und schaue Dir auch die 
Flanken der Signale an, ob sie nicht zu rund sind.
Hardwarefehler mußt Du meßtechnisch ausschließen !!
So nun gut Nacht
Gruß
Siegmar

von Daniel R. (zerrome)


Lesenswert?

Welchen inhalt hat der Pointer "pt" beim verlassen von ffseek()?

von ffseek-Problem (Gast)


Lesenswert?

@ Siegmar
Jo, Oszi hab ich nicht. Multimeter grad mal :).

Folgendes passiert:

Waiting...
main ffopen
rmain ffseek
main ffclose
1main ffclose done
main ffopen

Dazu muss ich ein wenig ausholen. Das Ganze funktioniert mit 3V3 wie 
folgt.
5V (USB) Vcc -> 3V3 über LDO Regler.
5V (USBasp) Signale <-> 3V3 Signale über Levelshifter.
µC <-> SD über 3V3.

3V3                                 5V
µC ---- Levelshifter ---- USBasp
SD -+

Zunächst ist der Levelshifter (LS) auf HiZ, damit der USBasp die SPI 
nicht beeinflusst. Damit erfolgen die ersten 3 Zeilen der Ausgabe.
Sobald ich den LS aktiviere, erfolgt die Ausgabe der Zeilen 4 bis 6. 
ABER gleichzeitig wird der RESET des µC auf GND gezogen (hardwired mit 
LS). D.h. eigentlich würde er weitermachen, aber es kommt der Reset 
dazwischen.

Werd mal den LS loswerden und die vielen Käbelchen die hier 
herumschwirren.

Ein Königreich für ein Oszi.

Scheint also kein Softwareproblem zu sein.

Dennoch fetten Dank an Dich Daniel für die Mühe und Hilfe! Und natürlich 
für die Lib!

von Daniel R. (zerrome)


Lesenswert?

Joa, kein Problem. Ich habe ja auch Interesse daran, da Fehler zu finden 
und an der Qualität zu arbeiten :)

Falls du da weiter kommst, lass von dir hören.
Wenn mir noch was einfällt, meld ich mich auch.

Grüße Daniel

von siegmar (Gast)


Lesenswert?

Hallo,
normales Oszi würde Dir da auch nicht so sehr helfen, außer die Flanken 
betrachten.Mit einem DSO wäre es kein Problem den Fehler einzugrenzen 
bzw. auszuschließen.
Einfach mal einen Referenzaufbau verwenden, der bei Anderen 100% 
funktioniert. Daniels Aufbau z.B einfach nachbauen , damit ihr 
identische Testbedingungen habt. Die Länge der leitungen zur Karte sind 
nicht unkritisch und sollten so kurz wie möglich sein.

Wird schon klappen, bleib dran !
Bin gespannt was es war, laß es uns wissen.

Schönen Sonntsag noch
Gruß
Siegmar

von ffseek-Problem (Gast)


Lesenswert?

Aufbau ist Breadboard mit ca. 3cm langen Drähten von µC zur Karte. 
Dieser Aufbau funktioniert mit Chan's Lib tadellos. Seeks, writes, 
reads...

von Daniel R. (zerrome)


Lesenswert?

Krass, endlich kann ich nachvollziehen warum das bei dir rappelt...
Der AVR-GCC macht da was falsch !

Eigentlich sollte der bei folgender Schleife:
1
while( offset>=512 ){
2
 sec++;
3
 offset-=512;
4
 file.seek+=512;
5
 fat.cntSecs-=1;
6
 if ( 0==fat.cntSecs ){
7
  fat_getFatChainClustersInRow(fat_getNextCluster( file.lastCluster ) );
8
  sec=fat.startSectors;      
9
  }
10
}
auch bei offset==512 noch einmal durchlaufen, macht der aber nicht, das 
Programm stoppt einfach !

Wenn man das "while( offset>512 )" so macht, läuft es durch.
Da muss man mal weiter nachforschen !
Schlimmstenfalls sollte offset mit der >= Bedingung ja 0 werden, was 
auch richtig wäre.

von Daniel R. (zerrome)


Lesenswert?

Oha, glaub das ist vielleicht doch mein Fehler^^
Das muss ich erstmal nachvollziehen...

von ffseek-Problem (Gast)


Lesenswert?

Dann hab ich wohl einen Sonderfall erwischt :).

Das wär natürlich prima, wenn sich das softwareseitig beheben ließe.

von Daniel R. (zerrome)


Lesenswert?

Hallo,
ja lässt sich ändern.
Bevor ich jetzt aber hier die Änderung poste, teste ich erstmal 
ausgiebig.

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

So der Bug is weg. Schwere Geburt^^

Der Fehler lag in einer Abfrage in ffseek. Warst da schon auf dem 
richtigen Weg.
Es konnte unter Umständen dazu kommen, das da verschiedene Grenzen 
aufeinander fallen und dieser Fall nicht abgefragt war.
In der Schleife in ffseek muss bei dem if die Bedingung erweitert 
werden...
1
if ( 0==fat.cntSecs && offset!=0){  
2
 fat_getFatChainClustersInRow(fat_getNextCluster( file.lastCluster ) );
3
 sec=fat.startSectors;
4
}

Es gibt da jetzt auch noch weitere Updates in der Lib.
Zu diesem Thema: Beitrag "Re: MMC SD library FAT16 FAT32 read write"
Was der Arne Z. da machen sollte, kann jetzt wegfallen, solange "#define 
MMC_OVER_WRITE TRUE" ist.

Es kann jetzt einfach in der main_simple.c eine eigene uart lib includet 
werden, da die funktion ffls() jetzt einen Parameter erwartet. Der 
Parameter muss ein Funktionspointer auf eine Funktion sein der Form: 
void funktionsName(unsigned char*); zum anzeigen der Daten.
Als Beispiel mit der mitgelieferten uart.c: ffls(uputs); und schon 
funktioniert das :)

@  ffseek-Problem (Gast)
Danke für deine Ausdauer und Hilfe.

Ich war nur am Zweifeln, weil ich den Fehler nicht reproduzieren 
konnte...


Grüße Daniel

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Und noch die AVR-Studio Variante.

von ffseek-Problem (Gast)


Lesenswert?

Ja hervorragend! Werde es gleich mal testen.

@Daniel
Klar, kein Thema.

von ffseek-Problem (Gast)


Lesenswert?

Einwandfrei! Vielen Dank!

PS: Habe die file.h leicht ergänzt:
1
#ifndef _FILE_H
2
3
  #define _FILE_H
4
  #include "config.h"

Sonst hat er gemeckert:

In file included from ../main.c:8:
../mmc/file.h:22: warning: parameter names (without types) in function 
declaration
../mmc/file.h:26: error: syntax error before "unsigned"

von siegmar (Gast)


Lesenswert?

Glückwunsch !!!!!!!!
Also doch ein Softwarefehler !
Komisch das Du den nicht reproduzieren konntest.

Noch einen schönen Tag
Gruß
Siegmar

von Daniel R. (zerrome)


Lesenswert?

Ja doch ein Software Fehler.

Das Problem war, bei mir war der nicht aufgetaucht, da fängt man halt an 
wo anders den Fehler zu suchen...
Ich glaube es hatte etwas damit zu tun wie ich besagte 1M.TXT, aus dem 
Image gelesen hatte.

Na ja, hat ja dann doch noch geklappt^^

Grüße Daniel

von Bernhard (Gast)


Lesenswert?

Hallo Johannes,
wie ich lese, beschäftigst Du dich ebenfalls mit dem Thema Soft-SPI und 
hast schon eine "Vorab"-Variante am laufen. Daniel möchte das in einer 
folgenden Version ja auch generell implementieren.

Ich betreibe hier einen Pollin-AVR mit einer für meine Bedürfnisse 
modifizierten Software von ROBUE. Robue hat auf der RADIG-Basis eine 
AVR-Steuerung entwickelt. Das funktioniert hier alles prächtig.

Nun möchte ich div. Daten in Tages-Files wegschreiben (Datenlogger). 
Hierfür suche ich ein integrierbares "Mini-Dos". Hier scheint gerade 
sowas zu "entstehen".

Das MMC/SD Slot (nach RADIG) hängt bei meinem AVR an Port D und 
funktioniert mit Radigs Testprogramm im Soft-SPI-Mode (mit invertiertem 
Clock-Takt). Nun fehlt nur noch die komplette DOS-Variante als 
Soft-SPI-Version. Leider bin ich beileibe kein C-Profi und nicht in der 
Lage sowas zu schreiben! Kleine Anpassungen hingegen klappen schon.

Kannst Du mir dein "lauffähiges Projekt" zu Testzwecken zukommen lassen 
(d.h. deine xxx.c und xxx.h Dateien im Bundle). Ich könnte dies mal auf 
meinem AVR laufen lassen und ggf. einige Schnipsel komplett übernehmen.
Ich arbeite hier mit WIN-AVR.

Herzlicher Gruß aus Franken
Bernhard

von Daniel R. (zerrome)


Lesenswert?

Hallo Bernhard.
Was meinst du mit:

>...integrierbares "Mini-Dos". Hier scheint gerade
>sowas zu "entstehen".

Meinst du eine Lib die Dateien so auf mmc/sd Karten schreiben kann, dass 
die auch am PC gelesen werden können?

Soft SPI sollte kein großes Ding werden. Komme ich sogar dieses 
Wochenende dazu, glaube ich zumindest mal.

Grüße Daniel

von Daniel R. (zerrome)


Angehängte Dateien:

Lesenswert?

Hallo,
Software SPI ist drin.
Es müssen 3 Dateien ausgetauscht werden,
config.h, mmc.c und mmc.h.

Grüße Daniel

von Johannes N. (strangeman)


Lesenswert?

Hallo Daniel, hallo Bernhard!

Ich hatte für meine Zwecke einfach den Soft-SPI-Code aus der von Ulrich 
Radig genommenen mmc.c wieder reinkopiert (den du, Daniel, im Laufe des 
Projekts offensichtlich entfernt hattest). Das ging aber nicht (siehe 
irgendwo weiter oben) und ich habe einige Delays einfügen müssen  - 
immer bei den clock-Flanken. Ich hatte dafür einfach _delay_us(1); 
genommen, weil es das kleinste Zeitintervall war, was mir einfiel. Diese 
Inline-Assembler-delays bekam ich damals auf die Schnelle nicht hin. 
Siehe hier: Beitrag "Re: MMC SD library FAT16 FAT32 read write"

Bei deinem Code - ich habe ihn fix im MS-NotePad überflogen - sehe ich 
gar keine Delays drin. Wenn es so klappt, dann würde mich interessieren, 
wie sicher das läuft. Bei mir ging damals mit ähnlichem (sogar fast 
gleichem) Code gar nix.

@Bernhard: Ich kann dir gerne mal das Projekt (bzw. die für dieses Thema 
relevanten Dateien - sonst wirds ganz schön viel... ^^) zukommen lassen. 
Ich bin nur leider gerade am falschen PC und komme an die Dateien nicht 
so schnell ran. Lass mir einfach mal deine Mail-Adresse zukommen.

Grüße,
Johannes Neumann

von Michael Z. (incunabulum)


Lesenswert?

Daniel, ich schon wieder :-)

Die neuen Config-Optionen wie auch die Idee, den UART als Argument zu 
übergeben, ist klasse. Damit ist die Lib schön portabel. Wunderbar & 
Danke!

Was mich allerdings wundert ist, wie du den UART-Funktionspointer 
definierst und verwendest. Das macht so nicht unbedingt Sinn... Also - 
irgendwie definiert wird der Funktor (Funktionspointer) in der Config.h. 
Hier:
1
#define MMC_PRINT_DISPLAY void(*uputs_ptr)(unsigned char*) 
2
  MMC_PRINT_DISPLAY;

Und dann z. B. in der file.c verwendet:
1
void lsRowsOfClust (MMC_PRINT_DISPLAY,unsigned long int start_sec){
2
  ...
3
  uputs_ptr(file.name);
4
  ...

Warum brauch ich hier den MMC_PRINT_DISPLAY define, wenn danach doch 
uputs_ptr direkt aufgerufen wird. Was passiert, wenn ich in der config.h 
das entsprechende define ändere?

Andere Ansatz
Warum nicht einfach so etwas:
1
lsRowsOfClust(void (*charHandler)(unsigned char c)) {
2
  ...
3
  (*charHandler)(someChar);
4
  ...

Die Methode definiert die Signatur des Funktionspointers eindeutig. 
Dieser wird in der Methode direkt verwendet. Das #define in config.h ist 
unnötig. Und so du willst, so kann dort vielleicht auch noch ein typdef 
helfen.
1
typedef void (*CharHandler) (u08);
2
3
lsRowsOfClust(CharHandler) {}

Macht das Sinn?

cu, Michael

von Daniel R. (zerrome)


Lesenswert?

Hallo Johannes,

der Code von Ulrich lief so out of the box nicht bei mir.
Ich dachte es liegt daran, das SCK nicht idle Low ist...aber wo ich so 
drüber nachdenke könnte es auch andere Gründe haben.

Für die maximal 8-10 Mhz Soft-SPI Takt der AVR sollte man eigentlich 
keine Pause in der Kommunikation brauchen. Da sind die Karten schon 
schneller.

Läuft denn http://www.mikrocontroller.net/attachment/60728/soft_spi.zip 
das bei dir ohne Probleme? Bei mir mit 5 Verschiedenen Karten schon. 
Unterschiedliche Frequenzen hab ich noch nicht ausprobiert, halt nur die 
16/20 Mhz...

von Daniel R. (zerrome)


Lesenswert?

Hallo Michael,
ja das define ist eigentlich schon überflüssig... gut fliegt beim 
nächsten mal raus.

Ja macht Sinn :)

von Michael Z. (incunabulum)


Lesenswert?

Daniel, dann bitte auch daran denken, die uputs_ptr calls durch das 
übergebene Argument der Methode zu ersetzen :-)

Nur als Hinweis, du machst das schon...

cu, Michael

von Johannes N. (strangeman)


Lesenswert?

Hallo mal wieder.

Ich habe eben versucht, die Version 0.5.6 zum Laufen zu bekommen. Dabei 
brauche ich aber leider noch einige Hilfestellungen...

Zuersteinmal musste ich bei fast allen ffxxx Funktionen die Argumente 
ändern. Denn: Seit der letzten Version, die ich hier genommen hatte, 
wurden alle string-Argumente von signed zu unsigned char geändert. Bissl 
ärgerlich finde ich, denn jetzt kann man nicht mehr
1
ffcd("ORDNER      ");
 schreiben, sondern muss das so machen:
1
ffcd((unsigned char*)"ORDNER      ");
Vielleicht kann mir nochmal jemand kurz erklären, wieso das so sein 
muss.

Desweiteren bekomme ich massenhaft warnings, die ich nicht einfach so 
ignorieren möchte:
1
...
2
In file included from main.c:39:
3
./sd/fat.c: In function 'fat_loadRowOfSector':
4
./sd/fat.c:105: warning: left shift count >= width of type
5
./sd/fat.c: In function 'fat_loadFileDataFromDir':
6
./sd/fat.c:157: warning: comparison is always false due to limited range of data type
7
./sd/fat.c:168: warning: comparison is always false due to limited range of data type
8
./sd/fat.c: In function 'fat_cd':
9
./sd/fat.c:192: warning: comparison is always false due to limited range of data type
10
./sd/fat.c: In function 'fat_loadFatData':
11
./sd/fat.c:527: warning: comparison is always false due to limited range of data type
12
In file included from main.c:40:
13
./sd/file.c: In function 'ffopen':
14
./sd/file.c:29: warning: comparison is always false due to limited range of data type
15
./sd/file.c: In function 'ffmkdir':
16
./sd/file.c:284: warning: comparison is always false due to limited range of data type
17
main.o: In function `flushFileData':
18
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:110: undefined reference to `fat_writeSector'
19
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:113: undefined reference to `fat_setClusterChain'
20
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:115: undefined reference to `fat_makeRowDataEntry'
21
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:118: undefined reference to `fat_writeSector'
22
main.o: In function `ffmkdir':
23
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:288: undefined reference to `fat_getFreeClustersInRow'
24
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:289: undefined reference to `fat_setCluster'
25
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:291: undefined reference to `fat_makeFileEntry'
26
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:301: undefined reference to `fat_writeSector'
27
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:305: undefined reference to `fat_makeRowDataEntry'
28
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:306: undefined reference to `fat_makeRowDataEntry'
29
/home/johannes/Documents/Bastelzeug/ATMega2560/sd/file.c:307: undefined reference to `fat_writeSector'
30
Kompilierung fehlgeschlagen.

Diese Vergleichswarnungen kann man so einfach nicht übergehen - immer, 
wenn ich so einen hatte, gab es arge Probleme. Was tun? Ist ein FASLE 
bzw. TRUE bei meinem avr-gcc was anderes als bei euch? Irgendwelche 
Vorzeichenprobleme oder so?
Zudem dieses komische Problem in der ffmkdir und flushFileData: Vor und 
hinter diesen Funktionen werden diese angeblichen "undefined references" 
aber nicht gemeldet: Warum also findet avr-gcc diese funktionen genau 
dort und nur innerhalb dieser Funktonen nicht und wie behebe ich das? 
Ich bin ziemlich ratlos...

Danke für Hilfe,
StrangeMan

[EDIT] Oh... ich seh gerade: Mache ich den Schalter für die 
Schreibunterstützung an, so verschwinden diese komischen 
reference-Fehler...

von Johannes N. (strangeman)


Lesenswert?

Ok, nachdem ich alle TRUEs und FALSEs durch mTRUE und mFALSE ersetzt 
hatte, gings. Wahrscheinlich hatte irgendeine der Libs, die ich sonst 
noch verwende, auch TRUE und FALSE definiert. Nur eben eines der beiden 
mit negativem Vorzeichen. Vielleicht sollte innerhalb der mmc-lib ein 
eigenes TRUE/FALSE genutzt werden, oder zumindest eine Warnung gemacht 
werden, wenn die Werte schon vorher (z.B. von einer anderen lib) 
definiert sind.

Nein, ganz ohne delays gehts bei mir nicht. Ich hatte ja oben meinen 
Code gepostet. Durch Testen bekam ich heraus, dass man jeweils das 
untere der zwei von mir eingefügten Delays in beiden Funktionen 
(read/write) entfernen kann. Eins muss aber rein.

Achso: Deine Soft-SPI Routinen gehen bei mir nicht. Kann am 
invertiert/nicht-invertiert Problem liegen oder an den (bei mir) 
mangelnden Delays. Müsste ich nochmal prüfen (mach ich später).
Könnte man vielleicht einfach in der nächsten Version noch einen 
Schalter für das Invertieren einfügen?

Grüße,
StrangeMan

von Daniel R. (zerrome)


Lesenswert?

Hallo,
1
./sd/fat.c: In function 'fat_loadRowOfSector':
2
./sd/fat.c:105: warning: left shift count >= width of type

sollte das einzige sein was kommen sollte. Und das ist Ok.

Zu dem TRUE und FALSE, vielleicht mach ich da einfach das "#ifndef" weg, 
dann sollte zumindest mal die Compiler Warnung wegen doppeltem 
definieren kommen.

Ich muss mal sehen ob ich nicht die Tage mal der SPI Geschichte auf den 
Grund gehe. Man müsste das ganze mal mit nem Logic-Analizer zerpflücken, 
hab ich aber keinen...

Grüße Daniel

von Bernhard (Gast)


Lesenswert?

Hallo Daniel, hallo Johannes,
Vielen Dank für Euere Antworten. Soeben habe ich Zeit gefunden um wieder 
mal am "Projekt" zu primeln. Habe die SOFT-SPI-Dateien ausgetauscht und 
die Pins meines ATMega in der Config angepaßt.

--> FUNKTIONIERTE AUF ANHIEB mit 3 verschiedene Karten (512MB bis 2GB 
SanDisk, Transcend, Kodak) sowohl FAT16 als auch FAT32, Super-Arbeit 
Daniel!!

Eine Frage hätte ich noch. Ich mußte im File main_simple.c die Zeile:
ffls(uputs);
auskommentieren sonst meckert der Compiler mich wie folgt an:

E:\05_06 mit Soft_spi\default/../main_simple.c:80: undefined reference 
to `ffls'
make: *** [MMC-Win.elf] Error 1
Build failed with 1 errors and 1 warnings...

Vermutlich habe ich da nochwas nicht ganz verstanden (eilt aber nicht).

Für Johannes,
vielen dank für das Angebot Johannes, hat sich nun aber erledigt da 
Daniel so schnell gearbeitet hat.

Herzlicher Gruß aus Franken
und nochmals MERCI !!
Bernhard

von Alex (Gast)


Lesenswert?

Hallo zusammen!

Bei mir läuft die Library leider noch nicht so reibungslos. Ich habe 
auch die SPI erweiterung hinzugefügt. Hat allerdings keine Abhilfe 
gebracht Ab und zu erstellt mir der Atmega leider noch kryptische Files 
obwohl das eigentlich nicht so sein sollte. Ich benutze dazu folgenden 
Quelltext :


unsigned char file_name[11]="LOG     TXT";
unsigned char new_log[18]="** New logging **";

...

if(sdiswriteable()&&sd_merker==0)//Überprüfungob Karte steckt
durchSchalter
    {
      while (mmc_init() == FALSE){
        nop();
        break;
      }
      if(TRUE==fat_loadFatData()){
        sd_merker = 1;

        ffopen(file_name);
        ffseek(file.length);
        ffwrite(0x0D);
        sd_laufer=0;
        do{
          ffwrite(new_log[sd_laufer]);
          sd_laufer++;
        }while(sd_laufer<17);0,
        ffwrite(0x0D);
      }
    }


if(!sdiswriteable() && sd_merker==1)// SD-Karte auswerfen
    {
      ffclose();
      sd_merker = 0;
    }

if(sd_merker==1)
    {
      portauslesenLAN(daten);
      ffwrites(daten);
    }


Eigentlich sollte der hier doch nur die Datei Log.txt anlegen und dort
Daten reinschreiben. Mittels sdiswriteable() wird abgefragt ob ein
Schalter umgelegt ist, damit Daten auf der SD Karte gesichert werden.
Ich benutze auch einen ungeraden Quarz (14745600 Hz) könnte das auch
daran liegen? Weiterhin benutze ich einen ATmega644.

Bin für jede Hilfe dankbar

Gruß
Alex

von ffseek-Problem (Gast)


Lesenswert?

Probier es doch einfach mal mit einem 8 MHz Quarz.

von Alex (Gast)


Lesenswert?

Habe ich leider nicht hier. Allerdings habe ich einen 16 MHz Quarz. Ich 
werde den mal ausprobieren(geht das auch?):)

Danke schonmal für die Hilfe
Alex

von Johannes N. (strangeman)


Lesenswert?

Hallo Alex!

Thema kryptische Files: Ich hatte eine Zeit lang eine 16MB-Karte 
(letztendlich waren es 12MB), die mit einer neuen Kamera geliefert 
wurde. Die hatte ein FAT12 Dateisystem (da zu klein für FAT16; das 
braucht 16MB+). Sobald ich die Schreibunterstützung aktiviert habe, 
kamen bei mir auch desöfteren kryptische Files raus, da der Code eben 
für FAT16/32 ist und bei FAT12 offensichtlich die FAT kaputtschreibt. 
Dann werden teils Daten von der Karte gelesen, die mit der 
entsprechenden Datei eigentlich nichts zu tun haben: Das sind dann die 
kryptischen Daten.
Also Achtung mit so kleinen Karten!

Ich hoffe, das kann dir weiterhelfen,
Johannes

von Daniel R. (zerrome)


Lesenswert?

Hallo,
bin mir nicht sicher, ob es einzig und alleine daran liegt, aber das
>unsigned char file_name[11]="LOG     TXT";
muss mindestens 12 Zeichen lang sein. Also:
1
unsigned char file_name[12]="LOG     TXT";
Wegen dem \0 was bei einem String noch hinten dran kommt.
Sonst sieht das auf den ersten Blick ja Ok aus was du da gepostet hast.
Besteht der Fehler immer noch, musst du ein wenig mehr über die Daten 
schreiben, und ob du noch andere Sachen verändert hast.
Wieviel Ram hat dein Controller?
Am Takt des Controllers wird es glaube ich nicht liegen...



Grüße Daniel

von Alex (Gast)


Lesenswert?

Danke schonmal für die Hilfe.

Ich benutze allerdings ein 2 Gig Karte mit Fat32. Daran sollte es 
eigentlich nicht liegen.

Das mit den 12 Zeichen anstelle von 11 habe ich auch geändert. Trotzdem 
treten immer noch die gleichen Kryptischen Dateien auf.

Anstelle die Datei zu öffnen erstellt der Mikrocontroller dann eine 
Kryptische Datei und schreibt da hinein. (Jedenfalls wird die log.txt 
Datei manchmal nicht angefasst.) Manchmal tretten auch noch andere 
Fehler auf. Z.B. kann die Datei selber nicht vom Computer gelesen 
werden. Könnte ja auch mit den Kryptischen Dateien zusammenhängen wenn 
irgendwo was auf der Karte wild geschrieben wird.

Eigenlich habe ich die Library nicht verändert. Die Daten die ich auf 
die Karte schreibe sind die Portdaten überführt in Strings (als Basis 
für das ganze benutze ich das AVR Webmodul vom Ulrich Radig 
(http://www.ulrichradig.de/home/index.php/avr/avr-webmodule).

Gibt es den eine Maximale Stringlänge die ich an ffwrites übergeben darf 
? Immoment überprüfe ich ob hier der Fehler liegt. Werde euch auf dem 
laufenden halten. Wenn euch noch was einfällt wäre ich sehr verbunden :)

Grüße Alex

von D. B. (deadbuglabs)


Lesenswert?

Sag mal wie groß dein Datensegment ist.
Formatiere die SD-Karte mal mit einem Windows-Rechner komplett (kein 
Quickformat).

von Alex (Gast)


Lesenswert?

Hallo zusammen!

Also ich habe den Fehler gefunden (die SD Karte war komplett mit windows 
formatiert; )

Aber der Fehler lag darin, dass die Funktion

void ffwrites( unsigned char *s ){
    while (*s) ffwrite(*s++);
    fat.bufferDirty=1;
  }

irgendwie die falsche länge des Strings ermittelt hat, den ich übergeben 
habe. Ich habe das abgeändert, indedm ich nun eine Feste Anzahl von 
Zeichen mittels ffwrite auf die SD Karte schreibe und es läuft.

Vielen Dank für eure Hilfe !

von Alex (Gast)


Lesenswert?

Nocheinmal Hallo :)

schon wieder der Alex :). Ich habe noch ein Problem. Ich schreibe Daten 
auf eine SD Karte. Hiernach lösche ich die Daten oder Formatiere die 
Daten mittels XP (der Löscht die Daten ja nicht richtig sondern nur die 
Fat-Entry (auch Formatieren hilft nicht wirklich)).

Nun will ich wieder auf die Datei schreiben. Aber anstelle neue Daten in 
eine Datei zu schreiben hängt der die Daten einfach an die alten Datei 
an (die durch das Löschen ja eigentlich schon gelöscht sein sollten). 
Ein generelles schreibe über alle Dateien ist allerdings auch 
unerwünscht. Gibt es eine Möglichkeit zu erkennen, ob die Datei von 
Windows gelöscht wurde und so das einfache schreiben in gelöschte 
Dateien zu verhindern?

Grüße Alex

von Daniel R. (zerrome)


Lesenswert?

Hallo,
also du Formatierst mit Windows die Karte, machst Datenträger sicher 
entfernen und dann erkennt die lib die Datei nicht als gelöscht?
Klingt seltsam!
Du könntest aber z.B. auch einfach mit der lib die Datei löschen, bevor 
du sie neu anlegst um so sicher zu gehen, das du sie wirklich neu 
anlegst...

Grüße Daniel

von FlipFlop (Gast)


Lesenswert?

http://www.sdcard.org/consumers/formatter/
damit wird die Karte auch unter windows komplett formatiert.

von Alex (Gast)


Lesenswert?

Hallo zusammen!

Also ich würde sagen das das dann nicht der Fehler ist. Selbst nachdem 
ich die SD-Karte mit dem tool formatiert habe ging es nicht. Ich habe 
allerdings immer noch Fehler. Wenn ich dem Fehler näher gekommen bin 
schreibe ich nochmal :).

Grüße
Alex

von Daniel R. (zerrome)


Lesenswert?

Hallo,
was gibt es neues an der Front, Alex?

Hab mir dieses Beitrag "Re: MMC SD library FAT16 FAT32 read write" 
Problem von dir mal durch den Kopf gehen lassen, ich wette es lag daran, 
dass du keinen String übergeben hattest sondern irgendwelche Daten.
Der Punkt ist, ffwrites() schreibt solange Daten, bis es auf '\0' alias 
0 trifft. Was ja das Ende eines Strings in c beschreibt.
Wenn in den Daten keine 0 bzw. '\0' vorkommt, wird der Ram Inhalt ab der 
Adresse es übergebenen Pointers geschrieben, bis irgendwann im Ram eine 
0 steht :)
Folge: Kryptische Datei

Poste doch mal deinen kompletten Code, dann schau ich mir das mal an.

Das Format Problem schau ich mir jetzt gleich nochmal genauer an. Bin 
mir aber sicher, dass bei Fat32 beim Formatieren außer dem Fat Bereich 
auch zumindest das Root-Dir mit gelöscht wird. Ist also nicht möglich da 
so einfach noch Reste einer Datei zu finden. Zumindest nicht in der von 
dir beschriebenen Weise.

Grüße Daniel

von Daniel R. (zerrome)


Lesenswert?

Beim Formatieren mit Fat32 und Windows XP wird der Fat Bereich gelöscht 
und natürlich auch der Root-Dir Bereich!
Somit gibt es keine Möglichkeit so einfach an die Daten zu kommen, die 
aber schon noch auf der Karte sind.

von Alex (Gast)


Lesenswert?

Nochmal der Alex,

also das Problem besteht weiterhin. Habe ich auch gedacht, dass das mit 
den Strings (oder mit der Länge der Strings) zusammenhängt. Allerdings 
Benutze ich immoment nur Quellcode der nach folgendem Schema aufgebaut 
ist also keine ffwrites(); Funktionen

while (*zwischespeicher_pointer) ffwrite(*zwischespeicher_pointer++);

Die Kryptischen Dateien sind schon weniger geworden allerdings auch noch 
nicht ganz weg. Ich Überprüfe gerade noch ein Paar Möglichkeiten. Mein 
nächster Ansatz wird sein, das ich die Zeichenlänge der Strings 
irgendwie falsch habe. :) Wenn es Funktioniert sag ich bescheit.

Eine Frage habe ich noch. Und zwar geht es schon meistens relativ gut 
aber manchmal kommt es vor das Ich Text finde (ich schreibe nur .txt 
Dateien) den ich früher auf die Karte geschrieben habe. Kann es sein das 
wenn solch ein Text bei anhängen an die Datei gefunden wird, einfach der 
Text mit angehängt wird?

Grüße
Alex

von ehem. ffseek-problem (Gast)


Lesenswert?

Hi Alex,

beschreibe doch mal wie Du die Karte hardwareseitig an den µC 
angeschlossen hast.

von Alex (Gast)


Lesenswert?

Hmm irgendwie komme ich noch nicht weiter. Ich kann ja mal die wichtigen 
Quelltextteile angeben und zeigen was nicht geht.
sd_ms ist sind hierbei Millisekunden(diese werden auch normal in die SD 
Karte geschrieben.



unsigned char new_log[18]="** New logging **\0";
unsigned char file_name[12]="LOG     TXT";
char after_str[7]="After \0";
char ms_str[4]=" ms\0";

...SD initialisieren...


while(1){

ffwrite(0x0D);
ffwrite(0x0D);
char zwischenspeicher[5];
char* zwischespeicher_pointer;

zwischespeicher_pointer  = after_str;
while (*zwischespeicher_pointer) ffwrite(*zwischespeicher_pointer++);

itoa(sd_ms, zwischenspeicher,10); // Into to ascii
zwischenspeicher[4]='\0';
zwischespeicher_pointer = zwischenspeicher;
while (*zwischespeicher_pointer)
          ffwrite(*zwischespeicher_pointer++);

zwischespeicher_pointer = ms_str;  // Text " ms\0";
while (*zwischespeicher_pointer) ffwrite(*zwischespeicher_pointer++);

}

Was in die SD-Karte geschrieben wird sieht folgendermaßen aus

After 1 ms

101

201
...

Allerdings sollte doch folgendermaßen Sachen in die SD Karte geschrieben 
werden.

After 1 ms
After 101 ms
After 201 ms

Die Frage die ich habe ist warum er nach dem ersten Durchlauf die 
Strings z.B. nicht mehr mitausgibt.

Grüße
Alex

von Alex (Gast)


Lesenswert?

Noch eine Anmerkung wenn ich

zwischespeicher_pointer  = after_str;
while (*zwischespeicher_pointer) ffwrite(*zwischespeicher_pointer++);

in

for(uint8_t i=0;i<11;i++)
  {
         ffwrite(after_str[i]);
  }


umwandel schreibt mir der ATmega alle möglichen Strings auf die SD Karte 
die eigenlich für Usart verwendet werden. Das verstehe ich auch noch 
nicht.

Gruß Alex

von Alex (Gast)


Lesenswert?

OK Problem gelöst.

Falls ich die Strings folgendermaßen auf die SD-Karte schreibe
ffwrite('A');ffwrite('f');ffwrite('t');ffwrite('e');ffwrite('r');ffwrite 
('  ');

geht es ohne Probleme. Ich weiß allerdings nicht wirklich warum :).

Danke für Eure Hilfe!

Gruß
Alex

von Johannes N. (strangeman)


Lesenswert?

Hallo Alex!

Ich hab mich jetzt nur kurz mit deinem Problem beschäftigt, aber etwas 
ist mir aufgefallen:

while (*zwischespeicher_pointer) ffwrite(*zwischespeicher_pointer++);

Da ist doch genau das selbe Problem wie in der ffwrites: Das Ding hört 
nur auf, wenn am Ziel des Pointers Null steht (Bedingung der Schleife). 
Du sagtest jedoch, dass es an diesem \0-Problem nicht liegen kann, weil 
du die ffwrites-Funktion nicht verwendest. Dein Code macht aber genau 
das selbe wie diese Funktion.

for(uint8_t i=0;i<11;i++)
  {
         ffwrite(after_str[i]);
  }

Da passiert folgendes: Du greifst auf das i-te Byte nach dem Pointer 
"after_string" zu. Da dieser aber nur 7 Byte groß ist, und du hier 11 
Bytes liest, liest der uC über das Ende von after_string hinaus. Daher 
kommt der Müll von den USART-Routinen, der eben zufällig im Speicher 
dahinter liegt.

Keine Ahnung, ob das jetzt so 100% richtig ist, ich habe selbst erst vor 
zwei Jahren angefangen mit C. Aber vielleicht hilfts ja doch. =c)

Johannes Neumann

von Alex (Gast)


Lesenswert?

Hallo Johannes

aber wie kommt es dann das auch bei

for(uint8_t i=0;i<11;i++)
  {
         ffwrite(after_str[i]);
  }

Müll rauskommt?

Ich meine der ließt ein Paar bytes rüber aber bei mir auf der SD-Karte 
stehen nachher sehr viele Strings die mehr als 3 oder 4 Byte drüber 
gehen. Das hat mich so sehr gewundert.

von Daniel R. (zerrome)


Lesenswert?

Hallo,
hab heute und morgen nicht viel Zeit...
Lass dir doch mal immer wenn du etwas schreibst, das auch anzeigen, z.B. 
über uart, vielleicht grenzt das etwas ein.

>Ich meine der ließt ein Paar bytes rüber aber bei mir auf der SD-Karte
>stehen nachher sehr viele Strings die mehr als 3 oder 4 Byte drüber
>gehen. Das hat mich so sehr gewundert.

Bist du sicher, dass nicht vielleicht auch alte strings von vorherigen 
Versuchen dort stehen?

Grüße Daniel

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.