Hallo Allerseits,
ich hab hier schon seit 2 Tagen ein Problem mit einer Micro-SD-Karte.
Die Karte ist von Intenso, 4GB, class 4, nix Besonderes. Das Ganze soll
auf einem selbstentwickelten Board laufen, ATXmega128A1U, alles 3,3V. An
CS, DO und den 2 ungenutzten IOs hängt je ein 10K Pull-Up gegen 3,3V.
Über UART kriege ich meine Debug-Ausgaben. Als Lib habe ich die von ELM
Chan, die hatte ich schon erfolgreich in einem anderen Projekt benutzt,
wenn gleich dort mit einem ATmega64. Also flink die Dateien kopiert, die
Low Level Sachen angepasst, los gehts. Oder auch nicht :-(
Zu Testzwecken öffne ich einfach eine Datei und schreibe dort ein paar
Zeichen rein. Das geht aber leider nicht.
Wenn ich nun mehrfach einen Reset am Controller mache, bekomme ich von
der Funktion f_open() abwechselnd den Fehler
FR_NOT_READY, /* (3) The physical drive cannot work */
oder
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
Den SPI-Bus sehe ich auf meinem Logicanalyzer. Beim Fehler 3 schlägt
schon die elementare Initialisierung mit 200kHz SPI-Takt fehl. Bei
Fehler 13 funktioniert sie, die Lib schaltet auf vollen SPI Takt von 8
MHz um und will dann weiter machen. Dort gibt es scheinbar nur ein
Kommando, das liefert einmal eine 0, dann viele 0xFF. Dann wird ein
Blockzugriff gemacht (sieht man am lückenlosen SPI-Takt), komischerweise
werden dort aber nur ~160 Byte gelesen, wobei ALLE gelesenen Daten 0
sind! Sehr mehrwürdig! Zur Initialisierung des FAT muss doch erstmal der
Bootsektor gelesen werden, das sieht man auch im Code von ff.c. Aber
soweit kommt es scheinbar nicht :-(
Hat irgendjemand eine Idee?
Ich habe schon mal 33 Ohm in die SCK Leitung zur SD-Karte eingelötet,
ich vermutete schlechte Signalflangen, auch wenn das eher
unwahrlscheinlich ist (Die Platine hat 4 Lagen und eine vollständige
Massefläche). 100nF sind auch ca. 5mm von der Karte entfernt an VCC/GND.
Im Anhang mal der SPI-Datenverkehr. Ab 16.52ms geht der High Speed
Verkehr los.
MFG
Falk
Kann es sein, dass es ein Problem mit der CS Leitung gibt und sich die
Karte manchmal garnicht angesprochen fühlt?
Es gibt ja an ein paar Stellen im Code wo er einen Softwaretimer (aus
ISR und Zähler) verwendet. Hast Du das korrekt übernommen oder wird da
vlt. was wegoptimiert? Mal die Optimierung ausgeschaltet?
Musst Du bei Deiner Lowlevel-Implementierung den SPI zwischen 8 und 16
Bit umschalten? (habe jetzt nicht mehr im Kopf ob der XMega 16-Bit SPI
kann). Das hatte bei meiner STM32F0 Anpassung für Probleme gesorgt.
Der Dump (SPI.TXT) sieht 100%ig OK aus, bis der Code den Lesevorgang
abbricht.
Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und
die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00"
bekommtst, ist also normal!
Unter Windoof bekommt man diesen Sektor nur mit Admin-Rechten zu sehen,
viele Tools zeigen Dir nur den 1. Sektor der FAT Partition an, selbst
dann wenn sie Admin Rechte haben.
Das Lesekommando sieht gut aus:
1719843 (17.20ms) MISO:MOSI 0x00 : 0xFF ÿ ; ab hier gibts die Daten
13
...
14
1738970 (17.39ms) MISO:MOSI 0x00 : 0xFF ÿ
Die SD Karte bestätigt das Lesekommando schon nach dem ersten Dummy Byte
mit 0x00 = OK. Dann braucht sie ca. 0.7 ms, bis die Daten zur Verfügung
stehen - es folgt das "Start Data" Token 0xFE. Alles weitere sind die
Daten, die im Auslieferzustand 0x00 enthalten - die Partitionstabelle
beginnt erst ab Byte 446, die Übertragung endet vorher.
Dass es danach abbricht, ist vermutilch ein Fehler im AVR Code. Schau
mal nach den Interrupts - und ob deren Handler existieren - oder dem
Watchdog.
@ Markus M. (adrock)
>Kann es sein, dass es ein Problem mit der CS Leitung gibt und sich die>Karte manchmal garnicht angesprochen fühlt?
Nein, das Signal ist OK.
>Es gibt ja an ein paar Stellen im Code wo er einen Softwaretimer (aus>ISR und Zähler) verwendet. Hast Du das korrekt übernommen
Ja, das habe ich geprüft, mittel Testpin. Der Interrupt läuft und ruft
alle 10ms die Funktion disk_timerproc() auf,
>>vlt. was wegoptimiert? Mal die Optimierung ausgeschaltet?
Geht nicht, ich hab diverse _delay_ms() im Code.
>Musst Du bei Deiner Lowlevel-Implementierung den SPI zwischen 8 und 16>Bit umschalten?
Nein, der ATXmega kann nur 8 Bit. Es wird UARTE1 im SPI-Modus verwendet.
Falk Brunner schrieb:> SPI Takt von 8> MHz
Ne ganz doofe Frage - kann die Micro-SD-Karte so schnell liefern? Da
gibt es doch Geschwindigkeits-Klassen, oder? Der Code wäre auch ganz
interessant :-)
@Jim Meba (turboj)
>Der Dump (SPI.TXT) sieht 100%ig OK aus, bis der Code den Lesevorgang>abbricht.
Eben, SEHR seltsam!
>Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und>die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00">bekommtst, ist also normal!
Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang
an Offset 82, das müsste man sehen. Ausserdem ist dort noch diverses
anderes "Gemüse" Verstreut, das man im HEX-Editor sieht.
>Unter Windoof bekommt man diesen Sektor nur mit Admin-Rechten zu sehen,
Ist bekannt, schaue ich mit als Admin an, mit WinHex.
>Das Lesekommando sieht gut aus:>1652993 (16.53ms) MISO:MOSI 0xFF ÿ : 0x51 Q ; CMD17>1653273 (16.53ms) MISO:MOSI 0xFF ÿ : 0x00 ;
Ja,k hab ich mittlerweile auch bis dahin verfolgt. Dann folgen viele
Polling-Zyklen, bis die Karte mit 0xFE antwortet. Danach wird es
mysteriös. Eigenlich sollte dann DIREKT der Blocklesezugriff folgen,
dabei ist der SPI-Takt lückenlos. Auf dem Logicanalyzer sieht man aber
noch drei Bytes mit Lücken. Das kann nicht sein!
>Die SD Karte bestätigt das Lesekommando schon nach dem ersten Dummy Byte>mit 0x00 = OK. Dann braucht sie ca. 0.7 ms, bis die Daten zur Verfügung>stehen - es folgt das "Start Data" Token 0xFE. Alles weitere sind die>Daten, die im Auslieferzustand 0x00 enthalten
Nein, da seht diverses Zeug drin. Ausserdem hab ich die Karte nochmal
mit Windows formatiert, dort hat das dämliche System einen Bootloader
draufgeschrieben. Warum auch immer. Aber davon sehe ich rein gar nichts
im Datenstrom!
>- die Partitionstabelle>beginnt erst ab Byte 446, die Übertragung endet vorher.>Dass es danach abbricht, ist vermutilch ein Fehler im AVR Code. Schau>mal nach den Interrupts - und ob deren Handler existieren - oder dem>Watchdog.
Es ist nur ein Interrupt aktiv, ein Timer. Der läuft normal. Wenn es
einen Reset geben würde, würde ich das im Terminal sehen
(Debugausschrift nach Reset).
Aus irgend einem Grund, wird diese Funktion nicht korrekt umgesetzt!
Sie wird, da nur einmalig genutzt, per Inline eingefügt.
@ Dieter Frohnapfel (jim_quakenbush)
>> SPI Takt von 8>> MHz>Ne ganz doofe Frage - kann die Micro-SD-Karte so schnell liefern?
Kann sie, weil JEDE SD-Karte 25 MHz Takt verkraftet. Class 4 heißt,
4MB/s (nicht im SPI-Modus, aber mit 4 Bit SDIO).
>gibt es doch Geschwindigkeits-Klassen, oder? Der Code wäre auch ganz>interessant :-)
Nö, der funktioniert ja problemlos auf dem alten Board. Es ist der voM
Meister ELM Chan.
http://elm-chan.org/fsw/ff/00index_e.html
Hier mal der Ausschnit aus dem .lss File. Wenn gleich der Compilier ein
paar Verwürfelungen (Optimierung -Os) macht, ist der Code FAST korrekt.
Aber das einmalig cnt-- wird verschluckt! Oder sehe ich es nicht?
Edit: OK, ich sehe es. Es wird mit 1 verglichen, nicht 0
(Schleifenabbruch)
Dennoch darf der Code nicht nach ~160 Byte abbrechen! Er wird mit 512
Byte = 1 Sektor aufgerufen!
1
00002952 <rcvr_datablock>:
2
static
3
int rcvr_datablock (
4
BYTE *buff, /* Data buffer to store received data */
5
UINT btr /* Byte count (must be multiple of 4) */
6
)
7
{
8
2952: 0f 93 push r16
9
2954: 1f 93 push r17
10
2956: cf 93 push r28
11
2958: df 93 push r29
12
295a: ec 01 movw r28, r24
13
295c: 8b 01 movw r16, r22
14
BYTE token;
15
16
17
Timer1 = 20;
18
295e: 84 e1 ldi r24, 0x14 ; 20
19
2960: 80 93 b9 20 sts 0x20B9, r24
20
do { /* Wait for data packet in timeout of 200ms */
Falk Brunner schrieb:>>Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und>>die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00">>bekommtst, ist also normal!>> Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang> an Offset 82
Quatsch. Das ist ein FAT-Bootsektor. So weit vorne kommt der nur, wenn
die Karte als "Superfloppy" formatiert ist. Ab Werk sind die Dinger aber
normalerweise als HD formatiert, vor der ersten Partition kommt also
mindestens der MBR in der Größe eines Sektors.
Typisch ist sogar, dass ein kompletter "Track" reserviert ist (hier
natürlich nicht wirklich ein Track im Sinne einer Spur einer HD, sondern
oft genau die Größe eines Löschblocks des verbauten Flash [oder
Flashcontrollers???]).
Was übrigens Wixdos macht, ist bei Wechselmedien eh' absolut
grenzwertig. Obwohl darauf lt. aller jeweiligen Standards immer auch
HD-Strukturen zumindest zulässig sind, ist Wixdos nicht in der Lage,
damit korrekt umzugehen. Nur bei "Superfloppy"-Formatierung sieht es
das, was wirklich dort ist. Ansonsten nur die erste Partition. Der
NT-Kernel selber sieht aber natürlich alles korrekt. Deshalb muß man
nicht nur Admin sein, sondern auch noch auf's richtige Devicefile
zugreifen, um selber alles zu sehen...
Lustige Effekte aus dieser schwachsinnigen Trennung in das, was
Microsoft will, was der User sieht und das, was wirklich ist, kann man
erzielen, wenn man in der sog. "Datenträgerverwaltung" mal ein wenig mit
Datenträgern spielt, die eine HD-Struktur mit mehr als einer Partition
aufweisen. Die dabei generierten Fehlermeldungen füllen ein komplettes
Realsatire-Magazin...
Noch extremer und wesentlich weniger lustig wird es, wenn man mit
bootfähigen Windows-Installationen auf solchen Wechseldatenträgern
gezwungenermaßen tatsächlich hantieren muß...
Nö, der (richtig gute) NT-Kernel hat wirklich besseres als den völlig
beschissenen Windows-Aufsatz verdient...
@ c-hater (Gast)
>> Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang>> an Offset 82>Quatsch. Das ist ein FAT-Bootsektor. So weit vorne kommt der nur, wenn>die Karte als "Superfloppy" formatiert ist. Ab Werk sind die Dinger aber>normalerweise als HD formatiert, vor der ersten Partition kommt also>mindestens der MBR in der Größe eines Sektors.
Stimmt, da hatte ich mich wohl vertan.
>aufweisen. Die dabei generierten Fehlermeldungen füllen ein komplettes>Realsatire-Magazin...
Wenn das mal nicht die Männer mit der Kalaschnikov hören . . .
OK,, es geht voran!
Es war noch ein Fehler in den IO-Funktionen. Der UART im SPI-Modus ist
halt doch ein wenig anders als das normale SPI-Modul, vor allem die
FIFOs machen da ein wenig Stress, wenn man nicht aufpasst.
Mit diesen Funktionen kann ich schon mal Dateien lesen!!!
Aber beim Schreiben geht noch was schief!. Öffnen zum Schreibzugriff
geht, aber bei f_write() kommt eine Rückgabewert von 1 (FR_DISK_ERR,
/* (1) A hard error occurred in the low level disk I/O layer */) zurück,
die Anzahl geschriebener Bytes ist auch Null. Dumm nur, dass dieser
Fehler an ziemlich vielen Stellen der Funktion zurückgegeben werden
kann. Einen In Circuit Debugger hab ich auch nicht, nur das gute, alte
AVR ISP MK II 8-0
Ich habe eine defekte Micro-SD-Karte, die mich unter Linux und einen
MP3-Player zur Verzweifelung gebracht hat. Lesen ist noch möglich. Beim
Schreiben tut das Betriebssystem so als ob. Danach ist der alte Inhalt
der Micro-SD-Karte wieder sichtbar.
Nicht das es an einer defekten SD-Karte liegt,. ;-)
@ noreply@noreply.com (Gast)
>Nicht das es an einer defekten SD-Karte liegt,. ;-)
Nein, die ist OK, hab ich gerade probiert. Man kann neue Dateien anlegen
und lesen. Ausserdem habe ich es auch mit einer anderen SD-Karte
probiert, gleiches Ergebnis. Der Dateiname wird angelegt, der inhalt
aber nicht geschrieben :-(
Soweit ich es im Moment eingrenzen kann, scheint die Zuweisung des neuen
(ersten) Clusters für die Datei schief zu gehen! Wie kann das sein? Die
Karte ist nahezu leer!
Also, das Problem ist im Moment, dass bei f_open() KEIN Fehler zurück
kommt, die Datei wird auch im Hauptverzeichnis angelegt (kann man am PC
sehen), aber der Schreibvorgang f_write() bricht ab, weil scheinbar kein
Cluster für die Datei verfügbar ist. Sehr merkwürdig.
Ich hab mir mal das ATMELICE bestellt, ich hoffe der Debugger wirft
deutlich schneller Licht auf die Sache als meine print_f Orgie.
So, mittels ATMELICE hab ich mich jetzt weiter zum Problem durchgewühlt.
Wie es scheint, gibt es ein Problem beim Schreiben der FAT auf die
SD-Karte. Wenn mittels CMD24 der FAT-Sektor 0 zurüchgeschieben werden
soll, kommt als Anwort der Karte 0xFF, machmal auch 0,1F, wo aber 0x05
erwartet wird. Scheibenhonig!
Merkwürdig ist, dass das Directory mit dem erstellten Eintrag der neuen
Datei aber beschrieben wird! Häää??
Allerdings sind die Signale auf dem Logicanalyzer nicht ganz plausibel.
Am Ende der Übertragung werden 2x 0xFF als Dummybytes für die CRC
gesendet, danach nochmal 0xFF um die Antwort der SD-Karte zu bekommen.
Aber diese Einzelsendungen müssten auch zeitlich etwas mit Abstand
erkennbar sein. Sind sie aber nicht! Der SPI-Takt ist lückenlos und hört
dann auf! Mysteriös!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHH
Ich Depp!
Ich hab den Fehler gefunden! Er lag natürlich mal wieder vor der
Tastatur!
"Also flink die Dateien kopiert, die Low Level Sachen angepasst, los
gehts. Oder auch nicht :-("
Denkste! Bei der Schreibroutine hab ich mir, wie bereits bei der
Empfangsroutione sauber ins Knie geschossen! Und warum?
Wegen des FIFOs!! (Genitiv ins Wasser weil Dativ)
Beitrag "Re: Problem mit Micro-SD-Karte"
Ich dachte, lösch doch einfach das TXC Flag vor der Übertragung, die
leiert dann schön durch und am Ende wird TXC gesetzt. FALSCH! TXC wird
ZWISCHENDURCH gesetzt! Warum? Weil die Übertragung des Datenblocks durch
Interrupts unterbrochen wird, dadurch läuft der FIFO zwischenzeitlich
leer. Jaja, man hätte DMA nehmen können, die bringt hier aber wenig,
weil die CPU sowieso warten muss. Ok, also muss man TXC am ENDE der
Übertragung VOR dem Senden des letzten Bytes löschen und zwar ATOMAR!
Warum? Wenn zwischen das Löschen von TXC und das Senden des letzten
Bytes ein Interrupt dazwischenfunkt, wird TXC gelöscht (von vorherigen
Sendepausen), die aktuelle Übertragung mit vollem FIFO läuft noch, die
ISR blockiert das Laden des letzten Bytes, der FIFO läuft leer und setzt
TXC wieder! Nach der Rückkehr der ISR wird das letzte Byte gesendet, die
Warteschleife geht aber sofort weiter, weil TXC ja gesetzt ist! Damit
holt man sich Probleme im weiteren Ablauf der FAT-Lib! Denn die macht
danach noch Einzelübertragungen. Die funktionieren aber nur, wenn die
vorherige Blockübertragung VOLLSTÄNDIG abgeschlossen ist!
OMG! Das hat mich jetzt $("§&$%")!!! Tage gekostet!!!
SCHEIIIIIIIIBENHONG!!!
Damit sich die Nachwelt diesen Krampf erspart, hier die Routinen, die
sollten jetzt WIRKLICH passen. Einzufügen in mmc.c
1
// oben einfügen
2
#include<util/atomic.h>
3
4
/* Exchange a byte */
5
static
6
BYTExchg_spi(/* Returns received data */
7
BYTEdat/* Data to be sent */
8
)
9
{
10
USARTE1.DATA;// clear old data
11
USARTE1.DATA;
12
USARTE1.DATA;
13
14
USARTE1.DATA=dat;
15
while(!(USARTE1.STATUS&USART_RXCIF_bm));
16
returnUSARTE1.DATA;
17
}
18
19
/* Send a data block fast */
20
static
21
voidxmit_spi_multi(
22
constBYTE*p,/* Data block to be sent */
23
UINTcnt/* Size of data block */
24
)
25
{
26
BYTEtmp;
27
28
cnt--;
29
for(;cnt>0;cnt--){
30
tmp=*p++;
31
while(!(USARTE1.STATUS&USART_DREIF_bm));
32
USARTE1.DATA=tmp;
33
}
34
35
// special handling of last byte due to FIFO
36
// and interrupts, which can set TXCIF in between a transfer!
Kleine Ergänzung. So ist es besser in xmit_spi_multi.
1
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
2
USARTE1.DATA=tmp;
3
USARTE1.STATUS=USART_TXCIF_bm;// clear TXC
4
}
Denn damit ist ABSOLUT sicher, dass TXC gelöscht wird. Denn theoretisch
besteht die Möglichkeit, dass zwischen dem Schreibzugriff auf .STATUS
und .DATA das TXC Flag schon wieder gesetzt ist, auch wenn dort nur
wenige Takte dazwischen liegen.
Aber was passiert nun, wenn zwischen dem Daten schreiben und dem
TXC-Flag löschen ein Interrupt auftritt, der länger als die Bytelaufzeit
ist? Dann löschst Du ein frisch gesetztes TXC-Flag und das wird dann nie
wieder gesetzt. Ich denke vorher war´s besser.
@ Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
>Aber was passiert nun, wenn zwischen dem Daten schreiben und dem>TXC-Flag löschen ein Interrupt auftritt, der länger als die Bytelaufzeit>ist?
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
}
> Dann löschst Du ein frisch gesetztes TXC-Flag und das wird dann nie>wieder gesetzt. Ich denke vorher war´s besser.
Nö.
Ein kleiner Tip der sich bei mir bewaehrt hat:
So frueh wie moeglich auch fuer den SPI-Modus die CRC-Datensicherung
einschalten und danach dann alles mit Pruefsummen uebertragen und
auswerten. Das macht den Coder erheblich robuster gegen Probleme aller
Art.
Olaf