Forum: Projekte & Code MMC/SD-Karte mit FAT16 an AVR


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen!

In den letzten Tagen habe ich mein MMC/SD-Interface für AVR-Controller
fertiggestellt. Dem ein oder anderen wird es inzwischen vielleicht
schon ein bisschen zuviel, schließlich gibt es dafür schon eine ganze
Menge Alternativen, aber ich wollt es eben selber machen.

Implementiert habe ich den low-level-MMC-Zugriff, den Zugriff auf die
Partitionstabelle und FAT16 Lese- und Schreibunterstützung.

Auf
  http://www.roland-riegel.de/sd-reader/
findet Ihr meine Testschaltung und den ausführlich dokumentierten
Quellcode. Ich habe das aber auch an diesen Beitrag angehängt.

Testen konnte ich nur mit einer einzigen 128MB-Karte, es könnte also
sein, dass es mit anderen Karten noch Probleme gibt.

Vielen Dank noch an Ulrich Radig, von dem ich mir die einfache, aber
gut funktionierende MMC-Anbindung mittels Spannungsteiler abgeschaut
habe.

Über Anregungen und Kommentare würde ich mich freuen.

Gruß,
Roland

von Senf (Gast)


Lesenswert?

Igitt was haben denn deine *.c fürne komische formatierung.
Schade, nix mit Editor anschaun, törnt mich grad ab das reinzuziehen.

von André K. (freakazoid)


Lesenswert?

@Senf:
Sieht bei mir okay aus. Deine Wortwahl und Schreibstil lassen eher
vermuten, daß Kiffen doch gesundheitsschädlich ist ;)

von Roland R. (roland) Benutzerseite


Lesenswert?

@Senf

Ich habe die Anwendung unter Linux entwickelt, daher haben die
Textdateien die Unix-Zeilenende-Markierung.

Wenn Du Sie aber mit einem vernünftigen Editor öffnest und nicht grad
mit dem Windows-Einfachst-Editor, dann ist alles ok. Sogar Wordpad
schafft das.

von SuperUser (Gast)


Lesenswert?

@Roland
Da du ja ohne FAT-Buffer etc. arbeitest, interessiert mich die
Geschwindigkeit die du erreichst. Hast du schon mal was gemessen?

von Roland R. (roland) Benutzerseite


Lesenswert?

@SuperUser

Ich habe jetzt mal mit einer 32kB-Datei gemessen. Der Durchsatz liegt
beim Lesen von 8Byte-Blöcken nur bei ca. 400B/s. Das überrascht mich
selbst ein bisschen, aber bei genauerer Betrachtung kommt das schon
hin. Denn für den ersten Cluster (also bis 16kB) braucht er nur ein bis
zwei Sekunden.

Der hauptsächliche Grund hierfür dürfte sein:
Im Dateideskriptor speichere ich den Cluster der aktuellen
Dateiposition nicht mit ab, sondern suche mir diesen immer neu. Solange
ich beim Lesen innerhalb des ersten Clusters bleibe, ist er
verhältnismäßig schnell, da er jeden 512Byte-Block wirklich nur einmal
liest. Nach dem ersten Cluster bricht er dann ein, da der Block-Puffer
durch das zwischenzeitliche Suchen des Clusters nicht mehr greift.
Ursprünglich hatte ich sogar den Cluster vom vorangehenden Lesevorgang
abgespeichert, hatte dann aber Probleme bei Dateien, die genau auf
einer Clustergrenze enden.

Sonstiges:
- Sehr geringe Blockgröße pro Lese-Aufruf.
- Wie Du schon gesagt hattest: kein FAT-Puffer. Der wäre aber schon bei
meiner 128MB-Karte 15kB groß, man kann sich das also nur mit externem
RAM leisten.
- SPI läuft mit 250kHz, also brutto max. ca. 30kB/s.

Ich denke, ich muss den Cluster doch zwischenspeichern. Das ist mir
jetzt klar geworden. Danke :)

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Die schlechte Lesegeschwindigkeit durch die fehlende Zwischenspeicherung
der Clusternummer habe ich nun korrigiert. Im Anhang findet ihr den
neuen Quelltext.

Das Auslesen einer 1MB großen Datei dauert nun 52 Sekunden, das
entspricht also ca. 20kB/s.

Über weitere Beiträge würde ich mich freuen.

von Fabian (Gast)


Lesenswert?

Sehr interessant :)
überlegst du eigentlich auch ein Programm zum schreiben von daten zu
entwickeln?
Ich hatte mal folgende Idee:
Von einer SD Karte daten lesen und diese dann auf einer Festplatte
abspeichern...(speziell für Fotos) ich weiss nicht mit wieviel aufwand
das zu realisieren ist.

von Roland R. (roland) Benutzerseite


Lesenswert?

@Fabian

> überlegst du eigentlich auch ein Programm zum schreiben von daten
> zu entwickeln?

Was meinst Du damit? FAT16 Schreibunterstützung? Die ist doch schon
implementiert?

von The E. (the_engineer)


Lesenswert?

*abo

von Lupin (Gast)


Lesenswert?

die 3.3v stromversorgung hast du ja ganz elegant gelöst :)

von Roland R. (roland) Benutzerseite


Lesenswert?

Wie zu Beginn gesagt, das war die Idee von Ulrich Radig.
Natürlich ist das recht einfach, aber wenn man eine Schaltung nur für
Testzwecke entwirft, brauchts nicht mehr. Ansonsten kann man ja einen
3,3V-Spannungsregler verwenden, der dann oft ohnehin noch von anderen
Komponenten benötigt wird.

von Fabian (Gast)


Lesenswert?

@Roland
ja sorry habe mich etwas unsauber ausgedrückt:
Schreiben ist zwar möglich aber nur mit einer sehr geringen
Geschwindigkeit, oder habe ich da etwas falsch verstanden?
Weisst du zufällig wie man diese Geschwindigkeit erhöhen könnte auf
z.b.  1MB/s ?

von Roland R. (roland) Benutzerseite


Lesenswert?

Nein, solche Geschwindigkeiten sind wohl nicht möglich. Soweit ich mich
erinnere, unterstützen die Karten im verwendeten SPI-Mode nur max.
400kHz, also brutto 50kB/s. Für 1MB/s wären demnach über 8MHz nötig,
was sowohl die Karte als auch den AVR weit überfordert.

von Lupin (Gast)


Lesenswert?

MMC karten unterstützen bis zu 20 Mhz SPI takt. steht auch in den
datenblättern.

von Gast (Gast)


Lesenswert?

SD-Karten bis 25 MHz.

von Pete (Gast)


Lesenswert?

@roland
Wo hast Du denn den Kartenslot her ?

von Roland R. (roland) Benutzerseite


Lesenswert?

@Lupin, Gast
Danke für die Info. Meine Datenblätter sind ziemlich knapp und an
einigen Stellen stark gekürzt. Ich habe den SPI-Takt nun auf das
Maximum von 8MHz bei 16MHz CPU-Takt gestellt. Statt 52 Sekunden braucht
der uC nun nur noch 13 Sekunden, um 1MB auszulesen. Das entspricht
78kB/s. Hmm, doch nicht so viel schneller...

@Pete
Von Reichelt, CONNECTOR SD 21 oder 22, leider sehr teuer.

von Lupin (Gast)


Lesenswert?

Ich meine mal auf wikipedia gelesen zu haben das SD oder MMC maximal
2mb/s kann... ich denke mal es liegt aber einfach an der Ansteuerung
mit SPI und die meisten karten erreichen den wert nicht wirklich.
78kB/s ist aber doch schon recht langsam, wenn ich mit der
Geschwindigkeit am PC zugreifen müsste würde ich irgendwann durch
drehen (wenn man nur mal daran denkt eine 4gb karte zu füllen). Ich
wusste gar nicht das die reichelt connectoren einen auswurf mechanismus
haben...

von Roland R. (roland) Benutzerseite


Lesenswert?

Nun ja, es ist ja ein AVR und kein PC...
Es ginge wahrscheinlich um vieles schneller wenn der FAT16-Overhead
nicht wäre. Gerade auf den AVRs mit ihren 8Bit-Registern ist das nicht
zu vernachlässigen, da FAT16 viele 16Bit- und 32Bit-Operationen
benötigt. Ich vermute, das es auf einem MSP430, ARM oder auch AVR32
wesentlich besser liefe.

Werde es auch mal mit größeren Blockgrößen versuchen. Im Moment lese
ich ja immer nur 8Byte pro read-Aufruf.

von m@u (Gast)


Lesenswert?

@Pete

Es gibt auch wesentlich billiger Sockets. Ich weiss gerade keinen Shop
in DE, der das zu diesem Preis schafft, aber diese hier (CH) können
das: http://www.compona.ch (~2CHF)
http://www.farnell.ch (2-19CHF, je nach Ausführung)
Es kommt einfach darauf an, was für Ansprüche du an den connector hast.
Wenn du nicht einen suuuper duuuper Connector mit Schirmung und
Schleudersitz brauchst, dann bekommst du einen für weniger als zwei
Euronen.

Gruss, Matthias

von Roland R. (roland) Benutzerseite


Lesenswert?

Habe jetzt nochmal verschiedene Puffergrößen ausprobiert, die ich
fat16_read_file() übergebe. Das hat, wie sich gezeigt hat,
entscheidenden Einfluss:

Puffer (B)  |  Zeit (s)  |  Geschw. (kb/s)
------------------------------------------
     8      |    13      |      78
    16      |     9      |     114
    32      |     6      |     171
    64      |     5      |     205

Also eine Steigerung um das 2,5-fache.

von Lupin (Gast)


Lesenswert?

also mit so kleinen reads ist das auch echt ineffizient... warum liest
du nicht 512 byte pro read command? Wie machst du das denn bei der MMC
funktion? Führst du partial reads aus? Im Normalfall wirst du immer 512
byte blöcke von der karte lesen müssen, die restlichen bytes "weg zu
schmeißen" kostet natürlich viel Zeit.

Wenn es tatsächlich um hohe Transferaten geht, dann wird ja meistens
auch in großen Blöcken gelesen, logisch oder? :)

von Fly (Gast)


Lesenswert?

Na wahrscheindlich geht ihm das RAM aus.... leider immer das selbe,
irgendeinmal trifft man auf die Grenze der AVRchen.

von Roland R. (roland) Benutzerseite


Lesenswert?

Richtig. Ich habe nur 1 kB RAM, die Hälfte davon nutze ich als
Schreib-/Lesepuffer für die low-level-Lesefunktionen. Den Rest brauche
ich für Dateisystem-, Datei- und Verzeichnis-Deskriptoren und natürlich
für den Stack.

Ich wollte den Kartenzugriff so flexibel wie möglich halten. Die
höheren Schichten (also Partitionshandling sowie FAT16) wissen
überhaupt nichts davon, dass sie von einer MMC/SD-Karte lesen,
geschweige denn dass dies für gewöhnlich in Einheiten von 512 Byte
geschieht. Die MMC/SD-Funktionen bieten "nach oben" die Möglichkeit
an, Daten beliebiger Länge von einem beliebigen Offset anzufordern oder
dorthin zu schreiben, egal ob das von der Karte selbst schon unterstützt
wird oder nicht.

Das ist vorteilhaft, weil ich dann z.B. zum Lesen eines FAT16
Verzeichniseintrags, der nur 32 Byte groß ist, mich nicht um die
Eigenheiten des Speichermediums kümmern muss und so dieser Code
Hardware-unabhängig wird.

Es ist also Aufgabe der Abstraktion, sich um die niederen Dinge wie
Einschränkungen der Hardware zu kümmern. Im extremen Fall, dass man
sich die 512 Byte Puffer sparen will, bringt dies natürlich Einbußen in
der Performance mit. Dafür ist der Code dann aber auch extrem klein und
genügsam. Benutzt man aber diesen Puffer, erhält man bessere
Performance und es genügt beim sequentiellen Lesen ein einfaches
memcpy, um die Anfrage auszuführen.

Ein weiteres Kapitel ist natürlich der Schreibzugriff. Wenn ich auch
dies von beliebigen Offsets aus zulassen will, benötige ich zwingend
einen Puffer, um den Teil des Blocks, der nicht überschrieben wird, mit
den neuen Daten zusammenzufügen. Die Tatsache, dass dies von den
MMC/SD-Routinen übernommen wird, vereinfacht wiederum den Code in den
höheren Ebenen. Denn, um beim Beispiel zu bleiben, der FAT16-Code muss
sich dann eben nicht mehr darum kümmern, die 32 Byte für einen neuen
Verzeichniseintrag mit dem vorhandenen 512 Byte-Block auf der Karte
zusammenzufügen. Aus seiner Sicht überschreibt er einfach die alten 32
Byte mit den neuen 32 Byte.

Und wenn es um hohe Transferraten geht, dann spendiere ich ein bisschen
mehr RAM, und schon kann ich z.B. 4 kB auf einen Schlag lesen, und die
MMC/SD-Funktionen kümmern sich um die Aufteilung in einzelne 512
Byte-Anfragen an die Karte.

von Tobias G. (tobster)


Lesenswert?

*abo

von Peter Baumann (Gast)


Lesenswert?

Hallo,

in den Thread hat sich zwar schon ne weils nichts getan hoffe aber
trotzdem auf ne Antwort.

Ich bin auch grad dabei ne SD-Karte über SPI anzusteuern.

Als erstes sende ich an die Karte 10mal 0xff und dann das Kommando
0x40,0x00,0x00,0x00,0x00,0x95 (CMD 0) alles in 8bit Blöcken. Danach
polle ich mit 0xff um die Antwort von der SD-Karte zu bekommen.
Normalerweise müste ich doch nun nach dem CRC irgendwann eine 0x01 von
der Karte zurückbekommen.

Komisch ist das die SD-Karte schon ab dem vierten 0x00 Block des
Kommandos,immer mit 0xFE und gleich dannach mit 0x03 antwortet. Dann
bekomme ich 2-3 Blöcke garnichts und dann die erwartete 0x01.

Kann jemand die Signale deuten? Kann ich die 0xFE und 0x03 ignorieren
oder ist das ein Error Code?

Danke im vorraus!!

Mfg Peter Baumann

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Peter,

Auf Anhieb kann ich mit dem von Dir beobachteten Verhalten auch nichts
anfangen.

Wichtig ist, dass Du der Karte nach dem Anlegen der Spannung ein paar
Takte Zeit gibst, um sich selbst zu initialisieren. Das kannst Du
machen, indem Du beispielsweise 10x 0xff sendest.

Erst dann sendest Du CMD0. Wie bei jedem R1-Befehl ist das erste Byte,
das ungleich 0xff zurückkommt, Deine Antwort. Danach solltest Du der
Karte nochmal ein paar Takte Zeit geben, um intern weiterarbeiten zu
können.

Ich polle dann ein paar Mal das Busy-Bit in der Antwort auf CMD1, um zu
warten, bis die Karte fertig ist.

Schau Dir doch mal meinen Code an, den ich auf meiner Homepage oder
hier in diesem Thread gepostet habe. In der Datei sd_raw.c steht
eigentlich alles drin, was Du brauchst. Den Code habe ich allerdings
noch nicht mit vielen Karten testen können. Mit meiner funktioniert er
aber.

Gruß, Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hi zusammen,

Ich habe eine neue Version auf
  http://www.roland-riegel.de/sd-reader/
zur Verfügung gestellt. Die ZIP-Datei habe ich auch an dieses Posting
angehängt.

Verbesserungen sind unter anderem:
- sehr viel zuverlässigere Karteninitialisierung
- viele Geschwindigkeitsverbesserungen
- Superfloppy-Unterstützung
- bessere Überprüfung des FAT16-Dateisystems beim Öffnen
- Fehler beim Vergrößern von Dateien behoben
- Fehler beim Anlegen einer Datei >31 Buchstaben beseitigt
- viele andere Dinge

Viele Grüße,
Roland

von Gernot F. (gernotfrisch)


Lesenswert?

Kann ich damit schnell an das Ende einer Datei springen. Ich möchte MP3
tags auslesen, und die stehen am Ende der Datei (und die haben 200MB)

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Gernot,

Ja das sollte möglich sein. Bzgl. der Geschwindigkeit müsstest Du das
einfach mal ausprobieren, 200MB sind ja viele tausend Cluster und das
könnte schon einige Zeit in Anspruch nehmen. Ich selbst habe das noch
nicht ausprobiert.

Gruß,
Roland

von Gernot F. (gernotfrisch)


Lesenswert?

Muss ich testen. Ich am besten einen ATmega32 mit 16MHz, oder? Kannst Du
einen Ausdruck von der Platine dazulegen - als png oder so? Ich hab das
Programm nicht, mit dem Du das gemacht hast.

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, bitteschön. Siehe Anhang.

Du musst Dir aber zum Testen nicht gleich eine eigene Platine
herstellen. Die Schaltung kannst Du auch auf einem Steckbrett aufbauen.
Beachte aber bitte, dass die einfachen Spannungsteiler und die zwei
Dioden zum Bereitstellen der Betriebsspannung für die Karte keine
optimale Lösung sind, durch die einzelne Karten eventuell nicht
zuverlässig arbeiten oder sogar beschädigt werden könnten. Besser wäre
ein eigener Spannungsregler sowie vernünftige Pegelkonverter für den
SPI-Bus.

