Forum: Mikrocontroller und Digitale Elektronik Initialisierung einer SD-Karte im SPI Mode


von Holger (Gast)


Lesenswert?

Hallo,

ich bin dabei eine 1GB MicroSD Karte mit einem STM32 zu initialisieren.
CMD0 antwortet mit 0x01, also erreiche ich den IDLE state.

Auf CMD8 kommt keine Antwort also nur 0xff. Daher gehe ich von SD Vers. 
1 aus.

Ich sende ACMD41, doch bereits beim CMD55 kommt als Antwort nur 0xff, 
also keine Antwort. Ich denke nicht, dass die MicroSD Karte als MMC Vers 
3 erkannt werden möchte.

Welche potentiellen Fehler könnte ich gemacht haben?

Vielen Dank!

von Jim M. (turboj)


Lesenswert?

Zeig mal den Code. Du musst übrigens bei CMD8 die korrekte CRC7 
Checksumme angeben.

Ansonsten: Ein R1 Antwort-Byte mit gesetztem 0x80 Bit ist keine 
Antwort, sondern die Info dass sich die Antwort verzögert und man noch 
ein (dummy) Byte senden muss.

von Holger (Gast)


Lesenswert?

Ich werde mal versuchen ein dummybyte zu senden, wenn ein 0xff kommt. 
Ich bin aber eigentlich davon ausgegangen, dass einfach keine Antwort 
gekommen ist, wenn der MISO Pin nicht irgendwann mal nach unten gezogen 
worden ist.

Die CRC Checksumme übergebe ich als 0x87 für CMD8

Hier mal die Initialisierung:
1
  SD_CS_H;
2
  SD_WRITE_H;
3
  SD_SCLK_L;
4
5
  delay_us(2000); // TODO vielleicht mehr als 1000
6
7
  SD_toggle(148);
8
9
  sendArray[0] = CMD0;
10
  sendArray[1] = 0x00;
11
  sendArray[2] = 0x00;
12
  sendArray[3] = 0x00;
13
  sendArray[4] = 0x00;
14
  SD_CS_L; // start
15
  SD_Command_Write(&(sendArray[0]));
16
  SD_Receive(1);
17
  SD_WRITE_L;
18
  SD_toggle(8); // TODO Pruefen ob notwendig
19
  SD_CS_H; // stop
20
  if (SD_readArray[0] == 0x01) // JA
21
  {
22
    sendArray[0] = CMD8;
23
    sendArray[1] = 0x00;
24
    sendArray[2] = 0x00;
25
    sendArray[3] = 0x01;
26
    sendArray[4] = 0xAA;
27
    SD_CS_L; // start
28
    SD_Command_Write(&(sendArray[0]));
29
    if (!SD_Receive(5))
30
    {
31
      SD_WRITE_L;
32
      SD_toggle(8); // TODO Pruefen ob notwendig
33
      SD_CS_H; // stop
34
      SD_Version = 1;
35
    }
36
    else
37
    {
38
      SD_WRITE_L;
39
      SD_toggle(8); // TODO Pruefen ob notwendig
40
      SD_CS_H; // stop
41
      if (SD_readArray[0] & 0x7F)
42
      {
43
        SD_Version = 1;
44
      }
45
      if (SD_readArray[3] != 0x01 || (SD_readArray[4] != 0xAA))
46
      {
47
        SD_Version = 0;
48
        // power off card
49
        return;
50
      }
51
    }
52
    int errCounter = 0;
53
    SD_CS_L; // start
54
    do
55
    {
56
      sendArray[0] = CMD55;
57
      sendArray[1] = 0x00;
58
      sendArray[2] = 0x00;
59
      sendArray[3] = 0x00;
60
      sendArray[4] = 0x00;
61
      SD_Command_Write(&(sendArray[0]));
62
      SD_Receive(1);
63
64
65
      sendArray[0] = ACMD41;
66
      sendArray[1] = 0x40;
67
      sendArray[2] = 0x00;
68
      sendArray[3] = 0x00;
69
      sendArray[4] = 0x00;
70
      SD_Command_Write(&(sendArray[0]));
71
      SD_Receive(1);
72
      delay_us(1000);
73
      errCounter++;
74
    } while ((SD_readArray[0] == 0x01) && (errCounter <= 1000));
75
    SD_CS_H; // stop
76
    // TODO hier muesste eigentlich eine 00 statt einer 0xff stehen
77
    if ((SD_readArray[0] == 0x00) && (errCounter <= 1000))
78
    {
79
      if (SD_Version == 2)
80
      {
81
        SD_toggle(8);
82
        sendArray[0] = CMD58;
83
        sendArray[1] = 0x40;
84
        sendArray[2] = 0x00;
85
        sendArray[3] = 0x00;
86
        sendArray[4] = 0x00;
87
        SD_Command_Write(&(sendArray[0]));
88
        SD_Receive(4);
89
        if (SD_readArray[1] & 0x40)
90
        {
91
          SDHC = 1;
92
          return;
93
        }
94
      }
95
      if (!SDHC)
96
      {
97
        // Blocksize 512 Bytes
98
        SD_toggle(8);
99
        sendArray[0] = CMD16;
100
        sendArray[1] = 0x00;
101
        sendArray[2] = 0x00;
102
        sendArray[3] = 0x02;
103
        sendArray[4] = 0x00;
104
        SD_Command_Write(&(sendArray[0]));
105
        SD_Receive(1);
106
      }
107
    }
108
    else
109
    {
110
      SD_Version = 0;
111
      // power off
112
      return;
113
    }
114
  }
