Moin leute. Eigentlich viel zu schönes Wetter um sich mit bockigen SD-Karten rumzuschlagen ^^. Aber naja. Meine Aufgabe besteht immo darin, eine SD-Karte an einen AT89C51RE2 per SPI anzubinden. An sich scheint das auch in gewisser Weise zu funktionieren. Aber ich bin grad bei einem Punkt wo ich einfach nicht weiterkomme. Der SPI-Bus des AT89C51RE2 läuft mit dem kleinsten einstellbaren Takt. Cpol und CPha sind jeweils auf 1 gesetzt. Mein Problem liegt in der Initialisierung der Karte. Laut des "Simplyfied_physical_layer_spec.pdf" von Sun, soll man zuerst ein CMD0 senden und auf die Antwort von R1 warten welches idealerweise ein 0x01 beinhaltet. Vorher hab ich 10x 0xff gesendet damit die Karte 80 Takte bekommt. Dann schick ich ein CMD8 mit dem Parameter 0x1AA (Spannungsbereichsgedöns usw). Als Antwort erhalte ich im 1. und 2. Byte des OCR-registers ein 0x01 bzw ein 0xAA. (Also so wies sein soll). Weil ja die Antworten von der SD_Karte (zumindest bei den ersten zwei Komandos) richtig ankommen, geh ich davon aus das die Kommunikation per SPI an sich funktioniert. So. Jetzt soll man laut dem oben genannten PDF ja ein ACMD41 senden. Ich geh also hin und schicke zuerst ein CMD55 und dann ein ACMD41. Dieses ACMD41 gibt mir nun Rätsel auf. CMD55 gibt ein 0x01 zurück. (In idle mode =1). ACMD41 hab ich einmal mit HCS-Bit und einmal ohne versucht. Mit dem 30. bit gesetzt erhalte ich die Antwort 0xe1. D.h. alle Error-flags gesetzt und immer ncoh im idle. (Was mich wundert ist, das sogar das MSB auf 1 is, was laut PDF immer 0 sein soll ^^) Schick ich aber ACMD41 mit allen Bits auf 0, bekomm ich ein 0xe0 zurück und bei dem nächsten, vom SPI-Master, gesendeten 0xff ein 0x7f. HÄÄÄ? ^^ An sich soll man ja so oft CMD55 + ACMD41 senden, bis irgendwann dieses idle-flag auf 0 ist. Nur passiert das bei mir auch nach 10000 durchläufen nicht. Irgendwas stimmt da nicht. Ich bin echt langsam ratlos. Ich hab auch schon die anderen Beiträge im Forum gelesen, aber das hat mir nciht geholfen. Aso. Ich benutze eine etwas meinem µC angepasste Form der PetitFS-Bibliothek von ELM. Wenn ich den CPOL und CPHA auf 0 setze, bekomm ich manchmal seltsamme Daten vond er SD-karte zurück. Meine Pegelwandlung von 5V auf die 3,3 der karte hab ich mit einem schnellen Komperator realisiert. Die Signale sehen auf beiden Seiten gut aus (gemessen mit dem Oszi). Also da erwarte ich eher weniger Probleme. Ich wär für eine Idee oder ein Tip echt dankbar. Mir geht die SD-Karten-geschichte langsam auf die nerven. Aso ich hab hier 3 verschiedene SD-Karten liegen. Alle 3 funktionieren am PC ohne probleme.
So hab mich mal angemeldet. Ich hab jetzt noch vor dem ACMD41 ein CMD58 (Antwort des Befehls 0x01) gesendet (Wie im PDF angegeben). Aus der Antwort (OCR-Register) bekomm ich folgendes: 0x80 0xff 0x80 0x00. Laut PDF heißt das, dass die "Power-Up Routine" fertig is und die Karte alle Spannungsbereiche unterstützt. Auch diese Antwort erscheint mir sinnvoll. Das Problem mit dem CMD55 und ACMD41 bleibt aber weiterhin bestehen.
So ich hab das Ding ma an ein Oszi gestöpselt. Zur Erklärung: Das oberste Signal ist die CS-Leitung. Das zweite Signal ist die Taktleitung vom SPI-Bus. Das dritte Signal ist Mosi (also was der µC sendet) und das vierte Signal ist das was die SD-Karte zurückschickt. Im 1. Bild (LeCroy1.jpg) sieht man CMD0 mit entsprechenden Antworten Im 2. Bild (LeCroy3.jpg) sieht man CMD58 mit entsprechender Antwort der SD-karte. Im 3. Bild (LeCroy2.jpg) sieht man nun den Gulasch den die SD-Karte bei CMD55 und ACMD41 zurückschickt. Auf CMD55 antwortet die SD-Karte noch mit einem sinnvollen Byte (0x01). Man sieht das nach dem ACMD41 die SD-Karte ein 0xE0 und dann ein 0xBF zurückschickt. Was soll dasn mit diesem 0xE0?
Nach ein wenig Suchen bin ich nun auf die Frage gestoßen welches jetzt der Richtige ACMD41-Befehl ist? ist ACMD41 = 0x69 0x00 0x00 0x00 0x00 0x01 ? oder ist ACMD41 = 0xe9 0x00 0x00 0x00 0x00 0x01 ? dieses 0xe9 hab ich aus der PetitFat-Bibliothek und das 0x69 hab ich hier im Forum irgendwo gelesen. Kann es sein das da der Fehler liegt? Werde das Morgen mal testen.
ACMD41 ist 0x69. So steht es auch in der simplified sd specification drin. Ich poste dir mal meine Init Routine, womit ich bisher problemlos alle SD Karten initialisieren konnte (sd v1, sd v2, sdhc v2). Diese ist für einen LPC935 (8051er Familie) geschrieben.
1 | // SD-Karte initialisieren
|
2 | unsigned char uc_SD_init() { |
3 | unsigned char ucTemp; |
4 | unsigned int uiTimeout = 0; |
5 | unsigned char aucCmd[6]; |
6 | bit btError; |
7 | |
8 | aucCmd[0] = CMD0_GO_IDLE_STATE; |
9 | aucCmd[1] = 0x00; |
10 | aucCmd[2] = 0x00; |
11 | aucCmd[3] = 0x00; |
12 | aucCmd[4] = 0x00; |
13 | aucCmd[5] = 0x95; |
14 | |
15 | // Initialisiere SD-Karte in den SPI-Mode
|
16 | // Sendet min 74+ Clocks an die SD-Karte
|
17 | for (ucTemp = 0;ucTemp < 15; ucTemp++) |
18 | v_SD_Write_Byte(0xFF); |
19 | |
20 | // Sendet Kommando CMD0 an SD-Karte um Reset auszulösen
|
21 | btError = bt_SD_Write_Command(1, aucCmd, 1); |
22 | if (btError == SD_ERROR) |
23 | // Die SD-Karte antwortet nicht
|
24 | return (SD_ERROR_NO_ANSWER); |
25 | else if (aucCmd[0] != 1) |
26 | // Irgend ein Fehler aufgetreten
|
27 | return (SD_ERROR_CMD0); |
28 | |
29 | // Sendet Kommando CMD8 an SD-Karte um Spezifikation zu ermitteln. (CRC benötigt)
|
30 | aucCmd[0] = CMD8_SEND_IF_COND; |
31 | aucCmd[1] = 0x00; |
32 | aucCmd[2] = 0x00; |
33 | // VHS = 0001 (2,7V - 3,6V)
|
34 | aucCmd[3] = 0x01; |
35 | // Check Pattern = 10101010
|
36 | aucCmd[4] = 0xAA; |
37 | // CRC = 1000011 (0x43)
|
38 | // Danach folgt noch eine 1 als Stopbit wodurch 10000111 (0x87) zustandekommt
|
39 | aucCmd[5] = 0x87; |
40 | |
41 | // Auf CMD8 kommt eine R7 Antwort wenn SD Spezifikation v2 ansonsten nur eine R1 Antwort
|
42 | btError = bt_SD_Write_Command(1, aucCmd, 5); |
43 | if (btError == SD_ERROR) |
44 | // Die SD-Karte antwortet nicht
|
45 | return (SD_ERROR_CMD8); |
46 | else if (aucCmd[0] == 5) |
47 | // Unbekannter Befehl, also SD_Karte v1 (Idle-State Bit ist dabei noch gesetzt)
|
48 | btSD_V2 = 0; |
49 | else if (aucCmd[0] == 1) |
50 | // Alles ok, also SD-Karte v2 (Idle-State Bit ist dabei noch gesetzt)
|
51 | btSD_V2 = 1; |
52 | else
|
53 | // Irgend ein Fehler aufgetreten
|
54 | return (SD_ERROR_CMD8); |
55 | |
56 | aucCmd[0] = 0xFF; |
57 | |
58 | if (!btSD_V2) { |
59 | // Weitere Initialisierung für SD-Karte v1
|
60 | |
61 | while (aucCmd[0] != 0 && uiTimeout < 10000) { |
62 | // Sendet Kommando CMD55 an SD-Karte um ACMD einzuleiten
|
63 | aucCmd[0] = CMD55_APP_CMD; |
64 | aucCmd[1] = 0x00; |
65 | aucCmd[2] = 0x00; |
66 | aucCmd[3] = 0x00; |
67 | aucCmd[4] = 0x00; |
68 | aucCmd[5] = 0xFF; |
69 | btError = bt_SD_Write_Command(1, aucCmd, 1); |
70 | if (btError == SD_ERROR || aucCmd[0] != 1) |
71 | // Irgend ein Fehler aufgetreten
|
72 | return (SD_ERROR_CMD55); |
73 | |
74 | // Sendet Kommando ACMD41 an SD-Karte
|
75 | aucCmd[0] = ACMD41_SD_SEND_OP_CMD; |
76 | aucCmd[1] = 0x00; |
77 | aucCmd[2] = 0x00; |
78 | aucCmd[3] = 0x00; |
79 | aucCmd[4] = 0x00; |
80 | aucCmd[5] = 0xFF; |
81 | btError = bt_SD_Write_Command(1, aucCmd, 1); |
82 | if (btError == SD_ERROR || (aucCmd[0] & 0xFE) != 0) |
83 | // Irgend ein Fehler aufgetreten
|
84 | return (SD_ERROR_ACMD41); |
85 | |
86 | // Kurz warten
|
87 | v_Sleep_RTC(RTC_RELOAD_5MS); |
88 | |
89 | // Timeout Zähler erhöhen
|
90 | uiTimeout++; |
91 | }
|
92 | }
|
93 | else { |
94 | // Weitere Initialisierung für SD-Karte v2
|
95 | |
96 | // VHS auslesen
|
97 | if ((aucCmd[3] & 0x0f) != 1) |
98 | // VHS Wert ist ungültig
|
99 | return (SD_ERROR_CMD8_VHS); |
100 | // Check Pattern auslesen
|
101 | if (aucCmd[4] != 0xAA) |
102 | // Check Pattern wurde nicht korrekt zurückgeschickt
|
103 | return (SD_ERROR_CMD8_PATTERN); |
104 | |
105 | uiTimeout = 0; |
106 | |
107 | while (aucCmd[0] != 0 && uiTimeout < 10000) { |
108 | // Sendet Kommando CMD55 an SD-Karte um ACMD einzuleiten
|
109 | aucCmd[0] = CMD55_APP_CMD; |
110 | aucCmd[1] = 0x00; |
111 | aucCmd[2] = 0x00; |
112 | aucCmd[3] = 0x00; |
113 | aucCmd[4] = 0x00; |
114 | aucCmd[5] = 0xFF; |
115 | btError = bt_SD_Write_Command(1, aucCmd, 1); |
116 | if (btError == SD_ERROR || aucCmd[0] != 1) |
117 | // Irgend ein Fehler aufgetreten
|
118 | return (SD_ERROR_CMD55); |
119 | |
120 | // Sendet Kommando ACMD41 an SD-Karte
|
121 | // HCS Bit ist 0 da der Host keine High-Capacity Karten unterstützt
|
122 | aucCmd[0] = ACMD41_SD_SEND_OP_CMD; |
123 | aucCmd[1] = SDHC_HCS_INAKTIV; |
124 | aucCmd[2] = 0x00; |
125 | aucCmd[3] = 0x00; |
126 | aucCmd[4] = 0x00; |
127 | aucCmd[5] = 0xFF; |
128 | btError = bt_SD_Write_Command(1, aucCmd, 1); |
129 | if (btError == SD_ERROR || (aucCmd[0] & 0xFE) != 0) |
130 | // Irgend ein Fehler aufgetreten
|
131 | return (SD_ERROR_ACMD41); |
132 | |
133 | // Kurz warten
|
134 | v_Sleep_RTC(RTC_RELOAD_5MS); |
135 | |
136 | // Timeout Zähler erhöhen
|
137 | uiTimeout++; |
138 | }
|
139 | |
140 | // Sendet Kommando CMD58 an SD-Karte um CCS Bit auszulesen (Bestimmt ob es eine SD oder SDHC Karte ist)
|
141 | aucCmd[0] = CMD58_READ_OCR; |
142 | aucCmd[1] = 0x00; |
143 | aucCmd[2] = 0x00; |
144 | aucCmd[3] = 0x00; |
145 | aucCmd[4] = 0x00; |
146 | aucCmd[5] = 0xFF; |
147 | btError = bt_SD_Write_Command(1, aucCmd, 5); |
148 | |
149 | if (btError == SD_ERROR || aucCmd[0] != 0) |
150 | // Irgend ein Fehler aufgetreten
|
151 | return (SD_ERROR_CMD58); |
152 | else if ((aucCmd[1] & 0x40) == 0) |
153 | // Normale SD-Karte
|
154 | btSDHC = 0; |
155 | else
|
156 | // SDHC-Karte
|
157 | btSDHC = 1; |
158 | }
|
159 | |
160 | // Karte erfolgreich initialisiert
|
161 | return (SD_OK); |
162 | }
|
Wenn du den gesamten Code sehen willst, dann kannst du in meinem SVN Repository drauf zugreifen: https://quakeman.homelinux.net/viewvc/uVision/trunk/Library/SD_Karte_Funktionen.c?view=markup und https://quakeman.homelinux.net/viewvc/uVision/trunk/Library/SD_Karte_Funktionen.h?view=markup Ciao, Rainer
Moin Nahcdem ich meine init-Routine mit deiner abgeglichen hab, funktionierts endlich. Es lassen sich alle SD-, SDHC- und MMC-Karten, die ich hier rumliegen hab, synchronisieren und unterscheiden. Ich hänge jetzt allerdings an einem anderem Problem. Das hat aber nichts mehr mit der Kommunikation zwischen µC und Karte zu tun. Die macht genau was sie soll. Bei der FAT-bibliothek von ELM-Chan funktioniert anscheind die Weitergabe der Pointer nicht richtig. Beim Versuch den 1. Block auszulesen um festzustellen um welches FAT es sich handelt, läuft der µC irgendwo in eine Endlosschleife. Ich denke das der Compiler (Kile µVision 3)da irgendwie Mist baut mit den Pointern bzw der µC. Werde dazu aber ggf einen neuen Thread beginnnen, falls ich das Problem nicht anders gelöst bekomme. (Wetter is aber zu gut :D )
Ich habe auch mal etwas mit dem FAT32 Dateisystem herumexperimentiert. Dabei habe ich die Fat32 Routinen selber geschrieben, da ich lernen wollte, wie es funktioniert und nicht einfach fertigen Code benutzen wollte. Leider habe ich schon länger nicht mehr weiter gemacht dadran, aber die paar einfachen Funktionen funktionieren schon mal. https://quakeman.homelinux.net/viewvc/uVision/trunk/Test_Fat32/FAT32_Funktionen.c?view=markup https://quakeman.homelinux.net/viewvc/uVision/trunk/Test_Fat32/FAT32_Funktionen.h?view=markup Der FAT32 Code ist allgemeingültig geschrieben, nur die Low-Level SD Funktionen sind speziell für den LPC935. Es werden dabei meine SD-Routinen verwendet, die ich vorher schon hier gepostet hatte. :) Ciao, Rainer
Vielleicht für den einen oder anderen interessant: Es gibt eine SD-Karte mit WLAN. Man könnte also bequem galvanisch getrennt übers WLAN seine Daten transferieren.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.