Roland

von Roland R. (roland) Benutzerseite


Lesenswert?

Ach so, zur MCU. Ja klar, ein ATmega16 ist ok. Mit dem kannst Du aber
nicht meine Platine nutzen. Für die brauchst Du einen ATmega8 oder
pinkompatiblen, also einen von ATmega8/48/88/168.

Roland

von Malte I. (maltomat)


Lesenswert?

Hallo,

ich versuche gerade, den sd-reader mit einem ATmega32 zu betreiben.
Muss ich dann in SD_RAW_CONFIG.H Änderungen vornehmen, da hier MOSI,
MISO etc. an anderen Pins liegen? Ich bin mir nicht ganz sicher, weil
irgenwo steht, es würde genügen im Makefile eine entsprechende Änderung
vorzunehmen. In SD_RAW_CONFIG.H steht aber explizit zB.

#define configure_pin_mosi() DDRB |= (1 << DDB3).

Beim Mega32 ist MOSI aber an Pin 5.
Bitte um Aufklärung für einen Anfänger.

Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Wenn Du die neue Version des sd-reader von vor zwei Tagen verwendest,
sollten die Pins für den SPI-Bus bereits stimmen. Daneben solltest Du
aber noch je nach Möglichkeiten Deines Karten-Slots die folgenden
#defines ändern:
#define configure_pin_available() DDRC &= ~(1 << DDC4)
#define configure_pin_locked() DDRC &= ~(1 << DDC5)
#define get_pin_available() ((PINC >> PC4) & 0x01)
#define get_pin_locked() ((PINC >> PC5) & 0x01)

Wenn Dein Slot keine Pins zum Detektieren einer Karte bzw. der Position
des Schreibschutzschalters hat, änderst Du diese ab zu:
#define configure_pin_available()
#define configure_pin_locked()
#define get_pin_available() 0
#define get_pin_locked() 0

Im Makefile änderst Du folgende Zeilen passend ab:
MCU := atmega168
MCU_AVRDUDE := m168
MCU_FREQ := 16000000UL

Das sollte dann alles sein.
Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

ok, alles klar, ich hatte die alte Version.

Danke
Malte

von Malte I. (maltomat)


Lesenswert?

Hallo,

ich krige die SD Karte nicht zum laufen. Bereits beim card-reset in
sd_raw_init() kommt ein Abbruch. Kann es daran liegen, dass ich eine
miniSD Karte (mit Adapter) verwende? Ansonsten habe ich einen 3.3V
Spannungsregler und Widerstände für die Pegelanpassung.

Noch eine Frage: Kann ich den AVRISPmkII Programmieradapter eigentlich
beim Testen dranlassen, oder stört er die SPI Kommunikation?

Ist sonst noch was zu beachten, spezielle Fuses oder so?

Gruß
Malte

von T.S. (Gast)


Lesenswert?

Malte

Auch ich habe eine Mega32, bei mir läuft's.

Der Programmier-Adapter stört bei mir bei einigen SD-Karten, nicht bei
allen. Und beim Flashen des Mega ziehe ich immer vorsichtshalber die
Karte raus.

Eine MiniSD-Karte sollte eigentlich kein Problem sein und der
3,3V-Regler ist das beste was Du machen konntest. Die Dioden-Lösung ist
nach meiner Erfahrung sehr unzuverläßig.

Baue doch einfach einige Debug-Meldungen in den Code ein. Man kann
sonst immer so schlecht sehen was wirklich passiert. z.B. mit einfachen
Meldungen die Du dann auf der seriellen Schnittstelle sehen kannst. So
etwa in sd_raw.c:

if(!sd_raw_available())

{
        printf_P(PSTR("Error: sd_raw_available\n"));
  return 0;

}

usw.

Platz hast Du ja im Mega32 vorerst reichlich zur Fehlersuche.

Spezielle Fuse verwende ich nicht, außer für den ext. Quarz.

Torsten

von T.S. (Gast)


Lesenswert?

Gernot

>..schnell an das Ende einer Datei springen.

Nachdem Roland das Buffering überarbeitet hat ist das kein Problem mehr
und blitzschnell. Mit der eingebauten Mini-Shell kann man das sehr
elegant selbst überprüfen, z.B. so:

Datei anlegen:
touch 1.txt

Datei auf 100MB erweitern und ein paar Zeichen reinschreiben:
write 1.txt 100000000
<abcd

Oder einfach mitten rein:
write 1.txt 50000000
<1234

Beim drücken von Enter spüre ich keine Verzögerung.
Das gilt für Schreiben, Lesen sollte schneller möglich sein. Mein
Test-Aufbau: Mega32 @ 14,7456MHz, NoName 1GB SD-Karte, 115kB am Uart.

OT:
MP3's mit 200MB, uff. Das sind keine Songs mehr, etwa Hörbücher o.ä.?

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

@ Malte
Zusätzlich zu den Antworten von Torsten noch drei Anmerkungen:
- Die Karte kann während der Programmierung im Slot steckenbleiben,
falls Du das /SS-Signal über den Mikroprozessor steuerst. Hast Du das
Signal jedoch fest auf Masse gelegt, wird während der Programmierung
gleichzeitig die SD-Karte angesprochen, die das wohl nicht mag. Zudem
dürfte sie durch vermeintliche Antworten auch aktiv den
Programmiervorgang stören.
- Da Du einen 3,3V-Regler verwendest, solltest Du drauf achten, dass
die Spannungsteiler bei logischem High-Pegel auf keinen Fall mehr,
besser etwas weniger als 3,3V an die Karte anlegen. Ich weiß nicht, wie
die Karte auf Spannungspegel reagiert, die höher als die
Betriebsspannung liegen.
- Achte darauf für die MISO-Leitung keinen Spannungsteiler zu
verwenden, da dies ein Eingang am Mikrocontroller ist. Die 3,3V der
Karte werden bei 5V Betriebsspannung des ATmega noch als High-Pegel
erkannt.

Gruß,
Roland

von Malte I. (maltomat)


Lesenswert?

@ Torsten, Roland
danke für die Tips. Ich bin gerade beim Debuggen. Dabei ist mir
aufgefallen, dass in sd_raw_config.h noch folgende Einträge stehen, die
nicht durch ein 'if defined' dem entsprechenden Controllertyp
angepasst werden:

#define select_card() PORTB &= ~(1 << PB2)
#define unselect_card() PORTB |= (1 << PB2)

Beim mega8 ist PB2=SS, beim mega32 ist SS an PB4. Eine entprechende
Änderung bringt aber auch nichts. Mache ich einen Denkfehler?

Die folgende Schleife in sd_raw_init bringt nur 0x00 Werte:
/* card needs 74 cycles minimum to start up */
    for(uint8_t i = 0; i < 10; ++i)
    {
        /* wait 8 clock cycles */
        uart_putc(sd_raw_rec_byte());
  //sd_raw_rec_byte();
    }

Die darauffolgende Schleife mit 'response' bringt 512 mal 0x00.

Kann man daraus schon schliessen, dass etwas grundsätzliches nicht
stimmt?

Gruß
Malte

von Malte I. (maltomat)


Lesenswert?

Ich habe gerade festgestellt, dass am CLK Eingang meiner Karte konstant
2.65V anliegen. Hinter dem 1.8k Widerstand, also am SCK Ausgang des
Controllers, kann ich dagegen während der Initialisierungsphase ein
Taktsignal messen. Die 2.65V sind offenbar so niederohmig, dass das
Taktsignal nicht "durchkommt". Wie kann das sein?

Gruß
Malte

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo Malte,

Bzgl. der beiden #defines hast Du Recht, die müssen jeweils an die MCU
angepasst werden. Eine aktualisierte Version habe ich angehängt.

Mit Deiner Schleifenausgabe stimmt tatsächlich etwas nicht. Könntest Du
mal ein Foto oder besser noch einen Schaltplan von Deinem Aufbau posten?
Sonst ist das alles ziemlich viel Raterei.

Wenn Du die Spannungsteiler so aufgebaut hast, wie in meiner Schaltung
bzw. der von Ulrich Radig, sollte das schon stimmen. Auf der
CLK-Leitung liegt nur ein Takt, während Daten in die ein oder andere
Richtung übertragen werden. Danach wird er wieder abgestellt. Der Takt
ist zudem so schnell, dass Du ihn nur mit einem Oszilloskop und nicht
mit einem gewöhnlichen Voltmeter messen kannst. Die Initialisierung
läuft für gewöhnlich innerhalb von wenigen Millisekunden ab, auf einem
Voltmeter erkennst Du da überhaupt nichts.

Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

ich hatte vergessen zu schreiben, dass ich das Taktsignal mit dem Oszi
gemessen habe. Und, wie gesagt, am SCK-Pin des Controllers liegt es
eine knappe Sekunde lang an (viel länger als wenige Millisekunden???).
Direkt an der Karte, hinter dem Widerstand ist aber nix mehr vom Takt
da, nur Gleichspannung. Die Spannungsteiler habe ich genau so wie du
und Ulrich aufgebaut, die Pegel stimmen sonst auch (etwas unter VCC).

Ich mache mal einen Schaltplan...

Danke und Gruß
Malte

von Malte I. (maltomat)


Angehängte Dateien:

Lesenswert?

...hier der Schaltplan. Ich habe keien Eagle-Vorlage für den Mega32, der
Mega163 hat aber die gleiche Belegung.

von Malte I. (maltomat)


Lesenswert?

Asche auf mein Haupt! Ich habe die Pin-Nummern der Karte verwechselt, da
der 9te Pin ausser der Reihe liegt. Ich Trott..
Immerhin musste ich mich so etwas intensiver mit der Materie
beschäftigen und habe dabei eine Menge gelernt.

Danke noch mal für die Hilfe

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte!

Heißt das, dass es jetzt bei Dir funktioniert?
Herzlichen Glückwunsch!

Naja, immerhin hast Du jetzt schon mal einen Schaltplan, auf dem Du
aufbauen kannst... ;-)

Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

ja, es funktionierte auf Anhieb. Klasse Software, dein reader!
Habe noch folgendes festgestellt: Wenn man eine Datei erstellt, etwas
reinschreibt, die Datei dann löscht und danach eine neue Datei mit
gleichem Namen erstellt, steht wieder der alte Inhalt drin. Richtig?

Gruß
Malte

von neuer (Gast)


Lesenswert?

kommt von dos.
wenn du eine datei löscht, wird nur der name herausgenommen, wenn dir
der gleiche name wieder einfällt und dort reinschreibst, kannste die
datei wieder herstellen.

von Avr N. (avrnix) Benutzerseite


Lesenswert?

abo

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Der alte Inhalt steht aber nur drin, wenn die Größe der neuen Datei > 0
ist, oder? Sonst würde da was nicht stimmen.

Das Verhalten ist ok. Hat aber nicht unbedingt etwas mit DOS zu tun,
sondern eher mit Geschwindigkeit. Da ich die FAT sequentiell nach
freien Clustern durchsuche, allokiere ich für die Datei denselben
Cluster, den die zuvor gelöschte Datei benutzt hat. Um die
Geschwindigkeit hoch zu halten, verzichte ich darauf, beim Vergrößern
der Datei die Cluster zu nullen. Bei Bedarf musst Du das Datenleck
selbst schließen und den Cluster leeren. In der Doku der Funktion
fat16_resize_file() steht das auch nochmal.

Gruß,
Roland

von Dirk Schlage (Gast)


Lesenswert?

Hallo Roland,
Ich habe gerade den Samstag damit verbracht ein kleines Board für den
Kartenslot und eine Testplatine für meinen Mega16 zu Bauen.
Ich kann jetzt von einer 128 MB SD-Karte eine Datei, dumpen.
Vielen Dank. Großartige Arbeit.
Auf meinen Mega88 hat das Image mit dem Test-Main leider nicht
raufgepasst, auch nicht nachdem ich ein bisschen was wegdefiniert
habe.
Und ich denke der Mega 16 hat jetzt auch nicht mehr viel Luft für neuen
Code, ich werde einen Mega32 Ordern.
Ich habe noch eine 16MB-Karte, die kann das Programm aber nicht lesen.
Ich würde mir noch ein paar Zeilen Doku zu dem Main wünschen, und ein
paar grundsätzliche Hinweise zur Inbetriebsetzung.
Aber nochmal danke und klasse Arbeit.

servus
    Dirk

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

noch ein paar Fragen zu deinen Schreibfunktionen:

Ich will den SD-Karte in einem Datenlogger einsetzen, der ständig
läuft. Es kommen pro Sekunde etwa 600 byte, die in Blöcken zu 512 byte
(oder mehr??) auf die Karte geschrieben werden sollen. Einmal pro Tag
wird eine neue Datei angelegt ("Tagesfiles"). Das ergibt eine Größe
von gut 5MB/Tag.

Muss man beim Schreiben ans Ende einer bestehenden Datei die Datei
vorher vergrößern (resize), oder wird die Größe beim Schreiben
automatisch angepasst?

Muss man für jeden Block die Datei öffnen und wieder schliessen, oder
kann man sie offen lassen? Oder nach jedem Schreiben ein sd_raw_sync
machen? Was bewirkt eigentlich das Schliessen der Datei, wird da noch
was in die FAT geschrieben?

Im Falle eines Stromausfalls wäre es nicht gut, wenn der gesamte
bisherige Tagesfile verloren wäre. Wie muss ich vorgehen, um dem
vorzubeugen / den Datenverlust zu minimieren? Bei DOS entsteht in
solchen Fällen bei noch geöffneten Dateien ja ziemlicher Murks.

Wie kann ich eine Funktion zur Ermittlung des verbleibenden
Speicherplatzes auf der Karte realisieren?

Beste Grüße
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

@Dirk

Schön, dass es funktioniert.
So wie das Programm im Download konfiguriert ist passt es tatsächlich
nicht mehr in 8kByte. Wenn man jedoch nur den Lese-Support benötigt und
sd_raw_config.h bzw. fat16.h dementsprechend abändert, sollte ein
einfaches Programm auf einem mega8 durchaus zu realisieren sein.
Und was den mega16 angeht solltest Du mal den recht umfangreichen Code
in main.c durch Deinen eigenen ersetzen. Ich weiß zwar nicht, was Du
mit der SD-Unterstützung vorhast, aber solang Du nicht wesentlich mehr
RAM brauchst, ist die Benutzung eines mega16 schon möglich.
Benutzt Du die Optimierungsmöglichkeiten Deines Compilers?

Könntest Du mir erläutern, welche zusätzliche Doku Du benötigst? Ich
dachte eigentlich, die main()-Funktion wäre als Beispielanwendung
weitgehend selbsterklärend. Die Dokumentation für die SD-, Partitions-
und FAT16-Funktionen hast Du ja sicherlich schon im doc-Verzeichnis
oder auf meiner Homepage entdeckt.

von Roland R. (roland) Benutzerseite


Lesenswert?

@Malte

Die von Dir zu schreibenden Daten werden vom sd_raw-Code automatisch in
512-Byte-Blöcke aufgeteilt. Du kannst Daten beliebiger Größe schreiben
oder lesen.
Wenn Du allerdings jede Sekunde schreiben willst, kann dies zu Lasten
der Lebensdauer der Karte führen. Du solltest daher eventuell in einem
eigenen Puffer die Log-Daten sammeln und in einem Rutsch auf die Karte
schreiben. Die von mir implementierte Schreibpufferung lindert dieses
Problem zwar, jedoch ist ein schreibender Dateizugriff relativ komplex,
sodass diese Pufferung nicht optimal greift.

Du kannst die Dateien zu beliebigem Zeitpunkt öffnen oder schließen. Es
sind beliebig viele Zugriffe in beliebig großen Zeitabständen möglich,
ohne die Datei zwischendurch zu schließen.

Wenn Du über das Ende einer Datei hinausschreibst, wird diese
automatisch vergrößert. Du kannst auch fat16_seek_file() benutzen, um
die Schreibposition innerhalb der Datei festzulegen. Auch diese
Funktion ruft bei Bedarf fat16_resize_file() implizit auf.

Wenn die Schreibpufferung aktiviert ist, sollte nach umfangreichen
Zugriffen oder auch in einem regelmäßigen Zeitintervall sd_raw_sync()
aufgerufen werden, um die Konsistenz der Daten und des Dateisystems zu
gewährleisten. Danach kann die Karte abgezogen werden. sd_raw_sync()
aufzurufen, während Dateien geöffnet sind, ist problemlos möglich.

Die Ermittlung des freien Speicherplatzes ist relativ einfach möglich,
man durchläuft dazu die FAT und zählt die freien Cluster. Bei
Gelegenheit werde ich das mal implementieren.

Gruß,
Roland

von Dirk Schlage (Gast)


Lesenswert?

@Roland:
Doku benötigen wäre sicher etwas zuviel gesagt.

