microSD-Karte lesen

#1070519
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.
Gast #1070754
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
#1070758
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.
#1070789
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.)
Gast #1070836
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren