Forum: Compiler & IDEs microSD-Karte lesen


von Julian M. (jvm)


Lesenswert?

Hallo!

Ich habe eine 2GB-microSD-Karte von Sandisk hier, und moechte auf die 
Daten zugreifen. Zum Testen meiner Hardware dachte ich, verwende ich mal 
das Beispielprogramm der avrlib von Pascal Stang unter examples/mmc. Nur 
Taktfrequenz richtig eingetragen und Programm auf einen ATMEGA8 
geflashed. Das Initialisieren ging nicht. Ich habe dann Dokumentation 
gelesen und die Initialisierungsfunktion ueberarbeitet, jetzt schliesst 
es immer erfolgreich mit einem erfolgreichem Return-Code (0) ab. (Bis 
alles erfolgreich durchlaeuft sind meistens drei Schleifendurchlaeufe 
erforderlich.)
Nach dem Initialisieren wuerde ich gerne Lesen ;) Beim Lesen des Sektors 
0 bekomme ich Daten zurueck, die nichts mit den auf der Karte 
enthaltenen Daten zu tun haben, aber eindeutig fuer die Karte sind. 
(Eine zweite, baugleiche Karte liefert reproduzierbar andere Werte, 
auch, nachdem beide Karten per "dd" synchronisiert wurden.)
Frage: Woran kann es liegen, dass ich Bloedsinn lese, wie sollte ich 
vorgehen um das Problem genauer zu analysieren, wieso sind die gelesenen 
Daten eindeutig fuer die Karte, aber unabhaengig von den auf der Karte 
gespeicherten Daten?