Du hättest vieleicht noch erläutern können, welche PortPins du mit
welchen an der Karte verbunden hast, insbesondere SS. Ebenso könnte man
beschreiben, welche Einstellungen für das Terminalprogramm zu wählen
sind, für das Testmain. Aber das bleibt dir überlassen und steht
schliesslich alles im Code drin. Ein Chef von mir hat mal früher
gesagt: Der Code ist die Doku.

Ebenso ein Vorschlag, was man mit der Shell anstellen kann, wie oben in
einem Beitrag:
touch 1.txt
write 1.txt 1000
ls
...

Vieleicht noch ein Warnhinweis, daß Backspace im Terminalprogramm evtl.
nicht so gut Tippfehler korrigiert, wie man denkt. Space am Ende von
Dateinamen,...

Aber das ist vieleicht mein persönliches Trauma. Konzentrier' dich,
auf was dir wichtig erscheint und lass dich nicht von mir davon
abhalten tolle Sachen zu machen.

Wirst du den Code noch weiterpflegen?

Gibt es noch known-bugs, mit Dateien, die sich überschreiben, oder
Karten, die Probleme bereiten?

Gruß
    Dirk

von Malte I. (maltomat)


Lesenswert?

@Roland:
Ich schliesse aus deinen Aussagen, dass ich noch einen externen RAM
verwenden sollte. Ich werde mir mal das Projekt von Benedikt
http://www.mikrocontroller.net/forum/read-4-121457.html
ansehen.

Du schreibst, dass man sd_raw_sync() auch bei geöffneter Datei aufrufen
kann. Bedeutet dies, dass bei einem Stromausfall alles, was vor dem
letzten Aufruf von sd_raw_sync() geschrieben wurde, erhalten bleibt,
auch wenn die Datei beim Ausfall geöffnet war? Das wäre natürlich sehr
komfortabel.


@Dirk:
auf Rolands Homepage ist ein Eagle Schaltplan.
Als Terminal Programm (für Windows) habe ich sehr gute Erfahrungen mit
Hterm (http://www.der-hammer.info/terminal/) gemacht.

Gruß
Malte

von Der T. (Gast)


Lesenswert?

Einfach Geil! :-D

abo

von Roland R. (roland) Benutzerseite


Lesenswert?

@Dirk

Ich werde mal schauen, was von den genannten Sachen noch sinnvoll wäre
aufzunehmen. Danke für die Anregungen.

@Malte

Viel RAM ist immer gut, zumindest bei Sachen wie Dateisystemen. Da
könnte man dann die ganze FAT, das Root Directory und vieles mehr
zwischenpuffern. Leider ist es aber mit den von Benedikt verwendeten
Speichergrößen nicht mehr möglich, den Speicher direkt zu adressieren.
Das verkompliziert den Speicherzugriff schon erheblich.

Bzgl. sd_raw_sync() hast Du Recht. Schließlich heißt die Funktion ja
auch so...

Als Terminalprogramm verwende ich unter Debian cu. Das hat wenigstens
kein nerviges Fenster sondern läuft in der Konsole :-)

Grüße,
Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

sorry wegen der vielen Fragen. Ich bin, was Controller angeht, noch ein
totaler Anfänger. Die Kiste läuft aber trotzdem schon ziemlich gut, dank
der vielen Hilfen aus diesem Forum.

Ich wollte mit dem RAM gar nicht in die Dateiverwaltung eingreifen,
sondern einfach nur zB. 64kB Meßdaten zwischenspeichern und dann in
einem Rutsch auf die Karte schreiben. Wäre das bei Verwendung deiner
jetzigen Software sinnvoll?

Falls ja, wie kann man das möglichst einfach realisieren? Kennst du
vielleicht eine gute Quelle für so ein (wahrscheinlich relativ
alltägliches) Projekt mit dem Mega32? Ich recherchiere schon seit
einiger Zeit, habe aber noch nichts passendes gefunden.

Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hi Malte,

Die 64k würden schon helfen, aber die Lösung ist das wohl nicht. Bei
600B/s wäre das ein Schreibzugriff alle 100s. Nach 12 Tagen sind 10000
Schreibzyklen in dem Verzeichniseintrag erreicht. Und das dürfte auch
das Ende der SD-Karte sein.

Hmm, Moment mal. Wenn Du zu Beginn die Datei direkt auf 5MB aufbläst
(mit fat16_resize_file()) und dann vom Dateianfang aus reinschreibst,
muss der Verzeichniseintrag nicht aktualisiert werden. Dann sollte die
Karte wesentlich länger durchhalten.

Bis demnächst,
Roland

von Wolfram (Gast)


Lesenswert?

Was ihr nur alle mit den 10000 Schreibzyklen habt. Ein SD-Card hat einen
internen Controller wenn ein Sektor nicht mehr schreibbar ist wird der
durch einen Ersatzsektor ausgetauscht. Wieviele solche Ersatzsektoren
vorhanden sind ist Sache der Hersteller und dürfte sich auch im Preis
wiederspiegeln. Eine SD-Karte hat auch einen internen RAM ,das merkt
man am schnelleren Multisektorzugriff. Da werden die Daten auch erstmal
gesammelt. Ausserdem schafft flash heutzutage 100.000 Zyklen. Wenn es
unbedingt Langzeit sein muss, nimmt man ein FRAM sammelt da die Daten
und schreibt am Block.

von Roland R. (roland) Benutzerseite


Lesenswert?

Eben, die Anzahl der Ersatzsektoren kommt auf den Hersteller an. Bei den
zur Zeit zu Schleuderpreisen angebotenen Karten handelt es sich ja oft
um Billig-Hersteller. Die werden an der Stelle bestimmt sparen. Ich
habe mir bereits eine Karte abgeschossen, sie ist jetzt dauerhaft
schreibgeschützt. Ob das durch zu viele Schreibvorgänge während der
Entwicklung des sd-reader geschehen ist kann ich nicht mit Bestimmtheit
sagen, aber es ist meine Vermutung.

Ich denke, wenn es mit wenig Aufwand möglich ist, den Flash zu schonen,
dann sollte man das auch tun. Zumindest beim in meinem Code verwendeten
Einzel-Blockzugriff wird durch die Karte nicht gepuffert, da man dann
ja Datenverlust beim Abziehen der Karte zu befürchten hätte.

Roland

von Ssss S. (sssssss)


Lesenswert?

>Die werden an der Stelle bestimmt sparen. Ich
>habe mir bereits eine Karte abgeschossen, sie ist jetzt dauerhaft
>schreibgeschützt. Ob das durch zu viele Schreibvorgänge während der
>Entwicklung des sd-reader geschehen ist kann ich nicht mit
Bestimmtheit
>sagen, aber es ist meine Vermutung.
Ich denke eher du hast irgendein (nicht dokumentiertes?) Register
beschrieben
beim testen...
Ich hab beim testen mit meinem Code extreMEmory Karten zerschossen
(reproduzierbar :-X).
Hab jetzt zwei Karten wo nur noch der SPI Modus geht, MMC modus = keine
Reaktion.
Und das obwohl die Karten im Betrieb deselektiert waren (CS=high und
dann ein §65 Display per SPI mit vielen Daten beschrieben -> mmc karte
tot).
Da vermute ich irgendeinen Bug in der mc karten statemachine oder so...
Kanns mir sonst nicht erklären. Bei uralten 32MB mmc karten passiert das
nicht :)

Bye, Simon

von Wolfram (Gast)


Lesenswert?

@Roland:
wie ich sehe versuchst du das FAT16 Dateisystem an dem String FAT16 zu
erkennen, dies ist ein Eintrag in dem auch andere Sachen stehen können
und er ist nicht obligatorisch für FAT16. Das Windowsformatprogramm
macht dies allerdings seit Jahren so.

von Roland R. (roland) Benutzerseite


Lesenswert?

Ja stimmt, das ist nicht eindeutig. Aber es ist üblich, und eine einfach
zu implementierende Möglichkeit. Es gibt mehrere Stellen, an denen diese
Zeichenkette stehen kann. Ich will damit eigentlich nur Datenverlust
vermeiden in dem Fall, dass ein Sektor fälschlicherweise als
FAT16-Header interpretiert wird. Den Zweck erfüllt es auch, denke ich.

Hast Du eine bessere Idee?

Roland

von Wolfram (Gast)


Lesenswert?

55AA prüfen, auf Partitionssektor prüfen
Bootsektor
55AA prüfen
Clusteranzahl<4085 ||Clusteranzahl>65524
Sektoren pro Cluster 2^n ?
evt. anfang der FAT cluster 0 und 1 Wert prüfen
Bevor Microsoft die FAT Patente bekam gab es von Microsoft ein
Dokument
das aus der Einführungszeit von VFAT stammt und unterschiedliche
FATimplementierungen und testroutinen (unter anderen Norton und
PCTools)
und mögliche Auswirkungen durch VFAT diskutiert. Ausserdem wird auf
typische Fehler in anderen FATimplementierungen eingegegangen.
Hier wird nochmals ausdrücklich darauf hingewiesen das FAT12 und FAT16
nicht durch den String sondern allein durch die Clusteranzahl
auseinandergehalten
werden. Auch PCIntern hat in der Bootsektorbeschreibung diesen String
nicht als obligatorisch.
Bezüglich Datenverlust: schon beim Einlesen des Hauptverzeichnisses
dürfte es probleme geben.

von Roland R. (roland) Benutzerseite


Lesenswert?

Danke für die Anregungen. Ich halte Deine Ansätze aber für ziemlich
Code-intensiv. Denn es sind mehrere Lesevorgänge erforderlich,
Zusammenbauen der 16-Bit-Werte, das Prüfen der Werte, usw.

Trotzdem, hast Du vielleicht noch einen Link zu dem von Dir erwähnten
Microsoft-Dokument? Ich habe das mit kurzer Suche nicht mehr finden
können.

Danke und Gruß,
Roland

von Wolfram (Gast)


Lesenswert?

>Denn es sind mehrere Lesevorgänge erforderlich,
1. Sektor laden
Partitionssektor?
wenn ja Bootsektor laden
>Zusammenbauen der 16-Bit-Werte, das Prüfen der Werte, usw.
Diese Werte musst du sowieso auslesen
und das Zusammenbauen aus 8Bitwerten solltest du sowieso machen wenn
du
Interesse daran hast das dein FAT-Code auch auf anderen CPU läuft.

>Trotzdem, hast Du vielleicht noch einen Link...
Dieses Dokument ist aus dem Netz verschwunden als Microsoft die
FAT-Patente erhalten hat. Ich muss mal suchen ob ich es noch finde.
BTW: Hast du dir schonmal Gedanken gemacht was passiert wenn Microsoft
an dich herantritt wegen der FAT-Implementierung?

von Roland R. (roland) Benutzerseite


Lesenswert?

Im Prinzip hast Du Recht. Wenn Du Dir meinen Code anschaust, siehst Du,
dass ich nur die Bereiche aus dem MBR bzw. dem Partitionssektor lade,
die mich für die Anwendung wirklich interessieren. Auf meinem mega168
ist RAM sehr knapp (und Flash bald auch), ich hatte mehrfach Probleme
mit Kollisionen zwischen Heap und Stack. Deswegen will ich mir keine
teuren Überprüfungen leisten. Ganz zu schweigen von Sektoren, die ich
der Einfachkeit wegen komplett auf einen Schlag ins RAM lade.

Im Übrigen sollte der Code schon plattformunabhängig sein. Alle
multi-Byte-Werte baue ich einzeln zusammen, um nicht auf die Endianess
der MCU angewiesen zu sein.

Was Microsoft angeht denke ich, dass ich nicht der erste bin, der
FAT16-Unterstützung implementiert. Mein Code basiert komplett auf
Informationen, die bereits öffentlich im Internet zu finden sind. Wenn
mich Microsoft ansprechen sollte, werde ich das Projekt natürlich
sofort von meiner Seite entfernen.

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

@alle

Ich habe nochmal eine neue Version auf
  http://www.roland-riegel.de/sd-reader/
bereitgestellt und auch an dieses Posting gehängt.

Die Neuerungen sind:
- Zwei Funktionen, die die Größe des gesamten und des
  freien Speicherplatzes berechnen.
- Unterstützung der Backspace-Taste in der Mini-Shell.
- Aktivierung des Idle-Mode beim Warten auf die UART.
- Kurz-Dokumentation der Mini-Shell-Befehle.
- (un)select_card() ist nun auch MCU-abhängig.

Gruß,
Roland

von Wolfram (Gast)


Lesenswert?

>Im Übrigen sollte der Code schon plattformunabhängig sein.
Ein Tip aus eigener Erfahrung, du hast sowieso nur eine Lese-/Schreib
und Kartendetektionsroutine. Der Rest sollte Hardwareunabhängig sein.
Wenn du die genannten Routine auf dem PC in eine Datei/Device umlenkst
kannst du alles auf dem PC entwickeln, aufgrund der erweiterten
Debuggingmöglichkeiten auf dem PC geht es wesentlich schneller voran
und es wird mit Sicherheit plattformunabhängig. Ganz nebenbei schont es
den flash der MCU und der SDCard.

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Wolfram,

Ganz zu Beginn hatte ich das schon so gemacht. Ich habe mir ein Image
der SD-Karte gezogen und auf dem PC mittels fopen(), fread() und
fclose() darauf zugegriffen. Als ich dann Dateien in dem Image
auflisten und dumpen konnte sowie in Verzeichnisse wechseln konnte, bin
ich dann auf den AVR umgestiegen.

Gruß,
Roland

von Wolfram (Gast)


Lesenswert?


von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Wolfram,

Danke, dass Du das noch auftreiben konntest. Werde ich mir bei
Gelegenheit mal durchschauen. Vielleicht findet sich ja noch das ein
oder andere Detail, dass ich anders oder sogar falsch implementiert
habe.

Gruß,
Roland

von Uwe (Gast)


Lesenswert?

Hi!
Wenn ich mich nicht verlesen habe so erkennt man die Fatart auch an den
1ten Byte jeder Fat.
$0FF8 = Fat 12
$FFF8 = Fat 16
$0FFFFFF8 = Fat 32
oder
Offset  Description  Size
000h  Executable Code (Boots Computer)  446 Bytes
1BEh  1st Partition Entry (See Next Table)  16 Bytes
1CEh  2nd Partition Entry  16 Bytes
1DEh  3rd Partition Entry  16 Bytes
1EEh  4th Partition Entry  16 Bytes
1FEh  Boot Record Signature (55h AAh)  2 Bytes

Partition Entry (Part of MBR)
Offset  Description  Size
00h  Current State of Partition (00h=Inactive, 80h=Active)  1 Byte
01h  Beginning of Partition - Head  1 Byte
02h   Beginning of Partition - Cylinder/Sector (See Below)  1 Word
04h  Type of Partition (See List Below)  1 Byte
05h  End of Partition - Head  1 Byte
06h  End of Partition - Cylinder/Sector  1 Word
08h  Number of Sectors Between the MBR and the First Sector in the
Partition  1 Double Word
0Ch  Number of Sectors in the Partition  1 Double Word

Partition Type Listing
There are more than just these shown, but I've only included that ones
relevant to MS Operating Systems.
Value  Description
00h  Unknown or Nothing
01h  12-bit FAT
04h  16-bit FAT (Partition Smaller than 32MB)
05h  Extended MS-DOS Partition
06h  16-bit FAT (Partition Larger than 32MB)
0Bh  32-bit FAT (Partition Up to 2048GB)
0Ch  Same as 0BH, but uses LBA1 13h Extensions
0Eh  Same as 06H, but uses LBA1 13h Extensions
0Fh  Same as 05H, but uses LBA1 13h Extensions

Die Fatstartadresse musst du sowiso berechnen, da kannste den Sector
auch mal lesen. Wenn du es dann noch mit dem MBReintrag vergleichst
sollte das eigentlich recht sicher sein. Du kannst natürlich auch die
VBReinträge prüfen und aus der Clusterzahl auf die Fat schließen.

schönen Tag noch, Uwe

von Roland R. (roland) Benutzerseite


Lesenswert?

@Uwe

Die ersten zwei Bytes der FAT auszuwerten ist aber wohl auch bloß ein
Notbehelf. Zudem wäre es noch durchaus denkbar, dass diese zwei Bytes
zufällig korrekte Werte haben, der Datenträger in Wirklichkeit aber
ganz was anderes als FAT16 enthält.

Inzwischen habe ich die von Wolfram vorgeschlagene Unterscheidung
anhand der Datenclusteranzahl implementiert. Dies wird im
Microsoft-Paper sogar als einzig richtige Methode dargestellt.

@alle

Dadurch konnte ich auch gleich noch einen anderen Fehler beheben. Mein
Code ging bisher davon aus, dass die FAT immer an einer Sektorgrenze
endet. Daher konnte es vorkommen, dass bei nahezu voller Karte Cluster
über die Kartengröße hinaus allokiert wurden.

Den korrigierten Code werde ich wohl noch diese Woche hier posten.

Gruß,
Roland

von Wirus! (Gast)


Lesenswert?

Moin,

