Forum: Mikrocontroller und Digitale Elektronik SD-Karte kommt nicht aus dem Idle (8051)


von SD-Gestresster (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Filippé M. (Firma: Norris Vietnam-Reisen GmbH) (mcspeckfett)


Lesenswert?

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.

von Filippé M. (Firma: Norris Vietnam-Reisen GmbH) (mcspeckfett)


Angehängte Dateien:

Lesenswert?

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?

von Schütze (Gast)


Lesenswert?

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.

von Filippé M. (Firma: Norris Vietnam-Reisen GmbH) (mcspeckfett)


Lesenswert?

upps vergessen mich einzuloggen.

von R. W. (quakeman)


Lesenswert?

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

von Filippé M. (Firma: Norris Vietnam-Reisen GmbH) (mcspeckfett)


Lesenswert?

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 )

von R. W. (quakeman)


Lesenswert?

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

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.