Zweite Frage:
In der avrlib steht
1
r1 = mmcCommand(MMC_READ_SINGLE_BLOCK, sector<<9);
im Beispiel der elm-Bibliothek hingegen
1
if ((send_cmd(CMD17, sector) == 0)  /* READ_SINGLE_BLOCK */
Letzteres wirkt plausibler. Was hat sich Pascal bei seiner Variante 
gedacht?

Vielen Dank fuer Tipps
Julian

Hier noch meine veraenderte Initialisierungsfunktion: (einzige Aenderung 
gegenueber der avrlib von Pascal Stang)
1
u08 mmcReset(void)
2
3
{
4
5
  u08 i;
6
7
  u08 retry;
8
9
  u08 r1=0;
10
11
12
13
  retry = 0;
14
15
  do
16
17
  {
18
19
    // send dummy bytes with CS high before accessing
20
21
    for(i=0;i<10;i++) spiTransferByte(0xFF);
22
23
    // resetting card, go to SPI mode
24
25
    r1 = mmcSendCommand(MMC_GO_IDLE_STATE, 0);
26
27
    #ifdef MMC_DEBUG
28
29
    rprintf("MMC_GO_IDLE_STATE: R1=0x%x\r\n", r1);
30
31
    #endif
32
33
    // do retry counter
34
35
    retry++;
36
37
    if(retry>10) return -1;
38
39
  } while(r1 != 0x01);
40
41
42
43
  for (retry = 0; retry < 10; retry++) {
44
45
    r1 = mmcSendCommand(CMD55, 0);
46
47
    #ifdef MMC_DEBUG
48
49
    rprintf("CMD55: R1=0x%x\r\n", r1);
50
51
    #endif
52
53
        if (r1 != 5) continue;
54
55
56
57
    r1 = spiTransferByte(0xFF);
58
59
    #ifdef MMC_DEBUG
60
61
    rprintf("DUMMY: R1=0x%x\r\n", r1);
62
63
    #endif
64
65
        if (r1 != 255) continue;
66
67
68
69
    r1 = mmcSendCommand(MMC_SEND_OP_COND, 0);
70
71
    #ifdef MMC_DEBUG
72
73
    rprintf("MMC_SEND_OP_COND: R1=0x%x\r\n", r1);
74
75
    #endif
76
77
        if (r1 != 0) continue;
78
79
80
81
    r1 = spiTransferByte(0xFF);
82
83
    #ifdef MMC_DEBUG
84
85
    rprintf("DUMMY: R1=0x%x\r\n", r1);
86
87
    #endif
88
89
        if (r1 != 255) continue;
90
91
92
93
    r1 = mmcSendCommand(MMC_CRC_ON_OFF, 0);
94
95
    #ifdef MMC_DEBUG
96
97
    rprintf("MMC_CRC_ON_OFF: R1=0x%x\r\n", r1);
98
99
    #endif
100
101
        if (r1 != 0) continue;
102
103
104
105
    r1 = spiTransferByte(0xFF);
106
107
    #ifdef MMC_DEBUG
108
109
    rprintf("DUMMY: R1=0x%x\r\n", r1);
110
111
    #endif
112
113
        if (r1 != 255) continue;
114
115
116
117
      // set block length to 512 bytes
118
119
      r1 = mmcSendCommand(MMC_SET_BLOCKLEN, 512);
120
121
      #ifdef MMC_DEBUG
122
123
      rprintf("MMC_SET_BLOCKLEN: R1=0x%x\r\n", r1);
124
125
      #endif
126
127
        if (r1 == 0) return 0;
128
129
  }
130
131
132
133
    return -1;
134
135
}

edit: Verwendeter Schaltplan: 
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1206874649/8 mit 
Pinbelegung fuer die SD-Karte von 
http://www.planetmobile.it/jumpjack/adattatore/pinout-eng.html und das 
ganze natuerlich an die SPI-Ports vom ATMEGA8.

von Olaf (Gast)


Lesenswert?

Gegenfrage: Woher weisst du was im Sektor0 stehen muss?
Liess die Karte mal unter linux mit dd aus.
Wenn du es bisher unter Windows gemacht hast dann kann dein Problem 
daran liegen das dich Windows wie gewoehnlich bescheisst und dir nicht 
den Bootsektor angezeigt hat sondern den ersten Sektor deiner Partition.

Olaf

von Julian M. (jvm)


Lesenswert?

Ich hatte dd doch bereits erwaehnt? Ich habe eine Karte FAT16 
formatiert, zwei Dateien ins root-Directory, die Rohdaten komplett 
gelesen, auf die zweite Karte per dd draufgeschrieben, und die Rohdaten 
im Hexeditor analysiert. Wie erwartet ein "MSDOS" und "FAT16" im ersten 
Sektor, viele Nullen, und irgendwann meine beiden Dateien.
Das Demoprogramm aus der avrlib gibt die Daten gleich nett formatiert 
per UART aus. Eine Zeichenkette in den von dem Demoprogramm ausgegebenen 
Daten kann der Hexeditor in den vorher kopierten Rohdaten aber nicht 
finden, ausserdem liest das Demoprogramm jedesmal das gleiche, auch wenn 
ich die Karte mit anderen Daten beschreibe. Das spricht dafuer, dass das 
Demoprogramm Bloedsinn liest.

von Julian M. (jvm)


Lesenswert?

Aehm...obwohl ich deine Antwort gerade als Bloedsinn abtat, war sie die 
Loesung: Wer immer dd if=/dev/sde1 of=... zum Kartenlesen verwendet, 
verpasst natuerlich den ersten Sektor. Kaum liest man wirklich die ganze 
Karte, hat man die gleichen Daten, wie das Demoprogramm sie auch liest.

Ich entschuldige mich vielmals, und bedanke mich!
(An alle Leute die Probleme mit MicroSD-Initialisierung haben: die 
avrlib mit obiger Reset-Funktion laeuft bei meiner 2GB-Sandisk-Karte, 
die Originalversion hingegen nicht. Der Beispiel-Code der elm-Bibliothek 
initialisierte bei mir auch nicht richtig.)

von Olaf (Gast)


Lesenswert?

Nochmal einen kleinen Tip dazu.

Wenn man Daten auf so einer Karte ablegen will dann gibt es 
normalerweise
zwei Moeglichkeiten.

1. Man schreibt sie raw einfach irgendwo hin, muss aber dann
   dann im Betriebssystem ebenfalls raw lesen.

2. Man unterstuetzt halt das FAT DAteisystem und hat dabei den
   entsprechenden aufwand.

Eine gute Loesung dazwischen ist es wenn man auf seiner leeren Karte
eine Datei anlegt die garantiert groesser ist als man fuer seine
Daten braucht. Es ist aber wichtig das die Karte vorher leer ist
damit die Datei nicht fragmentiert ist.
In den ersten Bytes seiner Datei legt man dann eine komplizierte
Bytefolge als Magicnumber. Der Controller sucht dann beim einlegen
nach dieser Nummer und weiss dann ab wo die Datei am Stueck auf der
Karte liegt. Danach kann er seine Daten einfach hinter die Nummer 
schreiben.
Damit umgeht man das Problem das eine Datei auf verschieden grossen 
Speicherkarten auf verschiedenen Sektoren beginnen wird, kann aber 
andererseits die Daten auf seinem Betriebssystem ganz einfach lesen. 
Letzeres sogar mit einem Texteditor wenn der Controller sie als ASCII 
ablegt.

Olaf

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.