erstmal Glückwunsch zu dem Projekt und Danke an alle, die sich hier
richtig reinhängen, speziell an Roland.

Ich möchte habe auch ein Projekt, bei dem ich eine SD/MMC als
Datenlogger mit einbinden möchte und erstelle gerade das Konzept.

Nun meine Frage:

Um die Anzahl der Bauelemente und den benötigten Platz klein zu halten,
wollte ich den Atmega168 direkt bei 3,3V betreiben und mir den
Levelshifter sparen.

Bis 10Mhz ist das ja laut Datenblatt zulässig oder habe ich noch was
übersehen?

Noch eine Bitte: Könnte jemand den Schaltplan mal als PDF, JPG oder PNG
posten? Ich habe hier auf Arbeit kein Eagle ....

Danke!

abo

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

@Wirus

Laut Datenplatt sind 10MHz@3,3V möglich. Achte aber darauf, dass je
nach Art auch Dein Programmieradapter die Spannung unterstützen muss.

Schaltplan ist angehängt.

Gruß,
Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, wie angekündigt gibts nochmal eine neue Version auf
  http://www.roland-riegel.de/sd-reader/

Die wichtigsten Veränderungen sind:
- Verbessertes Handling des Idle-Mode.
- Anzeige weiterer Kartenparameter beim "disk"-Befehl.
  Dieser wird jetzt auch beim Start automatisch ausgeführt.
- Identifikation von FAT16 anhand der Clusteranzahl.
- Mögliche Clusterreservierung über die Kartenkapazität
  hinaus korrigiert.

Quelltext wie immer auch angehängt.

Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

schönen Dank für die neue Version. Mir ist aufgefallen, dass die
disk-funktion nur etwa die Hälfte des tatsächlich freien
Speicherplatzes anzeigt. Eine leere 256MB disk zeigt folgendes:
manuf:  0x02
oem:    TM
prod:   SD256
rev:    68
serial: 0x707dd547
date:   03/05
size:   255066112
copy:   0
wr.pr.: 0/0
format: 0
free:   120578048/254795776

Unter Windows wird die korrekte Größe angezeigt. Filesystem anlegen und
formatieren habe ich unter Linux gemacht (eine unter Windows formatierte
disk wurde nicht erkannt). Habe ich beim formatieren vielleicht etwas
falsch gemacht? Jedenfalls habe ich bei mkdosfs  ausser dem device
nichts weiter angegeben. fdisk zeigt 8 Köpfe, 61 Sektoren, 1020
Zylinder.

Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte!

Zwei mögliche Ursachen fallen mir ein:
- Vor dem Auswerfen der Karte wurde nicht richtig synchronisiert.
  (unter Linux mit "eject /dev/sda", i.d.R. aber nicht nötig)
- Windows verwendet die zweite FAT.

Vernünftig erklären kann ich es mir aber eigentlich nicht. Könntest Du
bitte mal unter Linux die ersten 256kByte auf der Karte dumpen und mir
per Mail (feedback@roland-riegel.de) schicken?

Zur Info (Annahme: SD-Karte als /dev/sda):
    dd if=/dev/sda1 of=fat.dump bs=16k count=16
Die Datei fat.dump schickst Du mir dann bitte zu. Mal sehen ob uns das
irgendwie weiterhilft.

Gruß,
Roland

von Simon K. (simon) Benutzerseite


Lesenswert?

die kann man auch hier hochladen. Ihr immer mit eurem Email
hinundhergeschickte. Dafür ist das Forum nicht da!

von Roland R. (roland) Benutzerseite


Lesenswert?

@Simon

Die anderen Teilnehmer wird die FAT von Malte aber kaum interessieren,
für sie ist es ja bloß Datenmüll. Oder was sollen Sie Deiner Meinung
nach damit anfangen?

Roland

von Malte I. (maltomat)


Lesenswert?

Ok.
Noch eine Sache: die neue Version (0824) funktioniert bei mir leider
nicht wenn externe Interrupts benutzt werden. Bei den älteren Versionen
hatte ich gar keine Probleme damit. Daher muss ich jetzt erstmal mit der
älteren Version (0816) weiterarbeiten. Any idea? Vielleicht irgendwas
mit dem Idle-Mode?

Gruß
Malte

von T.S. (Gast)


Lesenswert?

Malte

Ersetze einfach in "uart.c"

#define USE_SLEEP 1
durch
#define USE_SLEEP 0

und kommmentiere in der main() in "main.c" folgende Zeile

set_sleep_mode(SLEEP_MODE_IDLE);

einfach aus. Dann sollte es eigentlich sein wie vorher.


Roland hat den Idle-Mode auf meinen ausdrücklichen Wunsch hin
eingebaut. Wir haben lange diskutiert wie es am sinnvollsten ist. Nur
an einen ext.Interrupt hat keiner gedacht..

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Wie Torsten schon sagt, ist das mit dem Sleep-Mode etwas heikel, und
sollte eventuell für ein richtiges Projekt deaktiviert werden.

Die ISR für den externen Interrupt sollte zwar schon ausgeführt werden.
Wenn Du dort jedoch wie üblich nur ein Flag setzt, welches dann in der
main() abgefragt und abgearbeitet wird, gibt es Probleme. Denn
uart_getc() wartet immer noch auf das nächste Uart-Zeichen, und die
main() kommt nicht zum Zug.

Für das Beispiel-Programm auf meiner Homepage mag das Verhalten
sinnvoll sein. Für ein anderes Projekt jedoch, wo die MCU noch andere
Dinge zu erledigen hat, wohl eher nicht.

von Peter bb (Gast)


Lesenswert?

Welche aufgabe übernimmt eigentlich am avr immer der port ss an der
mmc-karte? kann man auch eien anderen port nehmen?

von Roland R. (roland) Benutzerseite


Lesenswert?

Du kannst jeden beliebigen Port-Pin wählen. Die SS- oder auch CS-Leitung
dient zur Adressierung der Karte. Wenn diese Leitung auf Low liegt,
fühlt sich die Karte angesprochen und reagiert auf Befehle. Ist sie
jedoch High, verhält sie sich passiv.

Wenn Du am SPI-Bus nur die Karte angeschlossen hast, kannst Du Dir den
Pin sparen und den entsprechenden Anschluss der Karte auf Masse legen.
Ansonsten jedoch ist er nötig, um die Karte nicht durch den SPI-Verkehr
mit anderen Geräten zu stören, und umgekehrt.

Einige Chips, wie der ENC28J60, benötigen diese Leitung auch als eine
Art "Befehlstakt". In diesem Fall kann die Leitung natürlich nicht
eingespart werden.

von Peter bb (Gast)


Lesenswert?

da ich nur die mmc-karte anschliessen möchte und diese auch nur
betreibe, kann man den anschluss an der mmc cs sofort auf masse legen?

von Peter bb (Gast)


Lesenswert?

hier sind ja alles fachleute.

ich möchte die mmc-karte nicht mit dos und fat betreiben.
ich möchte einfach die mmc-karte initialieren und dann 512bytes lesen,
schreiben und evtl löschen.

wo kann man in winavr-c einfache beispiele ausmachen.
ich steige durch den oberen code für die mmc-karte nicht durch, finde
als laie keine timing, adressen usw.

danke.

mfg

von Roland R. (roland) Benutzerseite


Lesenswert?

@Peter

Lese Dir doch bitte meine obige Antwort sorgfältig durch, dass sollte
Deine erneute Frage bzgl. des CS-Anschlusses der Karte beantworten.

Was willst Du denn für die MMC-Ansteuerung über den SPI-Bus für
Timing-Parameter oder Adressen wissen? Alles was Du für Deinen
Anwendungszweck von meinem Code brauchst, steht in den Dateien
sd_raw.c, sd_raw.h und sd_raw_config.h. Den Rest kannst Du weglassen.
Mach Dir bitte die Mühe und beschäftige Dich mit dem Code. Im
Unterverzeichnis doc/html findest Du nicht umsonst eine ausführliche
Dokumentation der erforderlichen Funktionen.

Roland

von Thorsten (Gast)


Lesenswert?

Hallo Roland,
bin gerade dabei, einen Datenlogger mit einem Mega32 zu bauen und nutze
dabei Deinen Code zur Ansteuerung der SD-Karte. Hatte auch null
Probleme, den Code einzubinden, ist schön übersichtlich und gut
kommentiert (besser als meiner...;-)), echt klasse.
Leider sind die Ausführungszeiten mancher Funktionen zu lang, so dass
mir (bei höheren Sampleraten) jedes Mal wenn ein Block auf die Karte
geschrieben wird, samples verloren gehen, weil zum Beispiel die CPU auf
die SD-Karte wartet:

while(sd_raw_rec_byte() != 0xff);

Ich suche nun nach einer Möglichkeit, diese busy waits zu vermeiden und
statt dessen ins Hauptprogramm zurückzukehren, um bei Bedarf weitere
Messungen anzutriggern (gemessen wird mit einem MAX127 über TWI). Ich
habe schon versucht, statt der Warteschleife ein flag zu setzen und die
Warteschleife dann am Anfang des nächsten Aufrufs auszuführen, hat aber
nicht geklappt, wahrscheinlich weil nach dem write ein read
durchgeführt werden muss, um den nächsten Block zu finden, und die
Karte dann noch nicht bereit ist.
Ich fürchte, der Code müsste massiv umgeschrieben werden, um hier
deutliche Verbesserungen zu erzielen. Wahrscheinlich müsste dann auch
Deine elegante Aufteilung in Schichten dran glauben...
Irgendwelche Ideen, in welcher Richtung ich hier am schlauesten
vorgehen könnte?

Gruss,
Thorsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Thorsten!

Wie groß ist denn Deine zu erwartende Datenrate, mit der Du auf die
Karte schreiben willst? Nutzt Du den FAT16-Treiber, oder schreibst Du
im Raw-Format? Die FAT-Schicht verursacht natürlich einiges an
Overhead, um das Dateisystem zu verwalten.

Bevor Du versuchst, den Code im großen Stil umzuschreiben, solltest Du
die maximal mögliche Schreibdatenrate ermitteln. Wenn die Datenrate
unter Deinen Anforderungen liegt, müsste man etwas Grundlegendes ändern
(MCU-/SPI-Takt, Multi-Block-Writes, usw.).

Ich habe noch nicht genau getestet, ob die SD-Karten während des
eigentlichen Schreibvorgangs einen SPI-Takt benötigen. Wenn ja, muss
die MCU ständig die Karte pollen, um überhaupt den Schreibvorgang
abzuschließen. D.h. dann wäre das Busy-Waiting notwendig.

Ansonsten könntest Du das Problem mit irgendwelchen Callback-Techniken
(wie z.B. in sd_raw_read_interval()), Interrupts oder einem einfachen
Multi-Threading lösen. Als alles erschlagende Methode könntest Du auch
einen zweiten Controller einsetzen, der ausschließlich die Karte
ansteuert und vom ersten Controller die Daten bekommt. Falls Du die
Daten bisher in einem menschenlesbaren Format abspeicherst, bringt ein
binäres Format auch wesentliche Einsparungen. Je nach
Schreibgeschwindigkeit wirst Du wohl auch um eine großzügige Pufferung
der Daten nicht herumkommen.

Gruß,
Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland und Thorsten,

ich habe gerade exakt das gleiche Problem wie Thorsten und probiere
schon eine ganze Weile rum.

Bei meinem Datenlogger wird alle 2.5ms ein Interrupt ausgelöst, 2 bytes
eingelesen und in ein Array geschrieben. Das macht 800B/s. Wenn das
Array mit 512 bytes voll ist, wird es auf die Karte geschrieben (mit
FAT16). Dieser Schreibvorgang dauert unterschiedlich lang.
Normalerweise irgendwas zwischen 2.5 und 5ms, bei jedem achten
Schreibvorgang (4096 bytes) aber etwa 5 mal so lange. Bei
Puffergröße=256 bytes kommt der langsame Schreibvorgang auch immer nach
4096 bytes (16 x schreiben). Während des Schreibens gehen unregelmäßsig
manchmal ein paar Samples verloren.

Ich habe auch versucht, immer die jeweils 2 gelesenen bytes direkt
innerhalb der ISR auf die Karte zu schreiben. Ohne Erfolg, auch beim
schreiben von nur 2 bytes dauert irgendwas zu lange.