115
  else
116
  {
117
    SD_Version = 0;
118
    // power off
119
  }

von Holger (Gast)


Lesenswert?

Also insgesamt sende ich 64 dummybits wo ich darauf warte, dass die 
MicroSD mir den MISO-Pin mal nach unten zieht. Tut sie aber nicht. --> 
keine Antwort

Außerdem habe ich ein paar SD_WRITE_L durch SD_WRITE_H vor dem Toggeln 
ausgetauscht, weil ich ja 0xFF senden muss und nicht 0x00. Beim Toggeln 
werden jetzt also Einsen an de MOSI rausgeschickt.

Dennoch läuft es nicht. Nachdem ich 0x01 vom CMD0 bekommen habe bekomme 
ich weder von CMD8 noch von ACMD41 (schon beim CMD55) keine Antwort.

CMD8 ist bei mir: 0x48 0x00 0x00 0x01 0xAA 0x87

von Jim M. (turboj)


Lesenswert?

Holger schrieb:
> Also insgesamt sende ich 64 dummybits wo ich darauf warte, dass die
> MicroSD mir den MISO-Pin mal nach unten zieht. Tut sie aber nicht. -->
> keine Antwort

Bei welchem SPI Takt? Initial darf der maximal 400 kHz sein.
In meiner SD Kommandofunktion wartet er bis zu 1000 Zeichen ab, ob das 
0x80 Bit mal gelöscht wird. Das gilt auch für CMD0, das außerdem noch 
bis zu 16 Mal wiederholt wird.



Nochwas:
1
  SD_WRITE_L;
2
  SD_toggle(8); // TODO Pruefen ob notwendig
3
  SD_CS_H; // stop

Falsch herhum. "SD_CS_H;" muss vor dem Toggle stattfinden, also erst 
deselktieren und dann 0xFF Byte schreiben.

: Bearbeitet durch User
von Holger (Gast)


Lesenswert?

Also der Takt liegt momentan bei 66 kHz. Also weit unter den 400kHz.

Ich warte momentan nur 128 Bit. Ich habe das auf 8000 Bit (also 1000) 
Zeichen erhöht. Macht keinen Unterschied, nur dass man jetzt merkt, dass 
das Programm wartet.

Da CMD0 bei mir richtig läuft lasse ich das dort erstmal mit dem einmal 
aufrufen. Idle reicht doch oder muss ich dann nochmal resetten?

SD_CS_H steht jetzt vor dem toggeln, funktioniert aber auch nicht.

Weder CMD8 noch CMD55 oder ACMD41 liefert mir irgendwann ein 0x00;

von Reto W. (Firma: Swissbit.com) (swissbit)


Lesenswert?

Hast du möglicherweise einen Logik Trace von der Initialisierung?

Gruss

von Jim M. (turboj)


Lesenswert?

Holger schrieb:
> Weder CMD8 noch CMD55 oder ACMD41 liefert mir irgendwann ein 0x00;

Die dürfen aber auch 0x01 als Ergebnis liefern. Dass die Karte im Idle 
State ist, das ist ja korrekt so.

Bei meinem Code (Quelle is EFSL) wird das CMD8 auf "1" als Ergebniscode 
geprüft.

von Holger (Gast)


Lesenswert?

Einen LogicTrace habe ich leider nicht.

Wenn ich ein 0x01 erhalten würde wäre ich ja schon mal zufrieden. Leider 
antwortet die Karte gar nicht auf CMD8 und CMD55 oder ACMD41.

