Hallo,
auf dem Arduino Due ist der SAM3X8E, den ich schon erfolgreich mit dem
Atmel Studio programmiere. Alles läuft inzwischen wie gewünscht, auch
der SPI-Bus. Mit den angeblich vorhandenen Bibliotheken des Atmle Studio
für SD-Karten komme ich gar nicht klar, offensichtlich sind die wohl
auch nicht für einen einfachen SPI-Bus der SD-Karte vorgesehen. Ein
voller Anschluß mit 4 Bit Breite geht bei mir nicht, da schon viele
Ports vergeben sind.
Also habe ich die Blbliotheken vom LPCXpresso genommen, genauer gesagt
die Files ff.c und mmc.c. ff.c ist unverändert übernommen worden, mmc.c
habe ich an meine Hardware und meine eigenen SPI-Bus Finktionen
angepaßt, alles andere bleieb ebenfalls unverändert. Damit funktioniert
auch der Zugriff aud SD-Karten - aber nur lesend. Sobald ich versuche,
eine Datei zu schreiben, funktioniert das fopen, später ist auch eine
Datei mit dem Manen vorhanden, aber die Datei ist leer, fwrite
funktioniert nicht.
Mit dem Debugger habe ich das fwrite verfolgt und konnte feststellen,
daß der Fehler in der Funktion xmit_datablock stattfindet.
Hier mal der Inhalt meiner mmc.c (langer Code), die Funktion ist bei
etwa Zeile 230:
caseMMC_GET_TYPE:/* Get card type flags (1 byte) */
563
*ptr=CardType;
564
res=RES_OK;
565
break;
566
567
caseMMC_GET_CSD:
568
/* Receive CSD as a data block (16 bytes) */
569
if(send_cmd(CMD9,0)==0/* READ_CSD */
570
&&rcvr_datablock(ptr,16))
571
res=RES_OK;
572
break;
573
574
caseMMC_GET_CID:
575
/* Receive CID as a data block (16 bytes) */
576
if(send_cmd(CMD10,0)==0/* READ_CID */
577
&&rcvr_datablock(ptr,16))
578
res=RES_OK;
579
break;
580
581
caseMMC_GET_OCR:/* Receive OCR as an R3 resp (4 bytes) */
582
if(send_cmd(CMD58,0)==0){/* READ_OCR */
583
for(n=4;n;n--)*ptr++=rcvr_spi();
584
res=RES_OK;
585
}
586
break;
587
588
caseMMC_GET_SDSTAT:
589
/* Receive SD statsu as a data block (64 bytes) */
590
if(send_cmd(ACMD13,0)==0){/* SD_STATUS */
591
rcvr_spi();
592
if(rcvr_datablock(ptr,64))
593
res=RES_OK;
594
}
595
break;
596
597
default:
598
res=RES_PARERR;
599
}
600
601
deselect();
602
}
603
604
returnres;
605
}
606
#endif /* _USE_IOCTL != 0 */
Die Funktion xmit_datablock läuft auch durch, aber zum Schluß liefert
das Lesen resp = rcvr_spi(); den Wert 0xff, erwartet wird eine Antwort
0x05, nachdem sie mit 0x1f verundet wurde, d.h die obersten 3 Bits sind
egal.
Aus irgendeinem Grund wird der Datenblock nicht geschrieben, warum, das
kann ich nicht nachvollziehen. Die SPI-Zugriffe funktionieren jedenfalls
einwandfrei, es gibt ja nur Daten lesen und Daten schreiben, die jeweils
andere Funktion wird ignoriert, denn SPI-Zugriffe machen ja eigentlich
immer lesen und schreiben gleichzeitig. Beide Funktionen werden schon
beim Lesen von Dateien genutzt und da funktioniert es ja. Einziger
Hinweiß, der zu diesem Thema auf google zu finden war, hatte als Tip
eine Neuformatierung der SD-Karte ergeben, was bei mir jedoch keine
Änderung ergab. Der Schreiber dort hatte es schließlich gelöst, nachdem
er alles auf 3.3V Pegel geändert hatte, bei mir ist das aber beriets der
Fall.
Hat jemand schon Code für SD-Kartenzugriffe angewendet, vor allem mit
ff.c und mmc.c? Den Code gibt es offensichtlich für diverse Prozessoren,
man muß eben nur die SPI-Funktionen selber anpassen. Der CS-Anschluß
wird übrigens nicht vom der SPI-Hardware des Prozessors bedient, sondern
von einem separaten Port gesteuert, das ist bei mir auch entsprechend
gemacht worden, sonst würde ja auch das Lesen von Dateien nicht
funktionieren.
Gruß
Andy
Andreas W. schrieb:> mmc.c (langer Code)
Das brauchst du nicht extra zu schreiben - merkt doch jeder selbst, wenn
er nach dem Runter-Scrollen seine wunden Finger sieht :-(
Man fragt sich unwillkürlich, wofür es hier im Forum die Möglichkeit
eines Dateianhanges gibt?
Der Punkt ist, dass du hier hunderte Zeilen Code hast + Hardware ohne
einen blassen Schimmer, wo der Fehler liegt. Du musst das Problem in
kleinere Stücke zerlegen.
Also
1) Elektrische Signale auf Qualität prüfen (Oszilloskop, Augendiagramm)
2) Elektrische Signale auf Korrektheit prüfen (Logikanalyzer)
3) Eine Software verwenden, bei der du ganz sicher bist, dass sie mit
deiner konkreten SD Karte Funktioniert
Also notfalls mit irgendeiner fertigen Open-Source Hard+Software
beginnen, die fix und fertig geliefert wird. Dann ersetzt du sie
schrittweise durch deine eigene Hardware, dann erst baust du deine
Eigene Software ein.
Wenn du das nicht kannst, dann versuche eine andere Library. Zum
Beispiel die https://www.mikrocontroller.net/articles/AVR_FAT32. Damit
bin ich glücklicherweise auf Anhieb zurecht gekommen.
Hallo,
die andere Library AVR_FAT32 hat das Problem gelöst! Bei mir ist es zwar
der SAM3X8E, aber das war kein großes Problem. Die hardwarespezifischen
Funktionen mußte ich ja sowieso umschreiben, ich benutze ja sogar eigene
SPI-Funktionen. Und das spielt alles schön zusammen. Daß man nur eine
Datei zur gleiche Zeit offen haben kann (es gibt keinen Filepointer wie
z.B. in C) macht nichts aus, ich lese Dateien nacheinander und schließe
eine, bevor die nächste dran ist. Auch das Fehlen einer Meldung, wenn
beim ffread() das Ende der Datei erreicht ist, ist kein großes Problem,
man muß eben die Größes des Files lesen und herunterzählen.
Dafür ist der Code erheblich sauberer und übersichtlicher als der Code
vom LPCXpresso (ff.c und mmc.c) geschrieben. Auch die Quittung von der
alten Funktion xmit_datablock (die heißt hier jetzt anders) wird hier
mehrfach abgefragt, bis sie kommt (bis zu 20-mal), die Änderung hatte
ich im alten Code auch schon versucht, dort ohne Erfolg. Wahrscheinlich
hat beim alten Code die Funktion dann tatsächlich geschrieben, ich
vermute den Fehler inzwischen irgendwo in ff.c auf höherer Ebene, wo
z.B. die FAT durchwühlt wird.
Auf jeden Fall ist die neue Library sehr brauchbar und funktioniert
inzwischen in meiner originalen Umgebung mit allem Drum und Dran.
Gruß
Andy
Hallo,
leider zu früh gefreut... Eine Datei auf eine leere Karte schreiben
funktioniert. Sind bereits andere Dateien drauf, werden die teilweise
gelöscht oder teilweise zerstört oder seltsam umbenannt. Da geht also
auch in der FAT bzw. in den Namenstabellen was schief.
Wenn ich nur Dateien lese und keine schreibe, funktioniert das beim
ersten mal nach dem Einschalten und Aufruf von mmc_init() und
fat_loadFatData() sehr gut. Aber nach Ausschalten und erneut einschalten
sind die Dateien ebenfalls korrumpiert. Im Beispiel in der Funktion
main() ist aber keine Art unmount oder so vorhanden. Gibt es da etwas
entsprechendes, das dafür sorgt, daß alle Änderungen auf der Karte
landen, bevor ausgeschaltet wird?
Evtl. hängt das auch mit den zerstörten Dateien beim Nur-Lesen zusammen.
Wenn das nicht geht, werde ich wieder zur alten LPCXpresso Library
zurückkehren, da funktioniert es wenigstens, solange man nur liest und
nicht schreibt. Da das Ganze eine Fernbedienung für einen
Surroundverstärker wird und die über Funk in beiden Richtungen
kommunizieren wird, werden die zu schreibenden Daten dann wohl zum
Verstärker gefunkt und dort gespeichert. Dort werkelt ein Raspberry Pi
und da funktioniert das mit der SD-Karte... Ist aber irgendwie blöd,
wenn es keine Library für Atmel gibt, die vernünftig mit SD-Karten
klarkommt.
Gruß
Andy
Hallo,
die elektrische Qualität ist gut, es sind auch keine Pegelwandler
erforderlich, da der Arduino Due mit 3.3V läuft. Was noch sein kann, ist
der SPI-Modus, d.h. welche Polarität und welchen Ruhepegel der Takt hat
und bei welchen Flanken Daten gelesen und geschrieben werden. Es gibt da
insgesamt 4 Möglichkeiten. Da werde ich noch genauer weiterforschen.
Momentan hängt die SD-Karte direkt an den Portpins, der Buffer ist
momentan nicht benutzt, um den als Fehlerquelle auszuschließen. Der wird
erst nötig, wenn auch noch andere SPI-Hardware dazukommt, denn der
Arduino Due hat nur einen SPI-Port. Mit dem Buffer trenne ich die
SD-Karte komplett vom Bus, wenn ich den anderweitig benutze, den
SD-Karten mögen es nicht unbedingt, wenn nebenher ohne CS Aktivität auf
den Daten und Taktleitungen vorhanden ist.
Die Library vom LPCXpresso scheint wohl auch korrekt zu sein, denn
einmal klappte das Schreiben ja. Da gibt es wohl vor allem Probleme mit
dem Schreiben eines Sektors.
Gruß
Andy
Hallo,
Stromversorgung dürfte ausreichend sein. Der SPI-Modus war wohl richtig,
aber die Clockfrequenz des SPI-Busses war mit ca. 2.5MHz wohl zu hoch,
bei der Initialisierung sollen es ja 100-400kHz sein. Nachdem ich das
geändert habe, lief das Lesen mit der Library vom LPCXpresso
einwandfrei. Schreiben aber nicht, da habe ich die Schreibroutine für
einen Block im Verdacht, die ist sehr "dreckig" programmiert...
Dann habe ich eine Kopie vom Projekt angelegt und das auf die oben
angegebene AVR-FAT32 Library umgestellt. Das läuft mit Lesen auch,
allerdings nur, solange nicht versucht wird, nicht vorhandene Dateien zu
lesen. Leider ist keine genauere Doku zu finden, was man machen soll,
wenn z.B. ein Öffnen der Datei nicht klappt. Muß dann z.B. trotzdem nach
dem ffopen() ein ffclose() folgen? Momentan mache ich das nicht
(schließlich wurde die Datei ja nicht geöffnet) und offensichtlich wird
dann die Filestruktur zerstört. Muß also doch auch bei vergeblichem
ffopen() ein ffclose() folgen? Und was macht man in anderen Fällen, wenn
es eine Fehlermeldung gibt? Schadet ein zusätzliches ffclose(), obwohl
keine Datei offen ist oder passiert dann nichts? Schreiben funktionierte
noch nicht, bis dahin bin ich noch nicht gekommen. Momentan läuft der
Zugriff durchgehend mit 400kHz, das Hochsetzen der Taktfrequenz nach dem
Init mache ich erst, wenn alle Dateizugriffe funktionieren.
Nachtrag: ffclose genügt nicht. Nach dem ersten Einschalten kann ich
alle Dateien problemlos lesen. Nach Power off und erneutem Power on sind
Dateien verschwunden und die Filestruktur wohl auch angeknackst. Muß man
vor dem Power off noch etwas machen, um eine Zerstörung des Filesystems
zu verhindern? Im Beispielcode findet in der Funktion main() nach dem
letzten Zugriff nichts mehr statt.
Gruß
Andy
Hast du mal die Kommentare im Quelltext gelesen? Die sind hilfreich.
Ich zittiere:
// schliesst die datei operation ab. eigentlich nur noetig wenn
geschrieben/ueberschrieben wurde. es gibt 2 moeglichkeiten :
// 1. die datei wird geschlossen und es wurde ueber die alte datei länge
hinaus geschrieben.
// 2. die datei wird geschlossen und man war innerhalb der datei
groesse, dann muss nur der aktuelle sektor geschrieben werden.
// der erste fall ist komplizierter, weil ermittelt werden muss wie
viele sektoren neu beschrieben wurden um diese zu verketten
// und die neue datei laenge muss ermitt weden. abschließend wird
entweder (fall 2) nur der aktuelle sektor geschrieben, oder
// der aktuallisierte datei eintrag und die cluster (diese werden
verkettet, siehe fileUpdate() ).
Und wenn du Dir den Quelltext anschaust, siehst du, was die Funktion
genau macht:
1) Beenden einer Multi-Block Operation (falls MMC_MULTI_BLOCK==TRUE &&
MMC_OVER_WRITE==FALSE)
2) Flush data (also den Schreib-Puffer)
3) Setze file.cntOfByte=0 und file.seek=0;
Langer Rede kurzer Sinn: Diese Methode musst du nur nach
Schreiboperationen aufrufen. Also nach Fehlern beim lesen oder Öffnen
nicht.
> Muß man vor dem Power off noch etwas machen, um eine Zerstörung> des Filesystems zu verhindern?
Normalerweise nicht, hab ich noch nie gemacht.
Wenn die Karte nicht getaktet (also nicht angesprochen) wird, kann sie
auch keine Daten veändern. Es sei denn, die Spannungsversorgung macht
ganz üble Sachen.
Hast du mal eine andere SD karte versucht? Es ist bekannt, dass viele SD
Karten im SPI Modus nicht korrekt funktionieren. Aus dem Bauch heraus
würde ich schätzen, dass jede dritte nicht geht.
@Stefan Us (stefanus)
>Hast du mal eine andere SD karte versucht? Es ist bekannt, dass viele SD>Karten im SPI Modus nicht korrekt funktionieren. Aus dem Bauch heraus>würde ich schätzen, dass jede dritte nicht geht.
Das halte ich für ein Gerücht, in die Welt gesetzt von "Experten" die
mit den frikeligsten Adaptern und den schlechtesten Schaltungen
(Pegelwandler mit Widerständen etc.) arbeiten.
Hallo,
inzwischen habe ich das auch gesehen und bin auch die Source von mmc.c
fast komplett durchgegangen, nur die Multiblockoperationen habe ich
nicht beachtet, da die bei mir gar nicht aktiviert sind. Dabei bin ich
auch über die Funktion spi_init() gestolpert. Die pfuscht in
irgendwelchen SPI-Registern des Prozessors herum obwohl ich den SPI-Bus
selber mit eigenen Funktionen initialisiere. Das wird also als nächstes
komplett auskommentiert, auch die Funktionen, die die Taktfrequenz
verstellen, da kommt dann was eigenes dahin, wenn es erst einmal mit
400kHz klappt. Vielleicht hilft das schon. Ansonsten habe ich endlich
eine brauchbare SPI-Spec gefunden (war was mit sdcard.org, Files heißen
z.B. Part1_410.pdf). Der vorhandene Code widerspricht dieser Spec auf
den ersten Blick nicht, ich muß mal die entsprechenden Funktionen (cmd
senden, Block lesen und schreiben, Initialisierung) mit der Library vom
LPCXpresso vergleichen, was da für Unterschiede vorhanden sind.
Ich würde auf jeden Fall die AVR-FAT32 Library bevorzugen, wenn sie
funktioniert, da die erheblich besser geschrieben wurde und auch mehr
Kommentare enthält. Die andere ist fast gar nicht kommentiert und
dokumentiert, da gab es nur noch ein Beispielprogramm...
Gruß
Andreas
@Andreas W. (andy_w)
>inzwischen habe ich das auch gesehen und bin auch die Source von mmc.c>fast komplett durchgegangen, nur die Multiblockoperationen habe ich>nicht beachtet, da die bei mir gar nicht aktiviert sind.
Hä? Die macht er automatisch, wenn du größere Datenblöcke schreibst.
Diese Funktionen MÜSSEN korrekt sein. Da kann man nichts abschalten!
Das FATfs von Elm Chan funktioniert Prima, man muss nur die hardwarenahe
Anpassung an den jeweiligen Prozessor machen.
Beitrag "Re: Problem mit Micro-SD-Karte">selber mit eigenen Funktionen initialisiere. Das wird also als nächstes>komplett auskommentiert, auch die Funktionen, die die Taktfrequenz>verstellen, da kommt dann was eigenes dahin, wenn es erst einmal mit>400kHz klappt.
Ob das so sinnvoll ist? Der Meister aus dem fernen osten hat sich dabei
schon was gedacht. Man muss die jeweiligen Funktion an die Hardware
anpassen, aber NICHTS auskommentieren!
>z.B. Part1_410.pdf). Der vorhandene Code widerspricht dieser Spec auf>den ersten Blick nicht, ich muß mal die entsprechenden Funktionen (cmd>senden, Block lesen und schreiben, Initialisierung) mit der Library vom>LPCXpresso vergleichen, was da für Unterschiede vorhanden sind.
Vergiss es. Die höheren Funktion sind OK. Dein Problem liegt in der
Hardwareanpassuung der untersten Funktionen!
>Ich würde auf jeden Fall die AVR-FAT32 Library bevorzugen, wenn sie>funktioniert, da die erheblich besser geschrieben wurde und auch mehr>Kommentare enthält.
Ansichtsache.
> Die andere ist fast gar nicht kommentiert und>dokumentiert, da gab es nur noch ein Beispielprogramm...
Quark.
http://elm-chan.org/fsw/ff/00index_e.html
> Hä? Die macht er automatisch, wenn du größere Datenblöcke schreibst.> Diese Funktionen MÜSSEN korrekt sein. Da kann man nichts abschalten!
Doch, kann man. Es gibt einen ganzen Block von #defines, mit dem man
einzelne Feature deaktivieren kann.
Hallo,
genau so ist es, ich habe in der Konfiguration MMC_MULTI_BLOCK auf FALSE
stehen, das war auch defaultmäßig schon so. Und alle
Multiblockfunktionen stehen zwischen #ifdef MMC_MULTI_BLOCK und #endif,
werden also gar nicht compiliert. Multiblock wird durch mehrfache
Aufrufe der Funktionen für einen einzelnen Block realisiert.
Mit der "anderen" Library meine ich die vom LPCXpresso, nicht die von
Elm Chan.
Ich muß die SPI-Grundfunktionen erheblich anpassen, da die wohl eher für
einen anderen Prozessor gedacht sind, ich weiß nicht, ob das überhaupt
für einen SAM3X8E so direkt paßt. Es sind ja vor allem die Funktionen
zum Lesen und Schreiben eines einzelnen Bytes über den SPI-Bus sowie
dessen Initialisierung. Ebenso das Ansprechen des Portpins, der das
CS-Signal erzeugt, der CS von der SPI-Hardware wird nicht benutzt, so
ist es ja auch im Original schon vorgesehen.
Gruß
Andy
@ Andreas W. (andy_w)
>Ich muß die SPI-Grundfunktionen erheblich anpassen, da die wohl eher für
OMG! Was für eine LAST! Geht dem Mann eine Heldenmedaille!
Menschenskinder, diese Aufgabe haben vor dir schon Tausende von Leuten
gemacht und nicht so ein Gewese gemacht. Das bischen Kram dauert
vielleicht 1-2 Stunden, dann sollte das laufen. (jaja, ich habe selber
den Beweis gelifert, dass es auch mal länger dauern kann, aber da war
ich selber Schuld. Man sollte halt ab und an etwas langsamer und
gründlicher arbeiten).
>dessen Initialisierung. Ebenso das Ansprechen des Portpins, der das>CS-Signal erzeugt, der CS von der SPI-Hardware wird nicht benutzt, so>ist es ja auch im Original schon vorgesehen.
Ja und? Das ist EINE einfachste Zeile in einem #define! Sowas allein zu
hier zu erwähnen ist Energieverschwendung.
Hallo,
schalte ich die Write-Funktionalität ab (MMC_WRITE FALSE), dann
funktioniert das Lesen einwandfrei. Mit MMC_WRITE = TRUE schreibt
ffclose Sektoren auch beim Lesen einer Datei, das passiert in
fflushFileData(), das in ffclose aufgerufen wird - aber eben nur, wenn
MMC_WRITE = TRUE ist.
Warum werden eigentlich beim reinen Lesen Sektoren geschrieben? Ich habe
das mit dem Debugger und einem gesetzten Breakpoint in der Funktion zum
Sektorschreiben festgestellt. Kein Wunder, daß dann irgendwann beim
Lesen die Sektoren evtl. verändert werden und das Filesystem nicht mehr
konsistent ist, zumindest bei Dateien, die man lesen will und die noch
nicht existieren. Mit MMC_WRITE = FALSE werden nie Sektoren geschrieben
und das Lesen funktioniert trotzdem (warum auch nicht).
Gruß
Andy
@ Andreas W. (andy_w)
>Warum werden eigentlich beim reinen Lesen Sektoren geschrieben?
Das werden sie nicht. Das ist ein Irrtum.
>Ich habe>das mit dem Debugger und einem gesetzten Breakpoint in der Funktion zum>Sektorschreiben festgestellt.
Dann hast du noch mehr Bugs.
Hallo,
wieso landet dann der Debugger schon beim Lesen der ersten Datei, die
auch vorhanden ist, in der Funktion zum Schreiben eines Sektors? Das
sogar mehrere Male, indirekt aufgerufen über ffclose und fflushFileData.
Vor dem ersten Aufruf war fat.bufferDirty = TRUE.
Die SD-Karte habe ich auf dem PC jedesmal neu formatiert, allerdings nur
schnell, und dann die Dateien wieder draufgeschrieben, dann sollten doch
die relevanten Sektoren (FAT, Directories, vorhandene Dateien) korrekt
sein.
Ich werde mit dem Debugger nun mal das ffclose komplett durchsteppen,
wer weiß, was da noch für Überraschungen lauern...
Gruß
Andy
> Mit MMC_WRITE = TRUE schreibt> ffclose Sektoren auch beim Lesen einer Datei.
Dann hast du mit hoher Warscheinlichkeit einen Stack-Überlauf. Der führt
dazu, dass Variablen überschrieben werden.
Benutze mal die Suchfunktion, um Beiträge zu finden, wie man das prüft.
Hallo,
inzwischen habe ich das Problem gefunden: ffopen merkt sich nicht, ob
eine Datei zum Lesen oder zum Schreiben geöffnet wurde. Beim ffclose
wird unterschiedslos dann fflushFileData() aufgerufen. Und die Funktion
schreibt immer mindestens einen Sektor, zumindest den zuletzt gelesenen,
denn es könnte ja sich was beim Schreiben geändert haben. Noch
schlimmer: ffread() gibt keine Rückmeldung darüber, ob man schon das
Ende der Datei erreicht hat. Bei mir kam es vor, daß evtl. für ein
Zeichen mehr ffread() aufgerufen wurde. Damit war die neue Dateilänge im
ein Byte länger als die ursprüngliche und entsprechend wurde dann auch
ein Sektor geschrieben. Inzwischen habe ich meine Leseroutinen so
geändert, daß nicht mehr Daten gelesen werden als der Dateilänge
entspricht.
Ich habe daher in der Struktur file ein weiteres Element hinzugefügt (in
der Datei mmc-config.h, Kommentare hier im Listing zum Teil wegen zu
langer Zeilen entfernt und etwas formatiert, da Tabs hier nicht richtig
passen):
1
externstructFile_t
2
{
3
uint16_tcntOfBytes;
4
uint32_tseek;
5
uint32_tcurrentSectorNr
6
uint32_tlength;
7
uint8_t*name;
8
uint8_trow;
9
uint32_tfirstCluster;
10
uint32_tentrySector;
11
uint8_trw_flag;// das ist neu von mir
12
}file;
in file.rw_flag wird das 'r' bzw. 'c' vom ffopen gespeichert. Hier der
Anfang von ffopen (Datei file.c):
1
uint8_tffopen(uint8_tname[],uint8_trw_flag)
2
{
3
uint8_tfile_flag=fat_loadFileDataFromDir(name);
4
if(file_flag==TRUE&&rw_flag=='r')
5
{
6
fat_getFatChainClustersInRow(file.firstCluster);
7
file.name=name;
8
file.rw_flag=rw_flag;// das ist neu von mir
9
......
in ffclose wird nun file.rw_flag abgefragt und nur, wenn geschrieben
wurde ('c'), wird fflushFileData() aufgerufen. Beim Lesen ist das völlig
unnötig und stellt nur eine mögliche, zusätzliche Fehlerquelle dar.
if(file.rw_flag=='c')// die if-Abfrage ist neu von mir
16
{// nur machen, wenn ffopen mit 'c' aufgerufen wurde
17
fflushFileData();
18
}
19
#endif
20
21
file.cntOfBytes=0;
22
file.seek=0;
23
24
returnTRUE;
25
}
Nun funktioniert zumindest schon mal das Lesen einwandfrei. Beim
Schreiben eines Sektors gibt es wohl noch Probleme, die noch zu klären
sind, aber so findet das Lesen endlich ohne Sektorschreiben statt.
Gruß
Andy
@ Andreas W. (andy_w)
>inzwischen habe ich das Problem gefunden: ffopen merkt sich nicht, ob>eine Datei zum Lesen oder zum Schreiben geöffnet wurde. Beim ffclose>wird unterschiedslos dann fflushFileData() aufgerufen. Und die Funktion>schreibt immer mindestens einen Sektor, zumindest den zuletzt gelesenen,>denn es könnte ja sich was beim Schreiben geändert haben. Noch>schlimmer: ffread() gibt keine Rückmeldung darüber, ob man schon das>Ende der Datei erreicht hat.
Das kann ich kaum glauben. Und wenn, dann wäre die lib extrem buggy und
pre Alpha Stadium.
Nimm Elm Chans FATfs und sein glücklich, das Ding ist solide.
>Nun funktioniert zumindest schon mal das Lesen einwandfrei. Beim>Schreiben eines Sektors gibt es wohl noch Probleme, die noch zu klären>sind, aber so findet das Lesen endlich ohne Sektorschreiben statt.
Warum nimmst du eine Lib, die nicht sonderlich verbreitet und getestet
ist?
Hallo,
ich dachte, wenn die Lib hier in den Artikeln enthalten ist, wird die
wohl auch brauchbar sein. Ich habe jetzt noch die Lib von Elm Chan
downgeloaded, das wird aber die letzte Lib sein, die ich noch
ausprobieren werde. Die Anpassungen sind ja zum Glück nahezu dieselben,
also zum großen Teil Copy&Paste und relativ wenig Zeilen. Nur die
Aufrufe muß ich wieder anpassen, da Funktionen wie f_open usw. andere
Parameter haben, wahrscheinlich auch wieder ein Filepointer. Das wird
aber erst morgen was, hoffentlich ist die besser und hoffentlich
schreibt die keine Sektoren, wenn man nur liest...
Gruß
Andreas
Hallo,
endlich scheint es zu funktionieren. Zumindest kann ich jetzt Files
lesen und schreiben, das muß sich jetzt aber noch für längere Zeit
bewähren.
Die Library von Elm Chan funktionierte beim Nurlesen von Dateien auf
Anhieb, nachdem ich alle Hardwareanpassungen gemacht habe, da werden
dann auch keine Sektoren beschrieben. Schreiben funktionierte aber immer
noch nicht. Zunächst stellte ich fest, daß meine SPI-Funktion schon
einen Return machte, bevor die letzten SPI-Takte zudene waren, Bei der
Funktion, die SPI gleichzeitig liest und schreibt (das ist eigentlich
der Normalfall) war das nicht, nur bei den Spezialfunktionen für die
SD-Karte, die nur schreiben (dann werden die gelesenen Daten ignoriert)
und nur lesen (dann wird immer 0xff geschrieben) fehlte beim Copy&Paste
am Schluß das Warten auf die vollendete SPI-Übertragung...
Trotzdem funktionierte das Schreiben nicht. Ich stellte fest, daß beim
Schreiben eines Sektors das erwartete Statusbyte am Ende nicht sofort,
sondern erst beim erneuten Lesen eines Bytes kommt, xmit_datablock()
verlangt das Stausbyte aber sofort. Ich habe daher den Code der Funktion
entsprechend angepaßt, sodaß die auch zufrieden ist und ohne
Fehlermeldung zurückkehrt, wenn das Statusbyte erst beim 2. oder 3. Mal
kommt (in Datei sdmm.c):
constBYTE*buff,// 512 byte data block to be transmitted
7
BYTEtoken// Data/Stop token
8
)
9
{
10
BYTEd[2];
11
12
if(!wait_ready())return0;
13
14
d[0]=token;
15
xmit_mmc(d,1);// Xmit a token
16
if(token!=0xFD)// Is it data token?
17
{
18
xmit_mmc(buff,512);// Xmit the 512 byte data block to MMC
19
rcvr_mmc(d,2);// Xmit dummy CRC (0xFF,0xFF)
20
rcvr_mmc(d,1);// Receive data response
21
if((d[0]&0x1F)==0x05)// If accepted, return with OK
22
return1;
23
rcvr_mmc(d,1);// Receive data response
24
if((d[0]&0x1F)==0x05)// If accepted, return with OK
25
return1;
26
rcvr_mmc(d,1);// Receive data response
27
if((d[0]&0x1F)==0x05)// If accepted, return with OK
28
return1;
29
// if ((d[0] & 0x1F) != 0x05) // If not accepted, return with error
30
// return 0;
31
}
32
33
return0;
34
}
die auskommentierten Zeilen waren ursprünglich im Code, jetzt sind es
stattdessen die 9 Zeilen davor.
Und nach diese Änderung funktionierte auch das Schreiben, Ähnlichen Code
für xmit_datablock() habe ich auch schon in der Library, die hier im
Artikel AVM FAT32 verlinkt ist, vorgefunden, dort wurde auch mehrmals
das Statusbyte gelesen, bis die richtige Antwort kam und erst nach n
vergeblichen Versuchen gab es eine Fehlermeldung.
Vielleicht hilft das auch anderen, evtl. ist meine SPI-Funktion zu
schnell gewesen.
Ob das auch mit schnellerem SPI-Takt funktioniert, werde ich später noch
ausprobieren, eine Umschaltung nach der SD-Initialisierung ist
jedenfalls schon vorbereitet.
Gruß
Andy
@ Andreas W. (andy_w)
>noch nicht. Zunächst stellte ich fest, daß meine SPI-Funktion schon>einen Return machte, bevor die letzten SPI-Takte zudene waren,
Das ist dein Fehler.
>Trotzdem funktionierte das Schreiben nicht. Ich stellte fest, daß beim>Schreiben eines Sektors das erwartete Statusbyte am Ende nicht sofort,>sondern erst beim erneuten Lesen eines Bytes kommt, xmit_datablock()>verlangt das Stausbyte aber sofort. Ich habe daher den Code der Funktion>entsprechend angepaßt,
FALSCH! Finger weg von diesen Funktionen. DIe funtkionieren! Deine
Aufgabe besteht NUR in der Anpassung der aller untersten SPI-Zugriffe!
>Vielleicht hilft das auch anderen, evtl. ist meine SPI-Funktion zu>schnell gewesen.
Nö, du hast garantiert einen Puffer oder was ähnliches bei deinem
SPI-Modul übersehen oder du fragst das falsche Statusbit ab. Oder du
hast vergessen, VOR der Übertragung das Statusbit zu löschen. Bring das
in Ordnung!
Hallo,
das erste gelesene Statusbyte hat immer den Wert 0xff. Das ist aber gar
kein Stausbyte, das hat das Format x,x,x,0,b,b,b,1 (binär). b,b,b kann
010 (no error), 101 (CRC error) oder 110 (data rejected due to write
error) sein. 0xff deutet darauf hin, daß das Statusbyte zu dem Zeitpunkt
noch nicht kommt, sondern erst ein Byte später. Ein Timingproblem ist
das nicht, denn im Debugger, wo vor dem Lesen des Statusbytes beim
händischen Durchsteppen mehrere Sekunden vergehen passiert genau das
gleiche. Da ich an der Funktion sonst nichts geändert habe, ist die Zahl
der Bytes, die davor geschrieben werden, gleich, es kann also nicht ein
gelesenes Byte fehlen.
Hat jemand das auch zusammen mit der SPI-Hardware des Prozessors benutzt
oder nur die Softwarevariante, in der alle Portpins per Software bedient
werden? Wenn ja, würde mich interessieren, welche SPI-Funktionen mit
welchen Parametern aufgerufen werden (müßte irgendwie spi_transmit()
oder so heißen. Meine Funktion wartet, bis genau soviel Transmit
Register empty und Receive Register full abgearbeitet wurden, wie der
Blocklänge der SPI-Übertragung entspricht. Anschließend warte ich noch,
bis das Transmit Register auch gesendet wurde. Was mich wundert: erst
dann kann eigentlich das letzte Byte ins Receive Register geschrieben
werden, warum sind aber schon soviele Receive Register full Medungen
vorher gekommen, da die spi_transmit Funktion schon während der letzten
Clocks sich beendet hatte?
Das Datenblatt des SAM3X8E verrät zu dem Thema keine genaueren Details,
es gibt auch kein Fußdiagramm, wie man so einen Transfer durchziehen
sollte. Die Examples vom Atmelstudio schreiben einfach blind das
Transmit register und warten dann nur auf Receive Register full und
lesen dann das Receive Register, dann wird gleich das nächste Byte
geschrieben usw. Leider ist kaum herauszukriegen, wie SPI vorher
konfiguriert wird, ich brauche ein SPI, das bei mehreren Bytes
lesen/schreiben den CS ununterbrochen auf Low läßt und erst nach dem
letzten Byte auf High geht, sonst funktioniert normale SPI-Hardware
nicht.
Wenn tatsächlich momentan alle Bytes um eine Stelle verspätet gelesen
werden, wundere ich mich aber, warum es trotzdem einwandfrei
funktioniert, zumindest mit der Änderung in xmit_datablock().
Gruß
Andy
Hallo,
die SPI-Beschreibung im Datenblatt vom SAM3X8E ist eine Katastrophe! Es
ist zwar viel dokumentiert, aber die Feinheiten mit den Statusbits,
Kombinationen mit einigen Konfigurationsbits usw. sind nicht erklärt. Es
gibt vor allem kein Flußdiagramm oder einen Beispielcode, wie man z.B.
einen Masterzugriff auf die Beine stellt. So etwas ist auch nicht in den
Application Notes von Atmel zu finden, es gibt überhaupt nur eine, die
den SPI betrifft und da drückt man sich ebenfalls um genau diese
Informationen. Wenn man den SPI-Bus ausreizen möchte, also z.B. für
verschiedene SPI-Hardwareslaves unterschiedliche Settings nutzen muß
(z.B. NCPHA, CPOL und Taktfrequenz individuell), helfen einem die
Atmeltreiber nicht wirklich weiter, da kaum Doku vorhanden ist...
Aber inzwischen habe ich es geschafft, jetzt kommt das Statusbyte in
xmit_datablock() gleich beim ersten Mal. Das war ziemlich nervig zu
finden, da man die SPI-Funktion nicht richtig debuggen kann, denn die
Statusbits werden gepollt und beim Debuggen vergeht einfach zuviel Zeit
zwischen den Befehlen. Schließlich fand ich heraus, daß das Receive
Register full Flag beim Aufruf machmal auf 1 stand, also mußte dann ein
Dummyread erfolgen, ebenso war die Abfrage, wann das nächste Byte
geschrieben und auch gelesen werden kann, anzupassen. So, wie im Example
vom Atmel funktioniert es jedenfalls nicht, das hatte ich auch probiert.
Außerdem funktioniert auch das Hochsetzen des SPI-Taktes nach dem Init
der SD-Karte, bei mir auf 10.5MHz. Dazu mußte ich aber etwas in die
Funktion disk_initialize() eingreifen, am Anfang setze ich eine Variable
spi_fast auf 0 und am Ende auf 1. Die Aufrufe der SPI-Funktionen selber
berücksichtigen dann diese Variable und stellen entsprechend die
Taktfrequenz ein. Das hat seltsamerweise auf Anhieb funktioniert...
Gruß
Andy
> ffopen merkt sich nicht, ob eine Datei zum Lesen oder> zum Schreiben geöffnet wurde. Beim ffclose> wird unterschiedslos dann fflushFileData() aufgerufen.
Ich finde auch, dass das nach einem Bug aussieht.
Allerdings sollte der unnötige Schreibzugriff harmlos sein, denn es wird
der zuletzt gelesene Sektor zurück geschrieben.
Kann es sein, dass du den Inhalt des Buffers unabsichtlich veränderst?
Ich habe hier immer noch den Verdacht, dass du einen Stack-Überlauf
hast.
@ Andreas W. (andy_w)
>die SPI-Beschreibung im Datenblatt vom SAM3X8E ist eine Katastrophe! Es>ist zwar viel dokumentiert, aber die Feinheiten mit den Statusbits,>Kombinationen mit einigen Konfigurationsbits usw. sind nicht erklärt.
Zeig mal das Datenblatt.
Da du augenscheinlich ziemliche Problem mit dem Verständnis und
Inbetriebnahme des SPI hast, solltest du erstmal in einem minimalen
Testprojekt die SPI zum Laufen bringen, vor allem das Warten auf das
echte Ende einer Übertragung. Dazu braucht man ein Oszi oder
Logicanalyzer, mit dem Debugger geht das nicht. Mach es ganz klassisch.
CS low
N Bytes senden
CS high
Wenn alles passt und dir kein FIFO oder falsches Statusbit ins Handwerk
pfuscht, sollte das Signal mit CS und Takt exakt so auf dem
Oszi/Logicanalyzer zu sehen sein.
Hallo,
es läuft doch jetzt, auch mit der ursprünglichen Funktion
xmit_datablock()... Auf dem Oszi sieht es ja jetzt auch einwandfrei aus,
so einen Minimaltest nur mit SPI-Zugriffen ohne kontaktierter SD-Karte
hatte ich auch zum Finden des Fehlers laufen.
Es war tatsächlich noch ein Fehler in der SPI-Funktion selber, der
inzwischen behoben ist. Die Funktion hat sich beim Pollen der Flags
verzählt und ein Byte mehr (zuerst eins weniger) gesendet als gelesen.
Es war eben nur ziemlich mühselig, den Fehler zu finden, da es weder
brauchbare Beispiele (das eine, das ich gefunden hatte, ist definitiv
falsch und lief beim Probieren auch nicht) noch genaue Erklärungen im
Datenblatt gibt. Außerdem war das auch nicht zu debuggen, da es in
Echtzeit ablaufen muß. Die Register sind in der Doku zwar vollständig
beschrieben, die Funktion der einzelnen Bit und Bitfelder aber nur
ziemlich knapp, so daß Fragen offen bleiben. Seltsamerweise hat der
I2C-Bus auf Anhieb richtig funktioniert (da hängen mehrere Slaves dran
und alle lassen sich problemlos ansprechen), obwohl der eigentlich etwas
komplizierter als der SPI-Bus ist.
Der Bug bei der anderen Lib kann durchaus harmlos sein, d.h. es werden
wahrscheinlich identische Daten zurückgeschrieben, wenn man Dateien nur
liest. Aber unnötige Schreibzugriffe kommen besonders bei Flashspeichern
nicht gut an, da die die Lebensdauer verkürzen. Außerdem steigt die
Wahrscheinlichkeit, das Fehler passieren.
Inzwischen läuft die Software jetzt schon seit mehreren Tagen und hat
bzgl. SD-Karte und SPI keine Fehler mehr gezeigt, sogar das Umschalten
auf einen höheren Takt nach dem Init funktioniert einwandfrei.
Gruß
Andy
Hallo,
ich nehm grad auch die elmchan bib in Betrieb, mich würde interessieren
wie schnell du deinen SPI laufen lässt.
Initialisiert werden meine SD KArten mit unter 400kHz, danach ist je
vollgas möglich, begrenzt von den SPI Pin Spezifikationen oder
Bufferschaltungen.
Meine Betriebsgeschwindigkeit ist gerade zum Testen bei 1 MHz, ich habe
aaber auch Kabel dazwischen, also keine direkte PCB-Anbindung, weswegen
eben höhere Kapazitäten auftreten, die die Signale verlangsamen.
Merci.
@ stefan schmitt (mexakin)
>Initialisiert werden meine SD KArten mit unter 400kHz, danach ist je>vollgas möglich, begrenzt von den SPI Pin Spezifikationen oder>Bufferschaltungen.
Normale SD(HC)-Karten verkraften max. 25 MHz.
>Meine Betriebsgeschwindigkeit ist gerade zum Testen bei 1 MHz, ich habe>aaber auch Kabel dazwischen,
Wieviel Meter?
> also keine direkte PCB-Anbindung, weswegen>eben höhere Kapazitäten auftreten, die die Signale verlangsamen.
Ja und? Selbst mit 1m Kabel kommt man da locker auf 10MHz oder mehr.
Allerdings wird dann das Thema Wellenwiderstand relevant.
Mein MSP kann maximal 24 MHz, das habe ich auf Vollgas bezogen ohne es
euch zu schreiben.
Kabel sind 20cm aktuell, sieht bei 12 MHz SPI schon gut nach Dreieck aus
mein Clock, erstaunlicherweise geht es noch anständig, daher wollte ich
mal wissen wie schnell andere ihre SPIs so betreiben, bzw wie andere
Prozessortechniken wie Atmel, PIC das machen.
@ stefan schmitt (mexakin)
>Mein MSP kann maximal 24 MHz,
CPU Takt oder SPI Takt?
>Kabel sind 20cm aktuell,
Genug, um sich ins Knie zu schießen ;-)
> sieht bei 12 MHz SPI schon gut nach Dreieck aus
Wie hast du das gemessen? Mit einem 10:1 Tastkopf und einem halbwegs
schnellen Oszi? (100 MHz++)
>mal wissen wie schnell andere ihre SPIs so betreiben, bzw wie andere>Prozessortechniken wie Atmel, PIC das machen.
Exakt genau so. SPI ist nix weiter als ein Schieberegister.
Prozessortakt sind 24 MHz, SPI akt kann ich also je nach Teiler auch 24
MHz machen.
gemessen an einen 10:1 mit schnellem Oszi.
Und die Schieberegister, sind ja sicherlich von Silizium zu Silizium
leicht anders aufgebaut, daher hätte es mich interessiert, ob da manche
einfach schneller so nen Takt raushauen können, oder ob alle da begrenzt
sind.
@ stefan schmitt (mexakin)
>Prozessortakt sind 24 MHz, SPI akt kann ich also je nach Teiler auch 24>MHz machen.
Sicher?
>gemessen an einen 10:1 mit schnellem Oszi.
Wie schnell?
Poste mal ein Bild.
>Und die Schieberegister, sind ja sicherlich von Silizium zu Silizium>leicht anders aufgebaut,
Unwesentlich.
> daher hätte es mich interessiert, ob da manche>einfach schneller so nen Takt raushauen können, oder ob alle da begrenzt>sind.
Alles auf dieser Welt ist begrenzt. Oder wie es mal ein schlauer Kopf
sehr treffend formulierte.
"Es gibt zwei Dinge, die unendlich sind. Das Universum und die Dummheit
der Menschen. Bei ersten bin ich mir allerdings nicht ganz sicher".
Albert Einstein
Hallo,
bei mir läuft der SPI dann mit 10.5MHz (84MHz/8), höher habe ich noch
nicht probiert. Die SD-Fassung ist mit ca. 7cm langen Leitungen per
Stift-/Buchsenreihe mit der Leiterplatte verbunden, von dort bis zum
Arduino sind es noch einmal ca. 5cm. Momentan hängt die SD-Karte direkt
dran, später kommt ein Buffer (74LVC245) dazwischen, damit ich die
SD-Karte bei anderen SPI-Zugriffen elekrisch abtrennen kann, Konkurrenz
mit anderer SPI-Hardware mögen die nicht. Dann werde ich mal sehen, wie
hoch ich mit der Frequenz gehen kann, 25MHz dürfte dann schon
grenzwertig werden. Das bringt dann aber auch nicht mehr soviel
zusätzliche Geschwindigkeit, da der Overhead zwischen den Zugriffen auf
512Byte Sektoren schon sehr ins Gewicht fällt. Da meine Dateien nicht
sooo groß sind, macht das nicht soviel aus.
Gruß
Andy
@Andreas W. (andy_w)
>dran, später kommt ein Buffer (74LVC245) dazwischen, damit ich die>SD-Karte bei anderen SPI-Zugriffen elekrisch abtrennen kann, Konkurrenz>mit anderer SPI-Hardware mögen die nicht.
Das ist Unsinn. Man muss einfach nur CS auf High setzen, schon ist Ruhe.
Ich habe mehrere Projekte gemacht, wo die SD-Karte als ganz normaler
SPI-Slave am SPI-Bus mit anderen Teilnehmern hing, alles kein Problem.
> Dann werde ich mal sehen, wie>hoch ich mit der Frequenz gehen kann, 25MHz dürfte dann schon>grenzwertig werden.
Warum? Wenn 10 MHz sauber laufen und die Signale gut aussehen spricht
rein gar nichts gegen 25 MHz.