Übrigens habe ich die zu schreibende Datei vorher mit resize genügend
groß gemacht, daher sollte auf der FAT nicht mehr "rumgeorgelt"
(O-Ton letzte c't) werden müssen. Dies war ja auch ein Tip von Roland,
weiter oben in diesem Thread.

Wenn ich den Buffer per UART rausschicke, gibt es keine Probleme. Der
Sendevorgang wird zwar dauernd durch Interrupts unterbrochen, es kommt
aber alles heil und vollständig an.

Einzige Lösung die mir (wie Roland) eingefallen ist, wäre ein zweiter
Controller. Bin natürlich interessiert daran, ob ihr den Code noch
irgenwie schneller oder anders getimed hinkriegt.

Gruß
Malte

von Thorsten (Gast)


Lesenswert?

Hallo Roland,

Meine erwartete Datenrate sind ca. 20kbytes/s, zur Verwendung kommt ein
Binärformat. In reinen Schreibtests mit Deinem FAT16-Treiber konnte ich
ca. 60kbytes/s erzielen, sollte also drin sein (mein Mega32 läuft mit
14.7456MHz). Mein Problem ist nicht der absolute Overhead, sondern die
Latenzzeit, die auftritt wenn ein Block geschrieben wird. Ich verwende
den FAT16-Treiber, da die Karte nach der Messung im PC ausgelesen
werden soll. Da meine Datenrate recht konstant ist, bringt ein
grösserer Datenpuffer nicht so richtig was (wenn die Daten schneller
kommen, als der Prozessor sie wegschreiben kann, geht es halt einfach
nicht, egal wie gross der Puffer ist). Ausserdem löst eine geringere
Datenrate das Problem nicht, denn die Latenzzeit tritt zwar weniger oft
auf, ist jedoch immer noch genauso gross (grösser als mein
Samplingintervall). Eventuell könnte ein Puffer für die FAT16-Metadaten
etwas bringen?
Interrupts könnten auch was bringen, allerdings müssten dann auch
FAT16-Routinen in die ISR gepackt werden, sonst wartet dann halt die
FAT-Routine statt der sd_raw routine, und ich bin immernoch da, wo ich
am Anfang war (daher meine Befürchtung, dass grössere Änderungen am
Code nötig werden). Bei f/2 SPI Takt habe ich pro zu übertragendem Byte
16 Prozessortakte zur Verfügung, von den allerdings die meisten als
Overhead (springen in und aus der ISR) wieder wegfallen.
Das mit dem zweiten Controller habe ich mir auch schon überlegt,
versuche ich aber zu vermeiden, weil dadurch eine Menge zusätzlicher
Komplexität entsteht.
Werde mir mal sd_raw_read_interval() genauer angucken.

Danke für die Tips,

Thorsten

von T.S. (Gast)


Lesenswert?

Thorsten

Die FAT-Routinen kannst Du nicht in eine ISR packen weil die einfach zu
lange dauern. Nach kurzer Zeit gibt es einen Stack-Überlauf.

Die einzige Lösung wäre ein FIFO-Buffer der in einer ISR gefüllt wird.
Wenn Du Daten vom TWI lesen willst dann hast Du doch schon fast
gewonnen. Dafür gibt es doch extra eine ISR.

In der Hauptschleife schaust Du einfach ständig nach ob der FIFO neue
Daten enthält und schreibst diese weg.

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo,

> Da meine Datenrate recht konstant ist, bringt ein
> grösserer Datenpuffer nicht so richtig was (wenn die
> Daten schneller kommen, als der Prozessor sie
> wegschreiben kann, geht es halt einfach nicht,
> egal wie gross der Puffer ist).

Wenn die Daten mit 20kB/s kommen und Du 60kB/s wegschreiben kannst,
kommen sie doch nicht schneller als Du sie schreiben kannst?!?

Ich denke, hier kommt es entscheidend darauf an, wie die Sample-Daten
zustande kommen. Vorausgesetzt, die Daten werden durch den AVR parallel
ohne Zutun des Programms erzeugt (z.B. im ADC), kann man es wie folgt
machen:
1. Man reserviert sich zwei oder mehr Puffer, von denen immer genau
einer "aktiv" ist.
2. Sind neue Daten verfügbar, wird ein Interrupt ausgelöst, in dessen
ISR man die neuen Daten in den aktiven Puffer schreibt. Ist der Puffer
voll, wird der andere Puffer aktiv und empfängt ab dann neue Daten.
3. In der Hauptschleife wird überprüft, ob es einen vollen Puffer gibt.
Wenn ja wird dieser auf die Karte geschrieben und anschließend geleert.

Statt mehreren Puffern könnte man je nach Datenrate auch einen
einzelnen als Ringpuffer nehmen und zu schreiben beginnen, wenn mehr
als 512 Byte enthalten sind.

Natürlich muss das Timing bzw. die Datenrate so passen, dass in der
Zeit, in der der eine Puffer auf die Karte geschrieben wird, der andere
nicht überläuft.

Werden die Daten nicht über einen Interrupt angekündigt, kann man die
Warteschleife in sd_raw_write() vielleicht dennoch durch einen
Timer-Interrupt unterbrechen, der dann weitere Datensamples
zwischenspeichert.

Gruß,
Roland

von Thorsten (Gast)


Lesenswert?

Torsten,

Ich dachte auch nicht dran, die FAT16-Routinen samt ihren Wartezyklen
in eine ISR zu packen, sondern die SPI-ISR so zu schreiben, dass sie
bei jedem Aufruf entscheidet, was als nächstes zu tun ist (Byte zum SPI
schreiben/lesen, wenn der Block fertig ist, gucken was als nächstes zu
tun ist, z.B. die FAT Einträge draus lesen usw.). Würde aber trotzdem
eine ziemlich grosse ISR geben, auch wenn bei jedem Aufruf nur ein
kleiner Teil davon zur Ausführung kommt. Das ist auch meiner Meinung
nach nicht der richtige Weg.
Das Problem ist halt, dass viele der Routinen einfach "busy" warten,
bis der Kartenzugriff abgeschlossen ist. Dadurch kriege ich immer die
Latenzen, egal ob die Karte nun durch eine ISR oder eine andere Routine
angesteuert wird.
Was möglicherweise ginge, wäre aber der umgekehrte Weg:
- Es gibt nicht einen Buffer, sondern zwei. Ein Pointer zeigt auf den
gerade aktiven.
- Wenn ein Block geschrieben werden soll, wird der SPI Interrupt
aktiviert und das erste Byte geschrieben. Die ISR sorgt dann dafür,
dass der Buffer asynchron auf die Karte geschrieben wird (Globale
Statusvariablen kontrollieren das, wenn der Block fertig ist,
deaktiviert die ISR den SPI Interrupt). Gleichzeitig wird der Zeiger
auf den zweiten Buffer gestellt, so dass weitere Schreibzugriffe
abgebuffert werden können. Die sd_raw Funktion kann sofort
zurückkehren.
Wo ich noch nicht so genau weiss, wie man es lösen könnte, ist das
lesen: Was mache ich mit einer Routine, die einen Block einliest und
dann bearbeitet? Die blockiert dann wieder... (zwangsläufig).
Was hältst Du davon?
Die andere Möglichkeit wäre, wie Du schreibst, die TWI ISR zu benutzen.
Ich muss mir nur noch überlegen, wie ich die Messung antriggere, könnte
ich in meiner RTC ISR am INT0 machen (die kriegt 32768Hz von der RTC).
Ansonsten wäre das evtl. noch besser, denn die TWI ISR feuert nicht so
schnell wie die SPI ISR (400kHz vs. 7MHz), d.h. mir bleiben mehr Takte
dazwischen übrig. Mal gucken...

Gruss,
Thorsten

von Thorsten (Gast)


Lesenswert?

Roland,

> Wenn die Daten mit 20kB/s kommen und Du 60kB/s wegschreiben kannst,
> kommen sie doch nicht schneller als Du sie schreiben kannst?!?

Sorry, hab mich wohl undeutlich ausgedrückt. Der grössere Datenpuffer
bringt mir natürlich deswegen nix, weil ich Samples verpasse, während
ich auf die Karte warte (und daher nicht messen & in den Buffer
schreiben kann). Er würde aber auch bei zu hohen Datenraten nix bringen
(das wollte ich eigentlich zum Ausdruck bringen). Mein Problem sind
aber, wie gesagt, die Latenzen.

Ich glaube inzwischen, dass es am besten ist, zu versuchen die
Messungen komplett über die ISRs zu steuern, während der Kartenzugriff
dann vom Hauptprogramm aus kontrolliert wird.

Werde mal Versuche machen und berichten, wie es so klappt.

Gruss,
Thorsten

von T.S. (Gast)


Lesenswert?

> - Es gibt nicht einen Buffer, sondern zwei. Ein Pointer zeigt auf den
> gerade aktiven.

Double Buffering eben, geht auch. Nur, der Mega hat wenig Speicher und
der Verwaltungsaufwand dafür ist auch erheblich. Viel einfacher wäre es
mit einem Ring-Buffer und Zeigern auf Head und Tail zu arbeiten.

> - Wenn ein Block geschrieben werden soll, wird der SPI Interrupt
> aktiviert und das erste Byte geschrieben. Die ISR sorgt dann dafür,
> dass der Buffer asynchron auf die Karte geschrieben wird (Globale
> Statusvariablen kontrollieren das, wenn der Block fertig ist,
> deaktiviert die ISR den SPI Interrupt). Gleichzeitig wird der Zeiger
> auf den zweiten Buffer gestellt, so dass weitere Schreibzugriffe
> abgebuffert werden können. Die sd_raw Funktion kann sofort
> zurückkehren.

Das mit dem SPI Interrupt hört sich gut an. Leider muß dann Roland's
Code komplett neu geschrieben werden. ;)

> Wo ich noch nicht so genau weiss, wie man es lösen könnte, ist das
> lesen: Was mache ich mit einer Routine, die einen Block einliest und
> dann bearbeitet? Die blockiert dann wieder... (zwangsläufig).

Ja, das stimmt. Schwierig zu lösen.

> Was hältst Du davon?

Google mal nach einem Projekt nennt sich "AVRCam".

Das Konzept gefällt mir sehr gut. Dort wird mit einer globalen
Event-FIFO gearbeitet. Fast alle Events sind nicht-blockierend. TWI
wurde auch komplett in die ISR ausgelagert.

Schau Dir die Quelltexte unbedingt einmal an.

Wenn dieses Projekt CPU- und Speicher-intensives Video verarbeiten kann
muß es doch möglich sein einen Datenlogger mit SD-Karte auf die Beine zu
stellen. ;-)

BTW:
Die disk-info von Malte nach einer Neuformatierung
>free:   120578048/254795776
gefällt mir überhaupt nicht.

So ähnlich verhielt sich auch meine Karte auch kurz bevor sie ganz und
gar den Geist aufgegeben hat. :-(

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Thorsten,

Ich glaube, wir missverstehen uns hier ein bisschen. Wovon ich oben
ausgegangen bin ist, dass die Messung als solche durch eine
Hardware-Einheit des AVR stattfindet, somit keine MCU-Zeit braucht und
zum Schluss jeder Messung ein Interrupt (wie der des ADC) auslöst.

Die Interrupts sind doch in der Hinsicht praktisch, dass sie eben das
busy waiting unterbrechen. D.h. zeitkritische Sachen (wie das Erfassen
eines Messwertes) erledigt man in einer ISR, und Arbeiten mit "hohen
Latenzen" (wie das Schreiben auf die Karte) erledigt man im
Hauptprogramm.
Dem SPI bzw. der Karte ist es ja wurscht, ob durch die ISR-Abarbeitung
eine kleine Verzögerung im Datenverkehr auftritt. Der Interrupt, der am
Ende der Messung ausgelöst wird, garantiert, dass man den Messwert nicht
verpasst.

Das alles funktioniert natürlich nicht, wenn das Messen als solches
keine Interrupts auslöst und noch dazu MCU-Zeit verbraucht. Was misst
Du denn, und wie genau?

Irgendetwas mit dem SPI-Interrupt anzufangen halte ich für sinnlos. Der
feuert mit knapp 1MHz zu häufig.

Natürlich muss das mit den Puffergrößen und den Verzögerungszeiten
durch das Wegschreiben zusammenpassen. Aber irgendwann sind halt die
Grenzen der MCU erreicht, was Verarbeitungsgeschwindigkeit und
Speichergrößen betrifft. Eventuell sollte man dann einen anderen
Controller wählen.

Roland

von Roland R. (roland) Benutzerseite


Lesenswert?

Vielleicht mit weniger Worten in Pseudocode:

ISR(ADC_complete)
{
    puffer.add(ADC_value);
}

int main()
{
    while(true)
    {
        if(puffer.size >= 512)
        {
            sd_raw_write(puffer.data(0 to 511));
            puffer.remove(0 to 511);
        }
    }
}

Natürlich wäre der Zugriff auf den Puffer noch mit einer Semaphore oder
ähnlichem zu synchronisieren.

Roland

von T.S. (Gast)


Lesenswert?

> Ich glaube, wir missverstehen uns hier ein bisschen. Wovon ich oben
> ausgegangen bin ist, dass die Messung als solche durch eine
> Hardware-Einheit des AVR stattfindet, somit keine MCU-Zeit braucht
und
> zum Schluss jeder Messung ein Interrupt (wie der des ADC) auslöst.

Ich bin zwar der Torsten ohne 'h' im Namen aber der andere wollte
Daten vom TWI mit Hilfe eines MAX127 (kenne ich nicht...) lesen. Also
mit HW Unterstützung, und hoffentlich ohne busy-wait beim Register
lesen.

> Irgendetwas mit dem SPI-Interrupt anzufangen halte ich für sinnlos.
Der
> feuert mit knapp 1MHz zu häufig.

Ops, Du hast recht. Eine ISR macht bei der Geschwindigkeit keinen
Sinn mehr.

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Oops, habe gerade gemerkt dass da während dem Schreiben meiner beiden
Beiträge noch was dazugekommen ist. Ich meinte also nicht Dich,
Thorsten S., sondern den anderen Thorsten :)

Roland

von Roland R. (roland) Benutzerseite


Lesenswert?

@Torsten (ohne h)

Das mit dem TWI hatte ich überlesen. D.h. für das Messen ist auch ein
Polling nötig. Dann wird das natürlich schwieriger, ohje...

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

Also ich mach das genau so wie deinem Pseudocode. Das Problem ist nur,
dass während sd_raw_write schon wieder neue Interrupts kommen.

Wozu eigentlich das busy waiting? Wenn man den SPI nicht anderweitg
verwendet, kann man die Karte doch in Ruhe schreiben lassen, während
man den nächsten Puffer mit Daten vollmacht, ohne erst zu warten bis
die Karte fertig ist. Das ist auf jeden Fall genug Zeit. Man kann dann
ja VOR dem nächsten Schreiben das busy flag prüfen.
Siehe http://elm-chan.org/docs/mmc/mmc_e.html

Die von mir berichteten langen Schreibzeiten nach 4096 byte kommen
übrigens von einem karteninternen Puffer (dito).


Malte

von Thorsten (Gast)


Lesenswert?

Roland,

ich sehe, worauf Du hinauswillst.
Gemessen wird mit zwei MAX127 am I2C Bus. Für jeden Messwert müssen 5
bytes über den Bus (Adresse + Kontrollbyte zum starten der Messung,
dann Adresse plus zwei Nullbytes zum lesen des Messwertes). Pro Messung
(16 Kanäle) sind das also 80 bytes, bei 400kHz also ca. 1.6ms. Bei einem
Sample-Interval von 4ms hätte ich dann noch ca. 2.4ms pro Takt zum
speichern, was zwar im Mittel ausreicht, wegen dem angesprochenen
Latenzproblem jedoch nicht funktioniert.
Zur ISR:
Bisher verwende ich eine modifizierte Variante des Atmel-Beispielcodes.
Die ISR kümmert sich hier ums versenden/empfangen der Messages,
initialisieren und verarbeiten tu ich die Ergebnisse in einer normalen
Unterfunktion, die im Augenblick noch vom Hauptprogramm aus aufgerufen
wird. Das Timing geschieht in einer ISR, die von einem 32kHz Takt
angesteuert wird (der Takt kommt von der RTC).
Wenn ich nun aus dieser ISR jeweils alle 4ms die erste TWI Message
anschubse, und in der TWI-ISR dann (gesteuert über ein globales Flag)
automatisch die nächste TWI Message vorbereite, wenn die letzte
vollständig ist (usw.), könnte es gehen. Die Messwerte in der TWI-ISR
in einen Buffer schreiben, der einfach im Hauptprogramm dann gemütlich
auf die SD-Karte wandert. So könnte es gehen. Und das beste: Ich muss
den SD-Code nicht verändern. Dafür halt die TWI-ISR.
Werde das mal so probieren.

@Torsten: Werde mir auch mal AVRCam angucken, danke für den Tip.

Das Forum hier ist spitze :-)

Gruss,
Thorsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Es macht doch nichts, wenn die Karte noch schreibt und schon der
nächste Interrupt kommt? Wenn Du, wie oben beschrieben, zwei Puffer
abwechselnd füllst und gleichzeitig den jeweils anderen schreibst,
kommt Dir das ja nicht in die Quere.
In meinem Pseudocode oben war puffer als Ringpuffer gedacht. D.h. Du
kannst vorne Daten entnehmen, um sie auf die Karte zu schreiben, und
gleichzeitig hinten neue Daten im Interrupt anhängen.
Das dürfte bei Dir auch besser funktionieren als bei Thorsten, der eine
wesentlich höhere Datenrate zu bewältigen hat.

Das Verschieben der Wartezyklen an den Anfang könnte funktionieren.
Müsste man mal ausprobieren. Wie schon erwähnt weiß ich nicht, ob die
Karte den SPI-Takt, der durch das Polling erzeugt wird, zum Schreiben
benötigt. Wenn das der Fall ist bringt das verschieben des Wartezyklus
nichts.

Roland

von T.S. (Gast)


Lesenswert?

> Das mit dem TWI hatte ich überlesen. D.h. für das Messen ist auch ein
> Polling nötig. Dann wird das natürlich schwieriger, ohje...

Nein, ganz im Gegenteil, das macht es ja einfacher weil es eine extra
ISR für TWI gibt.

Mein Problem ist dass ich den MAX127 noch nicht kenne und die Art und
Weise wie man an dessen Daten kommt. Ich google gleich mal.

Langsam wird der Thread unübersichtlich, mehr als 100 Beiträge.
Scrollen macht jetzt keinen Spaß mehr. Was haltet Ihr von einer
Fortsetzung in einem neuen Thread?

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

Ich meinte, schwieriger im Sinne meines Lösungsvorschlages. Der
funktioniert dann nicht mehr.

Einen neuen Thread fände ich gut, aber nur für die Probleme von Malte
und Thorsten. Antworten auf Fragen direkt zu meinem Code oder neue
Versionen von diesem werde ich wohl weiterhin hierher posten.

Roland

von Malte Ibs (Gast)


Lesenswert?

Hallo Roland,

>Es macht doch nichts, wenn die Karte noch schreibt und schon der
>nächste Interrupt kommt?

Irgendwie scheinbar doch. Es fehlen immer Samples. Allerdings arbeite
ich mit nur einem Puffer, weil ich denke, dass das Wegschreiben über
SPI wesentlich schneller geht als das Einlaufen neuer Samples. Das muss
ich mir aber noch mal genau überlegen, vielleicht liegt da der Hase im
Pfeffer.

>Wie schon erwähnt weiß ich nicht, ob die
>Karte den SPI-Takt, der durch das Polling erzeugt wird, zum Schreiben
>benötigt.

In dem von mir oben zitierten Link steht folgendes:

"In principle of the SPI mode, the CS signal must be asserted during a
transaction, however there is an exception to this rule. When the card
is busy, the host controller can deassert CS to release SPI bus for any
other SPI devices. The card will drive DO signal low again when reselect
it during internal process is in progress. Therefore a preceding busy
check (wait ready immediataly before command and data packet) instead
of post wait can eliminate waste wait time."

Daraus schliesse ich, dass das Polling nicht benötigt wird. In dem Link
steht übrigens noch so einiges über write-performance Verbesserung, zB.
dass MMCs viel schneller sind als SDs...

Gruß
Malte

von Malte I. (maltomat)


Lesenswert?

Hallo,

das Verschieben der Wartezyklen an den Anfang hat bei mir nicht
funktioniert. Nach ein paar Schreibzyklen stürzt irgendwas ab.

Dafür funktioniert jetzt bei mir alles, nachdem ich einen zweiten
Puffer eingeführt habe. Wenn der erste voll ist wird er per memcpy in
den zweiten kopiert und der zweite dann weggeschrieben. Kann man sicher
noch eleganter machen...
Allerdings kann ich jetzt nur noch mit 256 bytes Puffergröße arbeiten.
Bei 512 sagt der Compiler zwar, dass nur ~95% des Speichers voll sind,
das Programm läuft aber trotzdem nicht mehr. Da muss ich nochmal ein
bisschen im Forum suchen um zu verstehen, woran das liegt.

Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Danke für das Zitat der Seite. Den Link kannte ich zwar schon, die
Stelle über das Vorziehen der Wartezeit hatte ich jedoch auf die
Schnelle nicht gefunden.
Wenn ich dazu komme werde ich das mit dem Vorziehen selbst mal
ausprobieren. Mal sehen ob ich da was zustande bringe.

Das memcpy() kannst Du Dir sparen, wenn Du einen Pointer auf den
Pufferanfang zum Schreiben verwendest. Dann brauchst Du dem Pointer für
den Pufferwechsel nur die Adresse des anderen Puffers zuweisen und schon
ist dieser aktiv.