Ich habe das Projekt jetzt erst einmal zurückgestellt und werde es 
später noch einmal versuchen.

Vielen Dank aber bis jetzt!

von Markus M. (adrock)


Lesenswert?

Was für ein STM32 ist es denn?

Ich hatte mir beim STM32F0 (fast) die Karten gelegt, weil das 
SPI-Register standardmäßig als 16-Bit Wert gelesen/geschrieben wird, 
d.h. es werden dann auch 16 Bits übertragen/gelesen.

Außerdem hat der STM32F0 auch einen FIFO im SPI.

Stimmt natürlich alles nur wenn man ohne die periphals lib programmiert.

von Holger (Gast)


Lesenswert?

Es ist ein STM32F407VGT6 auf einem Discovery Board. SPI habe ich nicht 
konfiguriert. Das mache ich momentan über Software.

Also ganz simples Bit setzen, Takt hoch, 3us warten, Takt runter und 
nächstes Bit...
Die Übertragung scheint auch zu klappten. Ich bekomme eine richtige 
Antwort auf CMD0.

von Holger (Gast)


Lesenswert?

Ich habe mich mal durchgesteppt.
Sowohl der CMD55 als auch der ACMD41 antworten beide genau einmal mit 
0x01.
Und das beim ersten Durchlauf. Danach kommen nur noch 0xFF, also keine 
Antwort.

Der Fehler muss also demnach im folgenden Codestück liegen.
1
    SD_CS_L; // start
2
    int position = 0;
3
    do
4
    {
5
      sendArray[0] = CMD55;
6
      sendArray[1] = 0x00;
7
      sendArray[2] = 0x00;
8
      sendArray[3] = 0x00;
9
      sendArray[4] = 0x00;
10
      SD_Command_Write(&(sendArray[0]));
11
      if (SD_Receive(1))
12
      {
13
        position = 1;
14
      }
15
16
//      SD_CS_H; // stop
17
//      SD_toggle(8); // TODO Pruefen ob notwendig
18
//      SD_CS_L;
19
20
      sendArray[0] = ACMD41;
21
      sendArray[1] = 0x40;
22
      sendArray[2] = 0x00;
23
      sendArray[3] = 0x00;
24
      sendArray[4] = 0x00;
25
      SD_Command_Write(&(sendArray[0]));
26
      if (SD_Receive(1))
27
      {
28
        position = 2;
29
      }
30
31
      SD_CS_H; // stop
32
      SD_toggle(8); // TODO Pruefen ob notwendig
33
      SD_CS_L;
34
35
      delay_us(1000);
36
      errCounter++;
37
    } while ((SD_readArray[0] != 0x00) && (errCounter <= 1000));
38
    SD_CS_H; // stop

von grundschüler (Gast)


Lesenswert?

Holger schrieb:
> Also ganz simples Bit setzen,

dann vergleiche deinen Code mit dem bitbanging Code von Chan -avr 
foolproof. Oder noch besser, nimm gleich den code von chan. Beim F103 
hat der fast auf Anhieb geklappt.

von Holger (Gast)


Lesenswert?

Praxis ist wenn es geht und weiß nicht warum.
Auf jeden Fall klappt es jetzt nach der Mittagspause die Karte als SDHC 
zu initialisieren.

