Moin,
leider konnten mir die vorhanden Threads nicht helfen.
Und zwar möchte ich ( wie so viele andere ) eine SD Karte betreiben.
Ich benutze dazu einen Spartan 6 inkl. Microblaze Core und SPI
interface.
Soweit scheint auch alles zu funktionieren, nur bei der initialisierung
hakt es.
Ich betreibe eine SD V2.0 Karte von SanDisk mit 2GB Kapazität und mein
Programm ist nur für diese aufgelegt.
Auch fahre ich das Ganze direkt mit 2,5Mhz, da meines Wissens nur die
MMC Karte eine 400Khz-Initialisierung benötigt.
Ich haben mich an den Code von einigen Vorgänger orientiert, also nicht
wundern.
Folgende Fehlermeldung erhalte ich in meinem Terminal.
1
startingSDinitialization
2
SDCardHardwareinitialized.
3
GoIDLEmode...
4
cardresponse:0x1
5
CardisinIDLEmode
6
leaveIDLEmode
7
cardresponse:0xfc
8
cardresponse:0xe1
9
cardresponse:0xe1
10
cardresponse:0xe1
11
...
12
Error:carddidn'tleftidlemode
Zur info:
"leave IDLE mode" ist ein CMD55 + ACMD41 ohne HCS bit.
Zum besseren Verständnis poste ich Euch nochmal die ini.c
(nicht wundern, ist gerade eine Baustelle und einiges auskommentiert)
1
Xuint8sd_init(void)
2
{
3
intStat;
4
intj;
5
intn;
6
Xuint8Card_Response;
7
Xuint8ocr[4];
8
intcount;
9
10
spi_init();// init for SPI XPS Core
11
12
delay(500);// wait some time after PowerUP
13
14
sd_send_cmd_no_cs();// send 8 clock sets for sd card
Card_Response=sd_send_cmd(ACMD41,0x00,0x00,0x00,0x00);// no need SD HC support
45
printf("card response : 0x%x \n",Card_Response);
46
if(!(--count)|!Card_Response)
47
{
48
if(!Card_Response)
49
{
50
printf("card left idle mode\n");
51
Card_Response=sd_send_cmd(CMD16,0x00,0x00,0x02,0x00);// force block size to 512bytes for FAT
52
Stat=1;// identifier for correct sd_init
53
returnStat;
54
55
}
56
else
57
{
58
Stat=3;
59
returnStat;
60
}
61
62
}
63
}
64
//}
65
//}
66
67
}
68
else{j--;}
69
70
}
71
while(j>0);
72
73
Stat=2;
74
returnStat;
75
76
}// end sd_init
Beim debuggen erhalte ich von CMD55 : 5 als response (?!)
und von ACMD : 225 oder dergleichen.
Die Frage ist nun, mache ich was im Initialisierungsflow etwas falsch
oder könnte es an meinen low lvl treibern liegen, also spi_read &
spi_send_byte.
Gruss !
> Auch fahre ich das Ganze direkt mit 2,5Mhz, da meines Wissens nur die> MMC Karte eine 400Khz-Initialisierung benötigt.
Das ist falsch. Auch eine SD-Karte kann nur 400kHz bei der
Initialisierung, wenn ich die Spec hier korrekt interpretiere - "Bus
timing is identical to SD mode" - im SD-Modus steht was von 400 kHz bei
der Initialisierungsphase.
@ Tomas, danke ich werd da direkt mal rübergucken und abgleichen.
@ Jim , bist du dir wirklich sicher? Es gibt viele Posts die das
bestätigen und viele die das verneinen :) z.B. siehe Anhang Seite 3/10
recht Spalte.
Darüber hinaus hat einer mal im Forum auch diese Frage gepostet, ob das
bei SD überhaupt Pflicht ist und da kam auch die Antwort, dass es nur
bei MMC der Fall ist.
Ich selber weiß nun ehrlich gesagt nichtmehr so ganz was denn nun
angesagt ist.
Wegen meinem Problem:
Kann es sein, dass bevor ich ACMD41 senden kann ein CMD8 erfolgen muss?
Quelle:
"But if you do not send CMD8, ACMD41 is still closed - no response."
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=50889&start=0
"Until the end of Card Identification Mode the host shall remain at fOD
frequency because some cards may have operating frequency restrictions
during the card identification mode."
So steht's in den Specs, hängt wohl letzten Endes von der Karte ab.
Soweit ich das weiß, muss bei Karten ab Spec2.0 ein CMD8 gesendet
werden, damit die Karte 'weiß', dass der Host zumindest versucht ihr die
passende Spannung zu geben.
Mark
Hi Mark,
Danke dir.
Folgenden Terminalausdruck habe ich mir noch ausgeben lassen:
1
startingSDinitialization
2
3
SDCardHardwareinitialized.
4
5
GoIDLEmode...
6
7
cardresponseCMD0:0x1
8
9
CardisinIDLEmode
10
11
leaveIDLEmode
12
13
cardresponseCMD55:0xf0
14
15
cardresponseACMD41:0xfc
16
17
cardresponseCMD55:0x5
18
19
cardresponseACMD41:0xe1
20
21
...bistimeout
Was mich ein wenig stutzig macht, ist der erste response vom CMD55.
Kann es angehen, dass der Pegel der MISO Leitung von 0xFF auf low geht
und der Response quasi der Übergang ist? danach kommt 0x05 also illegal
command, was die Theorie des fehlenden CMD8 unterstützt :).
EDIT:
Habe das gerade in der Spezifikation gefunden:
It is mandatory for the host compliant to Physical Spec Version 2.00
to send CMD8 before ACMD41.
Also:
() CS High
() Dummyclocks
() CMD 0 -> response : 1 --> IDLE MODE
() CMD 8 -> response : 1 -> Trailerbit [2] & [3] == 0x1AA ? --> passt
while response ACMD41 == 1
() CMD55 -> response : "ignored"
() ACMD41-> response : 0 --> left IDLE MODE
() CMD16 mit 0x00000200 als Trailer für 512 block size (FAT)
fertig?
Ich warte bei CMD8(bzw. überall), bis bei der Antwort das MSB=0 ist,
erst dann kommt eine korrekte (R7-)Response.
Um die Korrektheit der Übertragung sicher zu stellen, gibt's da die
Möglichkeit mit dem Check-Pattern (meist 0xAA). Ich fand's immer
hilfreich, mir die gesamte Antwort auszugeben und das Check-Pattern zu
überprüfen. Stimmt das auch mit geändertem Wert, ist die SPI-Ansteuerung
prinzipiell in Ordnung.
Mark
D.h. ich schicke nach einem Command mittels der spi_read_byte funktion
noch solange dummy daten heraus, bis ich ein response erhalte was =/= 0
ist.
Siehe Scope Bild.
Oben die MOSI Leitung
in der Mitte die CLK
Unten ist die MISO Leitung.
Nach einem Dummysend (nach dem CRC) erfolgt 0xC1 auf der MISO - Leitung.
Wie meinst du das mit dem Checkpattern?
GrusS !
Gruss !
Und irgendwie verschiebt sich das Ganze nur.
Der erste Response ist immer noch 0xC1.
Das Skopebild zeigt CMD0 mit dieser "read" Funktion.
Scheint alles zu funktionieren..
Christian F. schrieb:> ... bis ich ein response erhalte was =/= 0> ist.
Im Code steht aber !=0xFF ;-). Ist aber falsch für das Response-Byte,
dass ist immer nur gültig, wenn das MSB=0 ist. MSB=1 heißt, Karte ist
beschäftigt, Rest der Bits nutzlos.
1
if(return&0x80==0)
wäre vielleicht passender. Die Routine sieht aber eh' so aus, als wäre
sie nur für R1 geeignet. Wie empfängst du die Bytes einer R7-Response??
Das Check-Pattern ist Teil von CMD8 (Byte vor CRC) und wird unverändert
in der R7-Response zurückgesendet. Die 'vorgefertigten' Commands in
Beschreibungen haben hier meist 0xAA und die passende CRC dafür. Hat
einfach den Zweck, die Kommunikation zu überprüfen. Kommt das Pattern
korrekt zurück funktioniert der Austausch Befehl zu Antwort zumindest
und Probleme liegen woanders. Kommt das Pattern nicht korrekt zurück,
gibt's ein Problem mit Command-senden und Response-empfangen.
Mark
Ohne spammen zu wollen, hier nochmal der Ausdruck des Skopes bei dem ich
solange Dummybytes sende bis die response ein MSB von [0] aufweist.
Damit verschiebe ich dennoch nur das Problem, denn wie zu erkennen ist
ist nach einem Dummysend der erste Response immer noch 0xC1.
Gruss !
EDIT:
jetzt erst deine Antwort gelesen.
Ich habe den Code geändert auf
1
// SPI_MSB_MASK == 0x80
2
if((Return&SPI_MSB_Mask)==0)
3
{
4
returnReturn;
5
}
s.o. :)
Und der Ablauf des CMD8 (Ausschnitt aus dem Code oben, nur mittlerweile
leicht abgeändert):
ocr[n]=spi_read_byte();// Get trailing return value of R7 resp
9
10
}
11
spi_SlaveDeselect();
12
if(ocr[2]==0x01&&ocr[3]==0xAA)// The card can work at vdd range of 2.7-3.6V
13
{
d.h. ich sende solange dummybtes bis MSB == 0 ist.
Dann springe ich in die for schleife.
-> setze CS low (nach einem CMD senden und erfolgreichem receive ist
CS->HIGH)
nun schick ich wieder dummydaten und empfange dann byte per byte des R7.
Allerdings fällt mir gerade ein das ich bei der spi read funktion auch
auf MSB == 0 polle und das ist ja bei dem R7 response evtl. nicht immer
der Fall z.B bei dem 0xAA byte.
Nevermind, denn bis dahin komme ich ja garnicht, da Response CMD8 == 1
schon nicht erfolgt.
Christian F. schrieb:> Der erste Response ist immer noch 0xC1.
Du gibst der Karte ja auch nur 8(!) Versuche. Für einen Timeout
vielleicht ein Wenig knapp. Deine For-Schleife läuft so ab: Versuch 8x
eine gültige Antwort zu bekommen sonst nimm, was grad da ist. Und das
ist dann halt 0xC1.
Vielleicht lässt du für die ersten Versuche mal alles solange warten,
bis eine gültige Antwort mit MSB=0 kommt ohne Abbruch, den siehst du ja,
wenn nix kommt.
Mark
Hi Mark,
Ja das stimmt. Allerdings frage ich mich wieso beim CMD0 es nach 1x
Dummybyte senden mit Dummyresponse, sofort die richtige Antwort kommt (
siehe Skopebild 1 ).
Und die Karte reagiert ja nach/mit dem zweiten Dummybyte.
Im übrigen hatte ich das eben gerade versucht :).
Ich habe den Erwartungswert 0x01 vorgegeben und dann
1
while(response!=Erwartet)
2
{
3
response=spi_read_byte;
4
}
nach 20sek kam immer noch nichts.
Von der Sache her kann ich doch so vorgehen:
() send CMD8
() nun gucke ich mir das erste Byte an
() wenn das 0x01 ist, lese ich den Trailer(R7) aus und schaue ob a) der
Voltagebereich stimmt und b) das Checkpattern von 0xAA.
() dann weiter im Text.
Wie gesagt, ich erhalte kein R1 als erstes Byte des CMD8 responses.
Gruss
Er schickt CMD1, will aus dem IDLE Mode also raus. Dennoch erhält er den
gleichen komischen Fehler:
CMD0 funktiniert einwandfrei
alles andere mit Fehlern.
Gruss
Das ist das blöde an Foren, dass sich die Antworten überschneiden
(passiert gerade wieder ;-)
Wo ist die (korrekte) CRC bei CMD8???
0x48, 0x00, 0x00, 0x01, 0xAA, 0x87 ist das vollständige CMD8 (mit
Check-Pattern 0xAA). Dein Code verwendet hier auch 0x95, das gibt immer
einen CRC-Fehler zurück, also 0x09, nicht 0x01.
Das MSB=0 gilt immer für die gesamte antwort, nicht für jedes Byte. Bei
R7 musst du nur warten, bis ein Byte mit MSB=0 ankommt dann den Rest
'blind' empfangen.
Christian F. schrieb:> Und die Karte reagiert ja nach/mit dem zweiten Dummybyte.
Das Busy-Flag hat schon seinen Sinn. Je nach Karte und je nach Befehl
werden andere Zeiten benötigt.
Zur (aktuell) letzten Antwort von dir:
müsste die CRC sein, daher kein 0x01 (s.o.)
R1 ist ja nur das Datenformat des ersten Antwortbytes bei den meisten
Commands, alles unter 0x80 ist gültig, auch wenn's eine Fehlermeldung
ist.
SD-V1-Karten erkennt man bspw. am 'illegal command' bei CMD8(R1=0x05),
muss man nur ggf. berücksichtigen und trotz 'Fehler' weitermachen.
Auf mich hat das erstmal etwas chaotisch gewirkt. Mal ist etwas ein
Fehler, mal ein Hinweis auf eine Version.
Grüße
ALSO.
Es scheint zu gehen :-).
Es lag wirklich daran, dass ich nachdem die Karte in IDLE Mode gegangen
ist sofort angefangen habe den nächsten CMD zu schicken. In diesem Fall
CMD8.
Die Karte möchte jedoch erstmal ein paar dummybytes haben.
Ich habe nun nachdem er im IDLE Mode gelandet ist 10x Dummybytes
gesendet und DANN erst den CMD8 Command.
Er antwortet mit 0x01, sodass ich den Trailer(R7) auswerten kann.
Anbei das Scopebild.
Gruss !
EDIT:
jetzt wieder erst deine Antwort gelesen :-/.
Also die CRC war 0x87.
Code:
Tja geht das Eine, meckert das Andere herum :).
Jedenfalls ist der Trailer vom CMD8 response = 0x1 sowie 0xAA.
Danach möchte ich jedoch den IDLE Mode verlassen.
Allerdings "spuckt" die Karte dann nicht 0x01 aus und das solange bis
0x00 steht sondern:
1
startingSDinitialization
2
SDCardHardwareinitialized.
3
GoIDLEmode...
4
cardresponseCMD0:0x1
5
CardisinIDLEmode
6
cardresponseCMD8Byte1/5:0x1
7
cardresponseCMD8Byte4/5:0x1
8
cardresponseCMD8Byte5/5:0xaa
9
leaveIDLEmode
10
cardresponseCMD55:0x5f
11
cardresponseACMD41:0x5
12
cardresponseCMD55:0x5f
13
cardresponseACMD41:0x5
14
cardresponseCMD55:0x5f
15
...// 50x versuchen
16
Error:carddidn'tleftidlemode
Mit dem CMD1:
1
startingSDinitialization
2
SDCardHardwareinitialized.
3
GoIDLEmode...
4
cardresponseCMD0:0x1
5
CardisinIDLEmode
6
cardresponseCMD8Byte1/5:0x1
7
cardresponseCMD8Byte4/5:0x1
8
cardresponseCMD8Byte5/5:0xaa
9
leaveIDLEmode
10
cardresponseCMD1:0x7f
11
cardresponseCMD1:0x1
12
cardresponseCMD1:0x1
13
cardresponseCMD1:0x1
14
cardresponseCMD1:0x0
15
cardleftidlemode
16
cardresponseCMD16:0x0
17
sd_initcomplete
Macht das eigentlich sinn vor jedem command einmal dummy bytes zu
schicken?
Ich merke gerade, dass es sich positiv auswirkt.
Gruss
Dennoch mal eine Frage in die Runde.
Habt ihr in euer Realisierung das ebenfalls so gemacht?
Ich habe das nun runtergebrochen und sobald ich vor dem Command ein
Dummybyte sende funktioniert es.
Ohne Dummybyte, keine Chance. Woran liegt das?
Hier der Codeschnipsel :
Hab' bei mir mal nachgesehen, ich sende nach jedem Command ein Dummybyte
mit CS=high. Funktioniert auch.
Grundsätzlich ist die Logik in der Karte fest verdrahtet und benötigt
das Clocksignal um intern zu schalten.