Wenn es mit 2x512 Bytes nicht mehr funktioniert, liegt das
wahrscheinlich daran, dass der Stack in den Heap reinwächst. Kurz, Dir
geht das RAM aus. Denn zu den 2x512Byte kommen ja noch die 512Byte
Schreib-/Lesepuffer innerhalb von sd_raw hinzu. Dann bleiben von den
2kB des ATmega32 für alle Variablen, den Stack und den Heap nur noch
512Bytes übrig, und das wird wohl zu wenig sein.

Gruß,
Roland

von Uwe (Gast)


Lesenswert?

Hi!
>Wie schon erwähnt weiß ich nicht, ob die
>Karte den SPI-Takt, der durch das Polling erzeugt wird, zum Schreiben
>benötigt.
Habe in der Hinsicht mal Messungen gemacht und festgestellt das
langsame Karten dadurch viel schneller schreiben
1,8/1,1ms @250KHz/1MHz. Bei Karten, die von sich aus schon recht
schnell sind, ist der Unterschied deutlich geringer 393us/372us.
Wenn der Takt also ganz wegbleibt kann das schon zu Zeitverlust führen.
Die gemessene Zeit ist übrigens der Abstand zwischen dem Ende des
letzten zu schreibenden Byte und der Busy-reaktion, also reine
Schreibzeit.
Viel Erfolg, Uwe

von Malte I. (maltomat)


Lesenswert?

Hallo,

ich habe mal wieder ein Problem:
das Vergrößern von files mit fat16_resize_file() funktioniert
problemlos. Ein Verkleinern führt aber dazu, daß zumindest Windows das
File zwar anzeigt aber nicht mehr öffnen kann. Eine Reparatur über
"Fehlerüberprüfung" ist möglich, wenngleich etwas nervig.

Ich benötige das Verkleinern aus folgendem Grund: Zunächst gehe ich
davon aus, dass ich einen gesamten "Tagesfile" von etw 5MB aufnehmen
werde und blähe die neue Datei auf diese Größe auf, um die vielen FAT
Zugriffe zu vermeiden. Falls die Datenaufnahme aber vorher unterbrochen
wird, möchte ich den File auf die entsprechende Länge zusammenstutzen.
Der Ablauf ist etwa so:

fat16_create_file(...)
open_file_in_dir(...)
fat16_resize_file (fd, 5000000)
fat16_write_file(...)
...
...
fat16_resize_file (fd, new_size)
fat16_close_file (fd)
sd_raw_sync()

Wenn new_size >=5M ist geht es, sonst nicht. Woran könnte das liegen?

Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Danke für den Hinweis.
Aufgrund Deiner Probleme habe ich mir die Funktion fat16_resize_file()
nochmal genauer angeschaut und festgestellt, dass diese seit der
Version 20060808 zwei gravierende Fehler enthält. Durch diese wird u.a.
beim Verkleinern einer Datei deren Clusterkette, die den Dateiinhalt
enthält, in der FAT nicht richtig abgeschlossen. Das dürfte auch der
Grund sein, warum Windows meckert.

Ich werde hier morgen eine korrigierte Version posten.

Gruß,
Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

@Malte

In der angehängten fat16.c habe ich die folgenden Fehler korrigiert:
- Verkleinerte Dateien werden korrekt abgeschlossen.
- Abhängig von der Kartengröße wird der freie Speicherplatz nicht
richtig berechnet, wenn die FAT-Größe UINT16_MAX übersteigt.

Könntest Du die Datei bei Dir bitte kurz antesten? Nach Deinem Ok würde
ich dann ein neues Quellcode-Paket erstellen.

Danke und Gruß,
Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Schande über mich!
Die eben gepostete Version funktioniert nicht, wenn leere Dateien auf
eine Größe kleiner der Clustergröße vergrößert werden.
Die angehängte Version tut jetzt aber hoffentlich.

Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

vielen Dank für die überarbeitete Version. Das Verkleinern von Dateien
klappt jetzt bei meinen Tests!

Die Anzeige des freien Speicherplatzes stimmt nicht ganz:
> ls
 1455  MAIN.C
19200  malte.dat

> disk
manuf:  0x02
oem:    TM
prod:   SD256
rev:    68
serial: 0x707dd547
date:   03/05
size:   255066112
copy:   0
wr.pr.: 0/0
format: 0
free:   240644096/254795776

H:\>dir
 Datenträger in Laufwerk H: hat keine Bezeichnung.
 Datenträgernummer: 44F0-263B

 Verzeichnis von H:\

12.09.2005  23:54                1,455 main.c
01.01.1601  02:00               19,200 malte.dat
               2 Datei(en)         20,655 Bytes
               0 Verzeichnis(se),     254,275,584 Bytes frei

Mir würde es aber auch reichen, wenn der return value von
fat16_write_file() korrekt arbeitet, also '0 on disk full'. Ich habe
das noch nicht ausprobiert. Es geht nur darum, während des Betriebes
festzustellen, ob die Karte schon voll ist.

Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Malte,

Danke für den Test.
Mit Deinem FAT-Image habe ich das Problem mit der nicht ganz korrekten
Anzeige des freien Speicherplatzes auch, kann es mir aber nicht
erklären. Vielleicht hilft es, wenn Du unter Linux nochmal mit
  mkdosfs -F 16 /dev/sda1
formatierst. Eventuell gibt es da durch vorangegangene Tests noch
kleine Inkonsistenzen.

Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Mal wieder gibts ein neues Source-Package auf meiner Homepage und auch
angehängt an dieses Posting. Korrigiert habe ich wie schon diskutiert
das Verkleinern von Dateien und die Berechnung des freien
Speicherplatzes.

@Malte

Könntest Du bitte auf diese neue Version aktualisieren? Jetzt
funktioniert die Speicherplatzberechnung auch mit Deiner FAT. Ich
sollte Code-Änderungen einfach nicht voreilig posten...

Gute Nacht,
Roland

von Malte I. (maltomat)


Lesenswert?

Hallo Roland,

die Anzeige des freien Speichers nähert asymptotisch dem unter Windows
angezeigten. Ich bekomme jetzt (nach einem mkdosfs -F 16 /dev/sda1):

254 369 799 (SD-reader)
254 435 328 (Win)

Die Gesamtgröße der Karte wird bei beiden gleich angezeigt. Unter
Windows wird allerdings, auch wenn sich nur ein 10 byte große Datei auf
der Karte befindet, 4096 Byte belegter Speicher angezeigt. Ich weiss
nicht, ob man der Sache auf den Grund gehen muß.

Besten Dank und Gruß
Malte

von Roland R. (roland) Benutzerseite


Lesenswert?

Hi Malte,

Na das sieht ja schon ganz gut aus. Die 16 Cluster Unterschied machen
nichts aus, das wird an einer im Detail unterschiedlichen Zählweise
liegen. Ein bisschen wundern tut mich bloß, dass der AVR eine ungerade
Bytezahl ausspuckt (oder ist das bloß ein Tippfehler?).

Das mit der 10 Bytes großen Datei sollte mit meinem Code aber genauso
sein, schließlich belegt sie einen ganzen Cluster von eben genau 4kB
Größe. Und die Berechnung des freien Speicherplatzes beruht ja auf der
Anzahl komplett freier Cluster.

Viele Grüße,
Roland

von Reinhold Pieper (Gast)


Lesenswert?

Hallo Roland,
ich habe ein Problem mit der Funktion fat16_write_file,
  /* calculate new file position */
        buffer += write_length;
        buffer_left -= write_length;
        fd->pos += write_length;

Ist die zu schreibende Datei, die einzige Datei auf dem Datenträger
wird der Dir. Eintrag nicht neu geschrieben. In der Abfrage sind dann
beide Werte gleich:
 /* update directory entry */
    if(fd->pos > fd->dir_entry.file_size)

Wenn eine 2. Datei da ist, wird ein Update des Dir. aufgerufen.
Funktioniert jedoch nicht. Im Dir. Eintrag steht dann noch die Alte
Größe wobei die Dateidaten abgelegt wurden.

Viele Grüße
Reinhold

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Reinhold,

Könntest Du das bitte ein bisschen näher erläutern, was genau Dein
Problem ist? Was hat insbesondere das von Dir zitierte if-Statement mit
der Anzahl der gespeicherten Dateien zu tun?

Kannst Du einen Korrekturvorschlag machen? Vielleicht verstehe ich dann
besser, was Du meinst.

Roland

von Reinhold Pieper (Gast)


Lesenswert?

Hallo Roland,
das Problem hat sich geklärt. Die Funktion "sd_raw_sync()" wurde
nicht angesprochen deshalb wurde das Dir. nicht upgedatet. Ein
Speicherproblem war die 2. Ursache.

Wenn ich allerdings an eine Datei ohne Offset Daten anhängen will hab
ich ein Problem.
Die Ursache liegt in der Funktion:
fat16_seek_file(fd,&offset , FAT16_SEEK_END);

Ist offset = 0 wird diese mit return 0 abgebrochen.
Mein Vorschlag:

uint8_t fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset,
uint8_t whence)
{
    if(!fd )          //  || !offset
        return 0;

    uint32_t new_pos = fd->pos;
    switch(whence)
    {
        case FAT16_SEEK_SET:
            new_pos = *offset;
            break;
        case FAT16_SEEK_CUR:
            new_pos += *offset;
            break;
        case FAT16_SEEK_END:
            new_pos = fd->dir_entry.file_size + *offset;
            break;
        default:
            return 0;
    }

    if(new_pos > fd->dir_entry.file_size && !fat16_resize_file(fd,
new_pos))
        return 0;

    fd->pos = new_pos;
    fd->pos_cluster = 0;

    *offset = new_pos;
    return 1;
}

Oder mache ich was falsch?

Gruß und Danke schon mal für den Code
Reinhold

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Reinhold!

Ja, Du machst etwas falsch, aber Du bist nicht der erste...

Bitte schau Dir die Funktionsdeklaration nochmal genau an. Der
Parameter offset ist vom Typ uint32_t* (man achte auf den Stern).
Übergebe einen Zeiger auf eine Variable mit dem Inhalt 0, dann
funktioniert es. Die Funktion nutzt den Zeiger, um Dir den absoluten
Offset zurückzugeben, falls Du ihr nur einen relativen Offset gegeben
hast.

Gruß,
Roland

von Reinhold Pieper (Gast)


Lesenswert?

Hallo Roland,
jau ich hab meinen Fehler erkannt....

Gibt es einen Beispielcode zum anlegen eines Unterverzeichnisses?
Ich muss mit Unterverzeichnissen arbeiten da im Rootverzeichnis die
Anzahl der Einträge ja begrenzt ist.
Bei einer neu formatierten SD soll dann das Verzeichnis automatisch
angelegt werden.

Gruß
Reinhold

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Reinhold,

Am einfachsten wäre es natürlich, den Ordner am PC zu erstellen.

Ansonsten könntest Du fat16_create_file() leicht abwandeln. Ein Ordner
ist bei FAT16 nichts anderes als eine Datei mit den
Verzeichniseinträgen als Inhalt. Wenn Du der Datei das Flag
FAT16_ATTRIB_DIR gibst, wird sie zum Ordner. Eine Funktion gibt es
dafür im Moment nicht.

Roland

von Pete (Gast)


Lesenswert?

Hat das jemand schon einmal mit einer Kingston 256MB SD-Karte
hinbekommen ?

Ich bekomme bei dem Card init in Zeile 212 von sd_raw.c einen "test2"
Fehler:
/* reset card */
    uint8_t response;
    for(uint16_t i = 0; ; ++i)
    {
        response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0);
        if(response == (1 << R1_IDLE_STATE))
    {   printf("test1\n");
            break;
    }

        if(i == 0x1ff)
        {
            unselect_card();
      printf("test2\n");
            return 0;
        }
    }

Die Karte läuft mit 3,3V über Spannungsregler. Teiler sind 3K3 und 2K
Ohm, d.h. bei der Karte kommen die Pegel mit etwas über 3 Volt an.
Nun ja, nicht so optimal.

Würde auch 10k mit 6,6k gehen ? Dann liegt allerdings I=0,5mA recht
niedrig ...

von Pete (Gast)


Lesenswert?

So, geht jetzt, war ein elektrischer Fehler. Vielen Dank für die Library
!!! Jetzt steht dem Abenteuer SD-Card nichts mehr im Wege :-)

Für den 644er musste ich Änderungen am Interface machen. Die Register
enden dort alle mit "0" (z.B. SPCR0).

Pete

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Pete,

Mit meiner Vermutung, dass etwas mit der SPI-Beschaltung nicht stimmt,
bin ich jetzt wohl zu spät dran...
Aber gut, dass es jetzt läuft. An was lag es denn genau?

Das mit den unterschiedlichen Registernamen ist ein leidiges Thema. Es
wird sich nicht vermeiden lassen, hier und dort einige Anpassungen an
die jeweils verwendete MCU vorzunehmen. Einige gängige mega-Typen
unterstütze ich ja von Haus aus, für exotischere AVRs will ich den Code
aber nicht unnötig "ver-#ifdef-en", das wird dadurch eh alles schon
nicht schöner.

Gruß,
Roland

von Reinhold Pieper (Gast)


Lesenswert?

Hallo Roland,
die Funktion fat16_create_file() habe ich modifiziert zu
fat16_create_dir(). Das Ende der Funktion habe ich dazu modifiziert.

Der Dir-Eintrag im Root-Dir wird auch geschrieben aber das
Unterverzeichnis funktioniert nicht richtig.

.......
     cluster_num= fat16_append_clusters(fs, 0, 1);

    /* write directory entry to disk */
    dir_entry->cluster=cluster_num;
    dir_entry->attributes=FAT16_ATTRIB_DIR;
    dir_entry->date_create=format_time();
    dir_entry->date_change=format_time();
    dir_entry->entry_offset = dir_entry_offset;
    if(!fat16_write_dir_entry(fs, dir_entry))
        return 0;

    return 1;

#else
    return 0;
#endif
}

Ach ja das dir_entry habe ich um die Zeit/Datumsinformation erweitert.
Was muß ich machen damit das Unterverzeichnis richtig arbeitet?

Gruß
Reinhold

von Reinhold Pieper (Gast)


Lesenswert?

Hallo Roland,
ich hab herausgefunden das die SUBs nur dann nicht funktionieren wenn
in dem entsprechenden Cluster noch Datenmüll von gelöschten Dateien
steht. Bei einer gereinigten frisch formatierten SD geht alles! Also
muss ich jetzt nur noch den entsprechenden Cluster in dem das
Verzeichnis sein soll vorher löschen oder?
Gruß Reinhold

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Reinhold,

Ja, dass Nullen der neu allokierten Verzeichniscluster ist ok. Es
reicht aus, wenn Du jedes 32. Byte (bei Offset 0 gestartet) auf 0 oder
FAT16_DIRENTRY_DELETED setzt.
Ich habe mich bisher darum gedrückt, da es ja doch einiges an Overhead
darstellt. Siehe dazu den TODO-Kommentar in fat16_create_file().
Effizienter und ohne z.B. 128 einzelne Schreibzugriffe (bei Clustern
von 4kB), die die Lebensdauer der Karte beinträchtigen, lässt sich das
mit einer Callback-Technik a la sd_raw_read_interval() machen.

Du solltest auch in jedem Unterverzeichnis zwei weitere
Unterverzeichnisse mit den Namen "." und ".." anlegen, die auf das
aktuelle Verzeichnis bzw. das Verzeichnis darüber verweisen. Erst dann
ist eine korrekte Ordnernavigation gewährleistet.

Roland

von T.S. (Gast)


Lesenswert?