Hier der fertige Initialisierungscode:
1
void SD_init(void)
2
{
3
  unsigned char sendArray[5];
4
  SD_Version = 2;
5
  SDHC = 0;
6
7
  // Konfiguration SCK, MISO, MOSI, CS
8
  // Pullips
9
  GPIOC -> PUPDR &= ~(1 << 25);
10
  GPIOC -> PUPDR |= (1 << 24);
11
  GPIOC -> PUPDR &= ~(1 << 23);
12
  GPIOC -> PUPDR |= (1 << 22);
13
  GPIOD -> PUPDR &= ~(1 << 5);
14
  GPIOD -> PUPDR |= (1 << 4);
15
16
  // Konfiguration des Eingangs (MISO PC8)
17
  GPIOC -> MODER &= ~((1 << 16) + (1 << 17));
18
  GPIOC -> PUPDR &= ~(1 << 17);
19
  GPIOC -> PUPDR |= (1 << 16);
20
//  GPIOC -> TYPER |= (1 << 8); // open drain
21
22
  // Konfiguration der Outputs
23
  GPIOC -> MODER |= (1 << 22) + (1 << 24);
24
  GPIOD -> MODER |= (1 << 4);
25
26
  SD_SCLK_L;
27
28
  delay_us(2000); // TODO vielleicht mehr als 1000
29
30
  SD_CS_H;
31
  SD_WRITE_H;
32
33
  SD_toggle(148); // TODO vielleicht mehr als 74
34
35
  sendArray[0] = CMD0;
36
  sendArray[1] = 0x00;
37
  sendArray[2] = 0x00;
38
  sendArray[3] = 0x00;
39
  sendArray[4] = 0x00;
40
  SD_CS_L; // start
41
  SD_Command_Write(&(sendArray[0]));
42
  SD_Receive(1);
43
  SD_CS_H; // stop
44
  SD_toggle(8); // TODO Pruefen ob notwendig
45
  if (SD_readArray[0] == 0x01) // JA
46
  {
47
    sendArray[0] = CMD8;
48
    sendArray[1] = 0x00;
49
    sendArray[2] = 0x00;
50
    sendArray[3] = 0x01;
51
    sendArray[4] = 0xAA;
52
    SD_CS_L; // start
53
    SD_Command_Write(&(sendArray[0]));
54
    if (SD_Receive(5) == 0)
55
    {
56
      SD_CS_H; // stop
57
      SD_toggle(8); // TODO Pruefen ob notwendig
58
      SD_Version = 1;
59
    }
60
    else
61
    {
62
      SD_CS_H; // stop
63
      SD_toggle(8); // TODO Pruefen ob notwendig
64
      if (SD_readArray[0] & 0x7E)
65
      {
66
        SD_Version = 1;
67
      }
68
      if (SD_readArray[3] != 0x01 || (SD_readArray[4] != 0xAA))
69
      {
70
        SD_Version = 0;
71
        // power off card
72
        return;
73
      }
74
    }
75
    int errCounter = 0;
76
    SD_CS_L; // start
77
    int position = 0;
78
    do
79
    {
80
      SD_CS_H;
81
      SD_toggle(16); // TODO Pruefen ob notwendig (16)
82
      SD_CS_L;
83
84
      sendArray[0] = CMD55;
85
      sendArray[1] = 0x00;
86
      sendArray[2] = 0x00;
87
      sendArray[3] = 0x00;
88
      sendArray[4] = 0x00;
89
      SD_Command_Write(&(sendArray[0]));
90
      if (SD_Receive(1))
91
      {
92
        position = 1;
93
      }
94
95
      SD_CS_H;
96
      SD_toggle(16); // TODO Pruefen ob notwendig (16)
97
      SD_CS_L;
98
99
      sendArray[0] = ACMD41;
100
      if (SD_Version == 2) sendArray[1] = 0x40;
101
      else sendArray[1] = 0x00;
102
      sendArray[2] = 0x00;
103
      sendArray[3] = 0x00;
104
      sendArray[4] = 0x00;
105
      SD_Command_Write(&(sendArray[0]));
106
      if (SD_Receive(1))
107
      {
108
        position = 2;
109
      }
110
111
      errCounter++;
112
    } while ((SD_readArray[0] != 0x00) && (errCounter <= 100));
113
    SD_CS_H; // stop
114
    // TODO hier muesste eigentlich eine 00 statt einer 0xff stehen
115
    int test = SD_readArray[0];
116
    if ((SD_readArray[0] == 0x00) && (errCounter <= 1000))
117
    {
118
      if (SD_Version == 2)
119
      {
120
        SD_CS_H; // stop
121
        SD_toggle(16); // TODO Pruefen ob notwendig
122
        sendArray[0] = CMD58;
123
        sendArray[1] = 0x40;
124
        sendArray[2] = 0x00;
125
        sendArray[3] = 0x00;
126
        sendArray[4] = 0x00;
127
        SD_Command_Write(&(sendArray[0]));
128
        SD_Receive(4);
129
        if (SD_readArray[1] & 0x40)
130
        {
131
          SDHC = 1;
132
          return;
133
        }
134
      }
135
      if (!SDHC)
136
      {
137
        // Blocksize 512 Bytes
138
        SD_CS_H; // stop
139
        SD_toggle(16); // TODO Pruefen ob notwendig
140
        sendArray[0] = CMD16;
141
        sendArray[1] = 0x00;
142
        sendArray[2] = 0x00;
143
        sendArray[3] = 0x02;
144
        sendArray[4] = 0x00;
145
        SD_Command_Write(&(sendArray[0]));
146
        SD_Receive(1);
147
      }
148
    }
149
    else
150
    {
151
      SD_Version = 0;
152
      // power off
153
      return;
154
    }
155
  }
156
  else
157
  {
158
    SD_Version = 0;
159
    // power off
160
  }
161
}

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.