Mist, ich habe möglicherweise schon wieder eine Karte geschrottet. :(

Folgendes ist mir passiert:

Ich nutze Roland's Code um in einem Datenlogger alle 15min
Temperaturwerte von DS18S20 Sensoren aufzuzeichnen. Nur ein paar chars,
immer in die gleiche Datei. Nichts zeitkritisches, funktioniert super.
Den 'sync' Befehl nach dem schreiben hab ich auch nicht vergessen.

Nun dachte ich mir, es ist mal Zeit für einen Langzeit-Test und habe
meiner Schaltung die auf einem Steckbrett aufgebaut ist einen Akku
spendiert und in die Ecke gestellt. Und natürlich vergessen.

Irgendwann habe ich mich wieder erinnert und nachgesehen. Klar war der
Akku leer. Ok, Karte entfernt und in den Cardreader am PC gesteckt. Nun
der große Schreck - XP meint: Der Datenträger ist nicht formatiert.

Weder unter Linux noch unter XP mit dem SD-Formatter von Panasonic
konnte ich die Karte wieder zum Leben erwecken. Fehlermeldung:
write-protected.

Gut, eine neue kostet kein Vermögen. Aber die alte Karte kann sich doch
nicht einfach in Sonder-Müll verwandeln wenn die Stromversorgung mal
einknickt.

Hat jemand zufälligerweise ähnliche Probleme gehabt oder eine Idee ob
man evtl. mit einem Raw-Write an bestimmter Stelle die Karte(n) retten
könnte?

Torsten

von Pete (Gast)


Lesenswert?

Ich habe die gleichen Probleme :-(

von Pete (Gast)


Lesenswert?

Ergänzung:
Unter Ubuntu (Linux) sehe ich die Karte und kann auch Files lesen.
Formatieren geht auch nicht. Weder mit mkdosfs noch mit cat /dev/zero
</dev/speicherkarte>.

Haben wir uns ausgesperrt ??

P.S.: T.S.: Könntest Du Deinen Code vielleicht hier posten ?

von T.S. (Gast)


Lesenswert?

> Ich habe die gleichen Probleme :-(

Wie ist es bei Dir passiert?

> Haben wir uns ausgesperrt ??

Ich glaube schon.

Auch weil es nicht meine erste Karte ist. Irgend etwas ist oberfaul.
Mag sein wegen der sehr lückenhaften Doku.

> Könntest Du Deinen Code vielleicht hier posten ?

Hhmm.

Das macht atm nicht wirklich Sinn weil ich bestimmt andere HW verwende
und gerade erst angefangen habe. Mitten drin beim experimentieren so zu
sagen - und noch lange nicht fertig.

Wenn Du aber unbedingt darauf bestehst bekommst Du selbstverständlich
den Quelltext. Ich brauche dann aber Deine Mail Adresse und Dein
Einverständnis das Roland ein Cc bekommt.

Torsten

von Avr N. (avrnix) Benutzerseite


Lesenswert?


von Pete (Gast)


Lesenswert?

Hallo T.S.,

meine email Adresse ist p e t e r - k r u s e (a t) g m x. n e t.

Gerne mit Kopie an Roland.

Ich vermute, dass beim Schreiben etwas daneben gegangen ist.(?)

Gruss,
Pete

von T.S. (Gast)


Lesenswert?

@Pete
Done.

@AVR Nix
Zwar kenne ich den thread schon, weil aber auch dieser so ellenlang
ist, ist mir genau das entgangen. Danke für den Link. :-)

Torsten

von Pete (Gast)


Lesenswert?

Habe aber auch in dem Thread keine Lösung für die "Read-only"-Karten
gefunden...

von Malte Ibs (Gast)


Lesenswert?

Hallo,
habt ihr eigentlich schon mal überlegt, wie man solch eine Fehlfunktion
durch Stromausfall verhindern könnte? Würde mich sehr interessieren,
denn sowas kann ja bei jedem autark arbeitenden Datenlogger passieren.
Bei meinem System habe ich mich noch nicht getraut, den Stecker während
des Schreibens zu ziehen. Kann man da vielleicht mit dem Brown Out
Detector was machen? (Ich habe mich noch nicht damit beschäftigt)

Gruß
Malte

von Pete (Gast)


Lesenswert?

Nun ja, irgendwann möchte ich die Daten auch auf meinen PC übertragen.
Ich werde vor dem Schreibvorgang eine LED anmachen und nach dem
Schreiben wieder aus. Dann kann ich sehen, wann ich ziehen darf.

von Uwe (Gast)


Lesenswert?

Hallo Ihr Kartentöter,
Mal ne blöde Frage, Wie sieht denn euer CSD-Reg. an Bitpos.13-15 und
84-95 aus? Schreibschutz? Card Command Classes?

Ich würde da jetzt mal anfangen zu suchen.

MFG Uwe

von T.S. (Gast)


Lesenswert?

@Malte
Nachgedacht schon, aber noch keine Lösung gefunden. Der Brown Out
Detector nützt in meinem Fall gar nichts, weil auch bei fast entladenem
Akku die Zellspannung locker ausreicht. Nur bei hoher Belastung während
eines Schreibvorganges auf die Karte knickt die Spannung ein. Dann,
wenn es zu spät ist.

@Pete
Ich habe die Empfehlung in dem o.g. Thread mal angepasst &
ausprobiert:

if(sd_raw_send_command_r1(CMD_CLR_WRITE_PROT, 0))

{

    unselect_card();

    return 0;
}


Geht nicht wie zu erwarten war. Vielleicht muß die '0' durch etwas
anderes ersetzt werden. Bin ratlos.

Torsten

von Pete (Gast)


Lesenswert?

@Torsten:
Hast Du Deine Karte wieder reaktieren können ?

Beantwortet ist auch noch nicht Deine Frage nach der Reaktivierung der
Karte ...

von Lars (Gast)


Lesenswert?

Hallo hatte leider noch keine Zeit mich in den Source einzuarbeiten.
Arbeite aber mit einer selbstgeschriebenen Software
Aber einige Fragen bzw. Anmerkungen hätte ich schon.
Wie stellt das Programm die relative Adresse der FAT Sektoren fest?
Meiner Erfahrung nach liegt nähmlich der erste Sektor des Dateisystemes
je nach Kartengrösse nicht ab der Adresse 0x00000000 sondern etwa bei
einer 32 MB Karte erst bei 0x00006600. Obwohl er etwa in WINHEX bei
0x00000000 auftaucht.(Im Moment gehe ich nicht von einem Fehler meiner
Software aus)
Jetzt meine Frage könnte das mit dem Writeprotect-Managment der SD
Karte zusammenhängen. Und was passiert wenn man in diese Sektoren Daten
reinschreibt.
Eine weitere Frage wäre weiss irgentjemand hier wo ich eine genaue
Dokumentation über das WriteProtectmanagment herbekomme. In den
Üblichen Datenblättern etwa von Sandisk steht dazu nämlich leider nicht
viel drin.

von Sven Scholz (Gast)


Lesenswert?

Hallo,

lässt sich der Code dahingehend einstellen, dass ich mittels ATmega8 
schreibend auf das FAT16 - Dateiformat zugreifen kann?
Welche Einstellungen müssen hierfür getätigt werden?

Unter BASCOM mittels DOS-AVR bekommt man das nicht realisiert, weil 
hierfür einfach nicht genügend RAM zur Verfügung steht. Wieviel RAM 
benötigt diese Variante minimal für ein FAT-Dateisystem?

Wie sieht es mit einem Low-Level_Zugriff aus?

DANKE schon einmal.

von Nik B. (nikbamert)


Lesenswert?

Hi Sven,

ich denke das sollte so auf dem Atmega8 funktionieren, falls ich die
Tabelle von Rolands Homage richtig interpretiert habe


Ich spreche von der ersten Tabelle auf der folgenden Seite:
http://www.roland-riegel.de/sd-reader/


Grüsse Nik

von Holger Milz (Gast)


Lesenswert?

Hi,

hat jemand schon Verzeichnisse angelegt? Ich kriege es nicht richtig hin 
und habe immer alten Datenmüll in den Verzeichnissen.

Danke!!!

Gruß
Holger

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo zusammen,

Tut mir Leid, dass ich mich in letzter Zeit nicht beteiligt habe. Mit 
Semesteranfang und Umzug hatte ich einiges zu tun.

Vielleicht kann ich nächste Woche wieder was am SD-Reader machen. Dann 
könnte ich auch mal eine Funktion zum Anlegen von Verzeichnissen 
implementieren. Hier plagen sich ja anscheinend einige Leute damit 
rum... ;-)

Viele Grüße,
Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, wie versprochen zur Abwechslung mal wieder eine neue Version des 
sd-reader, zu finden im Anhang oder auf meiner Homepage 
http://www.roland-riegel.de/sd-reader/.

Änderungen sind insbesondere:
- Anlegen/Löschen von Verzeichnissen.
- Löschen neu allokierter Cluster für Verzeichniseinträge.
- Keine Verwendung von printf().
- malloc()/free() sind jetzt optional. Für Handles kann
  nun auch statischer Speicher verwendet werden.

Bei Problemen bitte hier melden.
Viel Spaß damit...

Gruß,
Roland

von T.S. (Gast)


Lesenswert?

Seit etwa 2 Monaten verwende ich die ältere Version von 20060319 in 
einem eigenen Projekt. Alles läuft sehr stabil und zuverläßig. Danke an 
Roland noch einmal dafür!

Nun ist in meinem Projekt etwas aufgetreten womit ich zu Anfang 
überhaupt nicht gerechnet habe: die Datenflut ist einfach zu groß. Alles 
in einer einzigen Datei im root zu speichern war zwar einfach umzusetzen 
aber nicht besonders klug. Aufgrund der Größe macht ein Download auch 
bei 115k nun keinen Spaß mehr.

Kein Problem dachte ich, die neue Version von 20061101 nehmen und alles 
in einzelne Verzeichnisse packen. Doch damit habe ich einige Probleme:

Wenn ich z.B. ein neues Verzeichnis anlege mit "mkdir Test", zeigt ein 
"ls" noch korrekt an das es wirklich angelegt wurde.

Aber beim hineingehen mit "cd Test" und "ls" bleibt alles in einer 
Endlosschleife hängen. Der erste Eintrag wird ständig wiederholt. Nur 
ein Reset erlöst den uC.

Was mich stutzig werden läßt: Nehme ich die Karte und erzeuge im 
Kartenleser unter XP ein gleich lautendes Verzeichnis, dann zurück zum 
uC, zeigt "ls" es korrekt an. Ein "cd Test" und "ls" zeigt 
erwartungsgemäß die Einträge "." und ".." an. Dann zurück mit "cd.." und 
"rm Test" um das Verzeichnis zu löschen. Aber jetzt kommt der Hammer: 
"mkdir Test" und "ls" funktioniert jetzt...

Die Karte habe ich mehrmals mit dem SDFormatter V1.2 formatiert. Einen 
"sync" nach jeder Eingabe habe ich auch nicht vergessen. Der uC und die 
Karte haben genug 'Saft'. ;)

Für jemanden der mit Dateisystemen nicht per 'Du' ist so wie ich ist der 
Quelltext auch wenn er so gut strukturiert ist wie im SD-Reader nicht so 
einfach zu durchschauen.

Deswegen meine Frage an Roland: Kannst Du mir bitte helfen dem Problem 
auf den Grund zu gehen? Möglicherweise könnten einige printf's an der 
richtigen Stelle helfen.

Torsten

von Funkamateur1 (Gast)


Lesenswert?

Hallo  André Kronfeldt,
kiffen kann auch gesundheitsförderlich sein. In den Niederlanden werden 
bei bestimmtne Krankheiten z.B. MS nicht Interferoon und Opium sondern 
das Kiffen als Medikament empfohlen. Spezielle Züchtungen mit 
gesundheitsförderlichen Tendenzen statt Chemiekeule und Abhängigkeit. 
Spritzen kann man nur 2 Jahre. Rauchen kann man das ganze Leben lang.
Roland weiter so. Denn in Zukunft gibt es CF Karten mit 8GB,16GB,32GB 
was ist mit denen.

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo Torsten,

Bezüglich Deines Problems habe ich nicht auf Anhieb eine Idee. 
Allerdings kenne ich im aktuellsten sd-reader einen Bug, der Probleme 
mit neuen Verzeichnissen im Zusammenspiel mit Windows XP bereitet. 
Vielleicht hilft das Beheben dieses Fehlers bei Deinen Problemen weiter.
Ich werde Dir heute oder morgen näheres per Mail zuschicken. Irgendwie 
werden wir das schon hinbekommen...

Gruß,
Roland

von Pete (Gast)


Lesenswert?

@ T.S.:
Hast Du die defekte Karte wieder reaktivieren können oder eine Lösung 
für das Ziehen der Karte beim Schreiben gefunden ?

von Adrian (Gast)


Lesenswert?

Hallo zusammen

Ist es möglich die SD-Karte an einem anderen Port und somit nicht mit 
dem Hardware SPI des AVR zu betreiben mit dem Code von Roland Riegel?

In sd_raw.c wird ja das SPCR Register entsprechend konfiguriert...

von T.S. (Gast)


Lesenswert?

@ Pete
1) Nein.
2) Nein. Das habe ich auch noch nie gewagt.

Mein Problem war ein anderes - nicht ausreichende Spannungsversorgung, 
siehe weiter oben. Die Lösung: aufpassen/vermeiden. ;)

PS: Meine Mail blieb von Dir bis heute unbeantwortet.

Torsten

von Roland R. (roland) Benutzerseite


Lesenswert?

@Adrian,

Klar geht das. Du müsstest jedoch Software-SPI verwenden. Nach kurzer 
Lektüre des Interface-Timings sollte das aber kein Problem sein.

Gruß,
Roland

von Pete (Gast)


Lesenswert?

@Torsten: Sorry, eine PM ist an Dich unterwegs.

Für das Ziehen der Karte oder Ausschalten habe ich eine kleine LED 
installiert, die mir anzeigt, wenn gerade nicht geschrieben wird. So 
richtig Austesten konnte ich das aber noch nicht.

Defekte Karte ist an Kingston unterwegs :)

Viele Grüße,
Pete

von Pete (Gast)


Lesenswert?

Wow ! Kingston hat eine neue Karte geschickt ! DAS nenne ich Service und 
Schnelligkeit !!! (freu)

Montag abgeschickt und Donnerstag die neue Karte in der Hand. Besser 
geht´s nicht :-)

von emil (Gast)


Lesenswert?

Hallo,

entschuldigt bitte die naive Frage aber leider fehlt mir der Durchblick:

kann ich jetzt in Windows XP ein Paar Bitmap-Dateien erstellen, auf 
einer SD-Card speichern (mit einem ganz normalen USB-Kartenleser für den 
PC),
um danach irgendeine beliebige dieser .bmp-Dateien mithilfe des 
Programms von Roland mit einem Mega8 auslesen?

Anders gesagt, ich will einfach Paar .bmp Dateien bequem am PC erzeugen, 
die dann mit einem Mega auf einer LED-Matrix angezeigt werden werden, 
als Speichermedium eben die SD-Card. Es ist nur Lesen seitens des Mega 
nötig, er wird nicht auf die Karte schreiben.

Bedeutet die FAT16 Unterstützung dieses Programms, dass ich eben so 
vorgehen kann und die .bmp-Dateien direkt vom PC auf der Karte kopieren 
kann, ohne sie irgendwie konviertieren zu müssen?

von Hauke Radtki (Gast)


Lesenswert?

Du musst sie nur im µC wieder zu raw dekodieren, was aber nicht äußerst 
schwer ist.

von Roland R. (roland) Benutzerseite


Lesenswert?

@emil,

Wenn der Mikrocontroller weiß, wie er das bmp-Format dekodieren/anzeigen 
kann, dann lautet die Antwort "Ja". Mein FAT16-Code liest exakt die 
selben Daten von der Karte, die das Grafikprogramm auf dem PC in die 
Datei auf der SD-Karte geschrieben hat.

Gruß,
Roland

von emil (Gast)


Lesenswert?

@Roland, Hauke:

danke, genau das brauche ist; mein µC weiss schon, wie er mit .bmp die 
LED Matrix steuert, nur schreibe ich sie z.Z. im Flash vom µC.

Ich mach'mich jetzt an die Arbeit mit der SD-Karte.

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Es gibt wieder eine neue Version im Anhang und wie gehabt unter
    http://www.roland-riegel.de/sd-reader/

Vorsicht: Die vorgenommenen Änderungen korrigieren Fehler im FAT16-Code 
bei der Erstellung von neuen Verzeichnissen. Wenn Ihr eine alte Version 
nutzt und die Funktion fat16_create_dir() verwendet, solltet Ihr auf 
diese Version aktualisieren, sonst droht Datenverlust!

Viele Grüße,
Roland

von M. (Gast)


Lesenswert?

Hallo,
verwende den fat16 Zugriff von Roland Riegel. Im Prinzip funktioniert 
alles prima, allerdings habe ich Probleme wenn ich der Übersicht halber 
die verschiedenen Funktionsaufrufe zum erzeugen eines files in eine 
eigene Funktion packe.
Der entstprechende Funktionsprototyp sieht folgendermassen aus:

uint8_t create_log_file(struct fat16_fs_struct* fs, struct 
fat16_file_struct* fd1)

In der Funktion erzeuge ich meinen gewünschten Dateinamen und mit der 
Funktion fat16_create_file die gewünschte Datei.
Mit fd1 = fat16_open_file(fs, &file_entry) öffne ich die Datei und weise 
den als Paramter übergebenen Pointer struct fat16_file_struct* fd1 zu.

Wenn ich nun in main nach Aufruf von create_log_file folgende Zeilen 
ausführe wird nichts in die Datei geschrieben.

struct fat16_file_struct* fd1;
create_log_file(fs, fd1);

char buffer[]="test";
int8_t data_len = sizeof(buffer);
/* write text to file */
fat16_write_file(fd1, (uint8_t*) buffer, data_len);
sd_raw_sync();

Wenn ich allerdings die selben Zeilen unmittelbar vor der return 
Anweisung in create_log_file einfüge wird der String "test" wie 
gewünscht in die Datei geschrieben.

Wird der Zeiger fd1 nach Beendigung von create_log_file ungültig (bzw. 
der Bereich wo der Zeiger hinverweist)? Oder wo könnte das Problem 
liegen?

Vielen Dank für eure Tips

M.







von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo M.,

Das Problem liegt in Deinem falschen Verständnis der Argumentenübergabe 
in C. Du änderst fd1 nur innerhalb der Funktion. Wird diese verlassen, 
behält sie ihren alten Wert.

Zwei Möglichkeiten:
1. Die elegantere
struct fat16_file_struct* create_log_file(struct fat16_fs_struct* fs)
{
    /* ... */
    struct fat16_file_struct* fd = fat16_open_file(...);
    /* ... */
    return fd;
}
2. Die Abänderung Deiner Funktion
uint8_t create_log_file(struct fat16_fs_struct* fs, struct 
fat16_file_struct** fd)
{
    /* ... */
    *fd = fat16_open_file(...);
    /* ... */
    return 1;
}

Bei weiteren Fragen suche nach einem beliebigen C-Tutorial im Web.

Gruß,
Roland

von M. (Gast)


Lesenswert?

Danke, klappt jetzt.

Super!
M.

von M. (Gast)


Lesenswert?

Hallo,

um meine Daten die ich auf die SD Karte schreibe zu komprimieren, lege 
ich die einzelnen Variablen die ich verwende nicht direkt auf der Karte 
ab sondern beschränke die Anzahl der Bits auf den tatsächlichen 
maximalen Wertebereich. Die Bits der verschiedenen Variablen verknüpfe 
ich zu einem Stream. Über einen Descriptor der jedem neuen Datensatz 
vorausgeht ist die Länge der einzelnen Datenfelder definiert.
Im Prinzip scheint auch alles zu funktionieren, allerdings habe ich hin 
und wieder beim dekodieren nach einer wechselnden Anzahl von Datensätzen 
keine vernünftigen Daten mehr. Ich vermute die Ursache darin, dass beim 
speichern auf die Karte dann an dieser Stelle Daten verloren gegangen 
sind. Der Decodier Algorithmus kommt dann durcheinander weil er durch 
das fehlende Byte um 8 Bit verschobene und somit falsche Bits für den 
Descriptor einliest.
In meiner Funktion zum abspeichern überprüfe ich zwar ob das zu 
speichernde Byte auch geschrieben wird, aber bekomme dort keine 
Fehlermeldung.
Habe sowohl mit als auch ohne SD_RAW_WRITE_BUFFERING das gleiche 
Problem.

Meine Funktion zum speichern und einen exemplarischen Aufbau des Aufrufs 
findet ihr im Anhang.

Tips? Oder suche ich den Fehler an der falschen Stelle? Sind die Daten 
sicher auf der Karte gespeichert wenn fat16_write_file() die richtige 
Anzahl von geschrieben Daten als Rückgabewert liefert? Auf der anderen 
Seite bin ich mir relativ sicher, dass die Kompression und Dekompression 
richtig funktionieren. Schwierig weil der Fehler mehr oder weniger 
zufällig ist.

Danke
M.

von M. (Gast)


Angehängte Dateien:

Lesenswert?

Der versprochene Anhang

M.

von Roland R. (roland) Benutzerseite


Lesenswert?

Hallo M.,

Was mir an Deinem Code auffällt ist, dass data_block nie initialisiert 
wird. Je nachdem, was da nach dem Reset oder durch den vorhergehenden 
Datenstrom noch drinsteht, gibt es nur noch Datenmüll.

Gruß,
Roland

von Pete (Gast)


Lesenswert?

Hallo Roland,

ich habe eine kleinen Service-Request für Deine Bibliothek.

Ich arbeite öfter mal abwechselnd mit dem ATMega16 und ATMega644 und da 
haben leider die SPI-Register unterschiedliche Namen.

Könntest Du es vielleicht etwas generischer in der Bibliothek bauen ? 
Das wäre prima :-)


Gruss,
Pete

von Roland R. (roland) Benutzerseite


Lesenswert?

@Pete,

Die unterschiedlichen Namen sind mir bisher nicht untergekommen.

Du kannst das in der Zwischenzeit aber auch selber machen. In 
sd_raw_config.h definierst Du Dir z.B.
    #define SPI_SPCR SPCR
    #define SPI_SPSR SPSR
für den ATmega16, und entsprechendes für den ATmega644.
In sd_raw.c ersetzt Du dann einfach alle Vorkommen von SPCR durch 
SPI_SPCR und SPSR durch SPI_SPSR. Entsprechendes für die einzelnen Bits, 
falls nötig.

Gruß,
Roland

von M. (Gast)


Lesenswert?

Ja stimmt sollte besser
static uint8_t data_block = 0x00;
in der Deklaration heißen.

Allerdings würde ein abweichender Startwert ja nur den ersten 
gespeicherten Wert beeinflussen. Das von mir geschilderte Problem tritt 
aber erst irgendwann später auf.

M.

von Roland R. (roland) Benutzerseite


Lesenswert?

Hmm, mir ist grad eingefallen, dass afaik statische Variablen ja doch 
einen Standard-Initialisierungswert bekommen.

Was genau Dein Problem sein könnte, weiß ich sonst aber auch nicht. Da 
mein FAT16-Code mittlerweile doch recht gut getestet sein sollte, glaube 
ich aber trotzdem, dass das Problem eher in Deinem Code liegt.

Gruß,
Roland

von M. (Gast)


Lesenswert?

Kann gut sein, werde mich wohl auch damit beschäftigen bis ich die 
Ursache gefunden habe ;-)
Kann es zu Problemen mit der SD Card Kommunikation kommen wenn während 
eines Schreibzykluses ein Interrupt ausgelöst wird? Ich empfange einen 
kontinuierlichen Datenstream über UART. Im Unterschied zu deiner 
Beispielkonsolenanwendung treten also immer Daten an der seriellen 
Schnittstelle auf und es kann dementsprechend auch während eines 
Schreibzykluses ein Interrupt ausgelöst werden.

Gruss
M.

von Roland R. (roland) Benutzerseite


Lesenswert?

Hmm, kann ich nicht mit Bestimmtheit ausschließen, aber ich denke nicht, 
dass Interrupts während eines SPI-Transfers Probleme machen. Der SPI-Bus 
ist unkritisch bzgl. des Timings und die Ansteuerung der Karte 
eigentlich auch.

Hast Du die Bitstream-Algorithmen denn schonmal ohne die UART 
ausprobiert? Also zum Beispiel an Hand von festen oder aufgezeichneten 
Daten?

Gruß,
Roland

von Pete (Gast)


Lesenswert?

Hallo Roland,

ich habe eine Frage zu dem Offset Parameter bei fat16_seek_file.

Wenn ich ein append machen will, geht das dann so? :

int32_t offset = 0;  // zero bytes from the end of the file ==> append
if(!fat16_seek_file(fd, &offset, FAT16_SEEK_END) { ... }

Das klappt auch, wenn das File leer ist ?

Beste Grüße,
Pete

von Roland R. (roland) Benutzerseite


Lesenswert?

Pete wrote:
> Wenn ich ein append machen will, geht das dann so? :

Ja, genau so funktioniert es.

> Das klappt auch, wenn das File leer ist ?

Äh... Sollte es. Gibts Probleme?

Gruß,
Roland

von Mille (Gast)


Lesenswert?

Hi Roland,

erst mal.....super Code den Du da hast!!!
Ich benutze Deinen neuesten Code vom 20.01.07 auf einem Arm7.
Funktioniert alles prima.
Das einzige Problem das ich habe ist, wenn ich Verzeichnisse erstelle
kann ich diese nicht unter Windows XP löschen da Windows mir immer sagt,
das das Verzeichnis nicht leer ist. Selbst erstellte Dateien zu löschen
funktioniert prima auch in ertellten Verzeichnissen.
Hast Du eine Idee?

Danke im voraus!!!
Gruß
Mille

von Roland R. (roland) Benutzerseite


Lesenswert?

Könntest Du mir bitte mal schildern, was Du genau gemacht hast, um den 
Fehler zu bekommen? Eine Schritt-für-Schritt-Anleitung wäre am besten, 
damit ich den Fehler reproduzieren und nachvollziehen kann.

Als Randnotiz: Auf einem Arm hast Du vermutlich mehr RAM verfügbar als 
ich auf einem mega168. Deshalb wäre vielleicht die Verwendung eines 
anderen FAT16-Treibers performanter, da ich bei mir nur wenige 
Strukturen des Dateisystems zwischenpuffern kann.

Grüße,
Roland

von Mille (Gast)


Angehängte Dateien:

Lesenswert?

Hi Roland,

Dein Code funktioniert soweit prima außer dem einem Problem und wenn was 
funktioniert sollte man nicht umsteigen! ;-)))
Wenn ich einfach ein Verzeichnis mit dem Namen "test" so anlege habe ich 
das Problem:

struct fat16_dir_entry_struct dir_entry;
fat16_create_dir(dd, "test", &dir_entry);

Egal ob ich einfach nur ein Verzeichnis alleine anlege oder eine Datei 
hineinschreibe. Die Datei kann ich dann unter Windows XP löschen....das 
Verzeichnis allerdings nicht. Auch wenn ich nur ein Verzeichnis anlege 
ohne eine Datei dort rein zu schreiben! Windows meckert dann immer!!! 
Siehe das JPEG im Anhang. Auch wenn ich das Häkchen unter 
Schreibgeschützt weg mache kann ich das Verzeichnis nicht löschen.
Vielleicht hast Du ja noch eine Idee?

Gruß
Mille

von Roland R. (roland) Benutzerseite


Lesenswert?

Ok, danke. Ich werde mir das mal anschauen, kann Dir aber noch nicht 
sagen, wann ich Zeit dafür finde.

von jeremy (Gast)


Lesenswert?

Hallo,

ich habe Probleme beim initialieren meiner Sd Karten. Wenn ich die 
Karten unter Windows formatiere kommt es relativ oft vor, dass die 
Karten nicht richtig funktionieren. Error beim Filessystem öffnen oder 
mein ganzes Program bleibt schon bei der Initialisierung hängen. 
Formatiere ich unter unix gehen die Karten dann vorerst wieder. Woran 
liegt das? Was verwendet ihr unter Windows zum formatieren eurer Karten?

Bei einer meiner Karten habe ich zudem das Problem, dass ich hin und 
wieder nach Verwendung mit dem Mikrocontroller die Karte nicht mehr 
formatieren und die Dateien löschen kann - Fehlermeldung die Karte ist 
schreibgeschützt.

Danke
Jeremy

von Roland R. (roland) Benutzerseite


Lesenswert?

@Mille,

Gestern habe ich Dein Problem nachvollziehen können. Nach einigem 
Gefummel mit dem Diskeditor habe ich auch den Grund gefunden. Windows 
mag die LFN-Verzeichniseinträge nicht, die meine Software für die "."- 
und ".."-Links erzeugt.

Ich werde mal schauen, wie ich das möglichst einfach beheben kann, oder 
ob ich nicht mehr für alle Dateien einen LFN-Eintrag anlege. In den 
nächsten Tagen wirds dann wohl eine neue Software-Version für den 
sd-reader geben.

Gruß,
Roland

von Dirk Meyer (Gast)


Lesenswert?

Hallo Roland,

da ich demnächst einen offline Temperaturlogger bauen wollte, würde ich 
gerne die Messwerte auf SD-Card speichern. Was ich auf deiner Homepage 
so sehe, sieht sehr gut aus. Respekt.
Zu den Eagle Files hätte ich zwei Fragen: verwendest du von Reichelt den 
"Connector 21"? Wie auch immer, wozu der Anschluss von "Pin" 10, 11, 12? 
Die sind doch für den Schreibschutz der Karte, oder? Wird der 
ausgewertet, bzw. benötigt man denn überhaupt? Wenn ich die Dokus zur 
SD-Karte richtig gelesen habe, dann obliegt die Auswertung des 
Schreibschutzes nur der Software, es wird also nichts hardwaremäßig an 
der Karte ausgeschaltet. Insofern: da ich eh auf die Karte schreiben 
möchte, kann ich mir die 2 Pins (+ 1 GND) auch sparen.

Gruß,

Dirk

von Roland R. (roland) Benutzerseite


Lesenswert?

@Dirk

> Was ich auf deiner Homepage
> so sehe, sieht sehr gut aus. Respekt.

Danke.

> Zu den Eagle Files hätte ich zwei Fragen: verwendest du von Reichelt
> den "Connector 21"?

Ja, richtig.

> Wie auch immer, wozu der Anschluss von "Pin" 10, 11, 12?
> Die sind doch für den Schreibschutz der Karte, oder? Wird der
> ausgewertet, bzw. benötigt man denn überhaupt?

Genau, das sind Schließer zum Erkennen ob eine Karte gesteckt ist und in 
welcher Position sich der Schreibschutzschalter befindet. Ausgewertet 
wird er von meiner Software schon (zumindest rudimentär), wobei das 
ganze optional ist. Du kannst die entsprechenden #defines in 
sd_raw_config.h auch zu 0 bzw. leer definieren. Dann ist quasi immer 
eine nicht schreibgeschützte Karte gesteckt.

> Wenn ich die Dokus zur
> SD-Karte richtig gelesen habe, dann obliegt die Auswertung des
> Schreibschutzes nur der Software, es wird also nichts hardwaremäßig an
> der Karte ausgeschaltet. Insofern: da ich eh auf die Karte schreiben
> möchte, kann ich mir die 2 Pins (+ 1 GND) auch sparen.
>

Richtig und wieder richtig :)

Viele Grüße,
Roland

von Dirk Meyer (Gast)


Lesenswert?

Hallo Roland,

danke für die Antwort. Habe eben bei Reichelt die passenden Bauteile 
(mit kleinen Änderungen) bestellt. Gönne mir den Luxus der 
Pegelanpassung mittels Transistoren und extra Spannungsregler. Das 
bischen neu layouten war auch kein Thema. Was mir dabei aufgefallen ist: 
die Library in deiner Zip Datei der ersten Version enthält den 
Connector, allerdings scheinen die "Platzierungen/Pins" des Connectors 
nicht zu stimmen (sind um 0,05inch verrückt), so dass er im schematic 
nicht angeschlossen werden kann. War allerdings kein Problem: einfach 
das device mit verschobenen Pins neu erstellen, Rest passt wohl 
hoffentlich (jedenfalls nach chinesischem Datenblatt von Reichelt).
Insofern bleibt unterm Strich nur zu sagen: Respekt vor deiner Leistung 
die Software dazu zu entwicklen und dich so in die Materie 
einzuarbeiten!

Gruß,

Dirk

von Roland R. (roland) Benutzerseite


Lesenswert?

Ja, bzgl. der Library hast Du recht. Habe die nicht selbsterstellt und 
hatte damals auch noch keine Erfahrung mit der Bearbeitung. Ich habe 
aber rausgefunden, dass Eagle eine korrekte Verbindung erstellt, wenn 
man das Netz am verschobenen Pin anfängt zu zeichnen. Nur wenn man das 
Netz an dem Pin abschließen will, funktioniert das nicht richtig.

Gut, dass Du ordentliche Pegelwandler und nen eigenen Spannungswandler 
vorsiehst. Ich hatte mit dem Provisorium von Ulrich Radig zwar kaum 
Probleme, das kann aber auch an den von mir verwendeten Karten liegen. 
Wenn die Karte während dem Schreibvorgang Stromspitzen von 100 oder 200 
mA braucht, ist das mit den Dioden wirklich nicht mehr optimal.

Gruß,
Roland

von Roland R. (roland) Benutzerseite


Angehängte Dateien:

Lesenswert?

@Mille und alle anderen,

Es gibt eine neue Version der sd-reader-Software auf meiner Homepage
    http://www.roland-riegel.de/sd-reader/
oder im Anhang.

Ich empfehle eine Aktualisierung, da ich einige nicht ganz unwichtige 
Fehler gefunden und behoben habe:
* Windows kann jetzt die vom sd-reader angelegten Ordner löschen.
* Falls der Dateiname mit dem Byte 0xe5 beginnt, wird dies nun korrekt 
gehandhabt. (Dieses Byte dient normalerweise dazu, die Datei als 
gelöscht zu markieren.)
* fat16_clear_cluster() löscht nun korrekt. Zuvor wurden 16 von 32 Bytes 
nicht richtig auf 0 gesetzt.
* fat16_delete_file() gibt nun auch bei leeren Dateien den richtigen 
Wert zurück.

Viele Grüße,
Roland

von Thomas (Gast)


Lesenswert?

Übrigens gute Meldung bezüglich FAT (zumindest in D):

http://www.heise.de/newsticker/meldung/86102

von Gast (Gast)


Lesenswert?

Ist Rolands Server down ? Ich bekomme keine Verbindung.

von Mille (Gast)


Lesenswert?

@Roland,

kurzes feedback.
Funktioniert alles prima!!! Super Arbeit!!! ->froi<-

Gruß
Mille

von Roland R. (roland) Benutzerseite


Lesenswert?

@Gast,

Ja, mein vServer ist down. Der Host hatte nach Auskunft des Providers 
einen Kernel-Panic, jetzt muss das Datei-System überprüft werden.

@Mille,

Danke!

Gruß,
Roland

von Roland R. (roland) Benutzerseite


Lesenswert?

So, wieder online...

:-))
Roland

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.