Forum: Mikrocontroller und Digitale Elektronik SD-Karte initialisieren


von Johannes (Gast)


Lesenswert?

Hallo!

Ich habe mir eigene Routinen in Assembler geschrieben, um die SD-Karte 
zu initialisieren. Beim Senden des CMD0 funktioniert das auch, ich 
bekomme eine 1 zurück, allerdings bekomme ich die auch bei einem CMD1 
immer zurück, ich habe es schon in einer Schleife versucht, die über 
eine halbe Minute lang CMD1 sendet und immer nur 1 empfängt.

meine Routine:

!ANMERKUNG! in r1 steht immer eine 0 und in r2 immer 255

.equ SD_Addr = 0x60 ;reservierter SRAM Speicher für SD-Karten Befehl

SD_SendCommand: ;sendet 6 Befehlsbytes [SD_Addr..SD_Addr+5]

  sbi PORT_SPI,SEL  ;Chip NICHT selektieren

  out SPDR,r2    ;$ff senden
  sbis SPSR,SPIF
  rjmp PC-1

  cbi PORT_SPI,SEL  ;Chip select

  lds r16,SD_Addr+0  ;1. Byte lesen
  out SPDR,r16    ;und senden
  lds r16,SD_Addr+1  ;nächstes Byte schonmal einlesen
  sbis SPSR,SPIF    ;warten bis erstes fertig gesendet wurde
  rjmp PC-1    ;
  out SPDR,r16    ;2. Byte senden... usw..
  lds r16,SD_Addr+2
  sbis SPSR,SPIF
  rjmp PC-1
  out SPDR,r16    ;3
  lds r16,SD_Addr+3
  sbis SPSR,SPIF
  rjmp PC-1
  out SPDR,r16    ;4
  lds r16,SD_Addr+4
  sbis SPSR,SPIF
  rjmp PC-1
  out SPDR,r16    ;5
  lds r16,SD_Addr+5
  sbis SPSR,SPIF
  rjmp PC-1
  out SPDR,r16    ;6
  sbis SPSR,SPIF
  rjmp PC-1

;auf Antwort Warten

  ldi r17,10      ;Zähler für Anzahl der Versuche
wr:          ;Auf Antwort warten..
  out SPDR,r2      ;Takt für eingehendes Byte erzeugen
  sbis SPSR,SPIF
  rjmp PC-1
  in r16,SPDR      ;empfangenes Byte lesen
  cpi r16,$ff
  brne weiter      ;Byte nicht $ff, dann fertig
  dec r17        ;Zähler schon bei 0?
  brne wr        ;nein, dann weitere Bytes lesen
weiter:
  ret        ;empfangenes Byte in r16, bei Timeout stets $ff


Hier die Initialisierungsroutine:

SD_Init:
  sbi PORT_SPI,SEL  ;Chip NICHT selektieren

;## 80 Clock-Pulse senden
  ldi r17,$0a    ;Zähler für zu sendende Bytes
clkLoop:
  ldi r16,$ff
  out SPDR,r16    ;$ff senden
  sbis SPSR,SPIF
  rjmp PC-1
  dec r17
  brne clkLoop

;## CMD 0 senden
  ldi r16,$40    ;Befehl
  sts SD_Addr+0,r16
  sts SD_Addr+1,r1  ;Adressbytes..
  sts SD_Addr+2,r1
  sts SD_Addr+3,r1
  sts SD_Addr+4,r1
  ldi r16,$95    ;Prüfsumme
  sts SD_Addr+5,r16
  rcall SD_SendCommand    ;Befehl senden
  cpi r16,$01    ;Idle-State?
  breq SD_OK1    ;Ja, dann weiter
  //**Fehlerbehandlung***  ;Nein, Fehlermeldung
  ret      ;und Abbruch.

SD_OK1:

;## CMD 1 senden
  ldi r16,$41
  sts SD_addr+0,r16  ;Befehl
  sts SD_Addr+5,r2  ;Prüfsumme auf $ff

  clr r18      ;Zähler für Anzahl der Versuche
  clr r19

cLoop:

  rcall SD_SendCommand    ;Befehl senden
  cpi r16,$00    ;Init erfolgreich?
  breq SD_OK2    ;ja, dann weiter
  dec r18      ;nein, dann dec(Zähler)
  brne cLoop
  dec r19
  brne cLoop    ;
                    ;Zähler bei 0 angekommen: Fehler...
  //**Fehlerbehandlung***  ;Fehlermeldung
  ret      ;und Abbruch.

SD_OK2:
    ;Alles OK!
  ret

von Carsten P. (papa_of_t)


Lesenswert?

Ein funktionierendes Beispiel in Assembler findest Du hier:

http://members.aon.at/voegel

oder genauer

http://members.aon.at/voegel/Downloads/Driver/MMC/MMC.LIB

(ist eigentlich für Bascom und MMC gedacht, sollte aber in Deinem Fall 
keine Rolle spielen)

von Daniel S. (dschwab)


Lesenswert?

Hallo Johannes

Ich hoffe, du verstehst etwas C. So dürfte es dir nicht mehr schwer 
fallen deinen Code in Assembler zum laufen zu bringen.

Gruss, Daniel


//********************************************************************** 
********************
// MMC Kontrollieren und korrekt Einstellen
//********************************************************************** 
********************
int MMC_0_Check (void)
{
// Karte eingelegt?
if (MMC_0_io_CDS()) // Ist eine Karte eingelegt?
  {
  MMC_0_SPI_Modus(); // Karte in den SPI Modus umschalten
  if (MMC_0_Kommando(0x40, 0x00, 0x95) == 0x01)  // Karte Reseten
    {
    if (MMC_0_Init()) // Karte initialisieren
      {
      // Karten CRC ausschalten
      if ((MMC_0_Kommando(0x7B, 0x00, 0x00) == 0x00))
        {
        // Karten Blocklaenge 512
        if ((MMC_0_Kommando(0x50, 0x0200, 0xFF) == 0x00))
          {
          MMC0_Status = MMC_CARD_OK;
          return TRUE;
          }
        }
      }
    }
  }
return FALSE;
}


//********************************************************************** 
********************
// Karte in den SPI Modus umschalten
//********************************************************************** 
********************
void MMC_0_SPI_Modus (void)
{
MMC_0_io_card_select(MMC_CARD_DESELECT);
// Damit der User mehr Zeit hat, die Karte in den
// Kartenslot zu schieben
for (int x = 0;x < 40000; x++)  {spi0_send_receive (0xFF);}
}


//********************************************************************** 
********************
// MMC Initialisieren
//********************************************************************** 
********************
int MMC_0_Init (void)
{
int c;

for (c = 0; c < 0xFF; c++)
  {
  if (MMC_0_Kommando(0x41, 0x00, 0xFF) == 0x00)
    {
    return TRUE;
    }
  }
return FALSE;
}


//******************************************
// Kommandos an die MMC senden
//******************************************
int MMC_0_Kommando (unsigned int Kommando, unsigned int Adresse, 
unsigned int CRC)
{
int out;
MMC_0_io_card_select(MMC_CARD_SELECT);
spi0_send_receive (0xFF);
spi0_send_receive (Kommando);
spi0_send_receive (Adresse >> 24);
spi0_send_receive (Adresse >> 16);
spi0_send_receive (Adresse >> 8);
spi0_send_receive (Adresse);
spi0_send_receive (CRC);
spi0_send_receive (0xFF);
out = spi0_send_receive (0xFF);
MMC_0_io_card_select(MMC_CARD_DESELECT);
return out;
}




von Johannes (Gast)


Lesenswert?

Ja, ich kann den Code gut nachvollziehen, finde aber leider keine 
Unterschiede in der Vorgehensweise...

habe mal weiter getestet:
wenn man keine karte einsteckt, dann bekomme ich FF zurück
leider kann ich an stelle von CMD0 alles mögliche senden: andere 
Befehlscodes oder eine Falsche Prüfsumme liefert trotzdem den wert 1

mein spi ist folgendermaßen initialisiert:

ldi r16,(1<<SPE)|(1<<MSTR)|(1<<SPR0);MASTER, Prescaler: 16
out SPCR,r16

von fubu1000 (Gast)


Lesenswert?

hallo,
vielleicht schon zu schnell die initialisierung!!!

    ldi  temp1,  0x53
    out  SPCR,  temp1
    ldi temp1,  0x00
    out  SPSR,  temp1   ;vorteiler 128

wenns dann nit klapppt muss man deine routine mal anschauen oder deine 
hardwarwe!!

von Johannes (Gast)


Lesenswert?

Die eingänge der Karte sind alle über Spannungsteiler mit dem ATMega8 
verbunden. Data-out liegt direkt an. Versorgt wird die Karte über einen 
Spannungsregler (3.3V)
Ich habe alles nochmal ausgiebig getestet:
Wenn man die Karte rinsteckt, und die 80 clock-Pulse gesendet hat und 
den CMD 0 gesendet hat, dann bekommt man 1 als Rückgabewert.

Wenn ich nun einen Falschenbefehlscode sende, bekomme ich eine 5 zurück.
Das würde bedeuten, das "Illegal Command"-Bit und das "Idle" bit sind 
gesetzt -> übertragung macht keine Probleme.
jedoch das Senden des CMD1 sendet immernoch eine 1 zurück, egal wie oft 
ich es wiederhole. Zum Ausprobieren habe ich 2 verschiedene Karten.
Jetzt das komische: einmal habe ich es geschafft! es kam schon nach 
kurzer Zeit eine 0 zurück!
auch wenn ich jetzt einen ungültigen befehl sende, bekomme ich nur noch 
eine 4 zurück, also das "Idle" Bit ist tatsächlich gelöscht.
Dann hab ich die Schaltung neu in betrieb genommen, also Strom aus,an 
und schon stand ich vor dem alten Problem..

von fubu1000 (Gast)


Lesenswert?

hallo,
wenn du willst kann ich dir mal meine SD/MMC routinen (auch in asm) 
geben und du kannst testen oder erlesen worans liegt.
gruss

von holger (Gast)


Lesenswert?

Benutz mal anständige Pegelkonverter für MISO,MOSI,SCK,CS.

Ich hab mittlerweile 10 verschiedene MMC/SD
am laufen. Von 16MB bis 4GB.

Probleme wie du sie hast kenne ich gar nicht.

von Simon K. (simon) Benutzerseite


Lesenswert?

holger wrote:
> Benutz mal anständige Pegelkonverter für MISO,MOSI,SCK,CS.

Hat er doch. Ich benutze bei meinem AVRNAS auch Spannungsteiler, und das 
Dingen fluppt sehr gut...

Ich kann mich nicht mehr genau erinnern, aber mein C-Code der 
Initialisierung sieht so aus:
1
#define CMD0  (0x40+0)              
2
#define CMD1  (0x40+1)              
3
4
void spi_putb(uint8_t b)        
5
{
6
7
  SPDR0 = b;                
8
  while(!(SPSR0 & (1<<SPIF0)));          
9
}
10
11
uint8_t sd_cmd(uint8_t cmd, uint32_t arg)
12
{
13
  uint8_t temp;
14
15
  spi_putb(cmd);                
16
  spi_putb((uint8_t) (arg >> 24));          
17
  spi_putb((uint8_t) (arg >> 16));          
18
  spi_putb((uint8_t) (arg >> 8));            
19
  spi_putb((uint8_t) (arg));            
20
  spi_putb(0x95);                
21
22
  while((temp = spi_getb()) == 0xFF);        
23
24
  return temp;                
25
}
26
27
void sd_init()
28
{
29
  //....
30
  //select
31
  while(sd_cmd(CMD0, 0) != 1);
32
  while(sd_cmd(CMD1, 0) != 0);
33
  //deselect
34
  //...
35
}

Ich sende CMD0 also so oft, bis das Responsebyte stimmt. Ich kann mich 
glaube ich daran erinnern, dass die Karte in der ersten Schleife auch 
einen Moment verharrte. Vielleicht mal ausprobieren.

von holger (Gast)


Lesenswert?

>Hat er doch. Ich benutze bei meinem AVRNAS auch Spannungsteiler, und das
>Dingen fluppt sehr gut...

Schön für dich. Was macht das Teil bei 8MHz SPI ?
Bringen alle SD/MMC wirklich mindestens 3V am Ausgang
damit der AVR das auch noch als High erkennt ?



von Simon K. (simon) Benutzerseite


Lesenswert?

holger wrote:
> Schön für dich. Was macht das Teil bei 8MHz SPI ?

Läuft. Als Spannungsteiler benutze ich 1k8/3k3 Ohm

> Bringen alle SD/MMC wirklich mindestens 3V am Ausgang
> damit der AVR das auch noch als High erkennt ?

Jo.

von holger (Gast)


Lesenswert?

>> Bringen alle SD/MMC wirklich mindestens 3V am Ausgang
>> damit der AVR das auch noch als High erkennt ?

>Jo.

Sorry, das wusste ich nicht ;)

Welche ALLE SD/MMC schaffen das bei dir ?

von Simon K. (simon) Benutzerseite


Lesenswert?

holger wrote:
> Welche ALLE SD/MMC schaffen das bei dir ?

Versteh ich jetzt nicht. Wenn die Betriebsspannung 3,3V ist, dann wird 
ein High-Pegel heutzutage auch etwa um 3,3V liegen...

von holger (Gast)


Lesenswert?

>Versteh ich jetzt nicht. Wenn die Betriebsspannung 3,3V ist, dann wird
>ein High-Pegel heutzutage auch etwa um 3,3V liegen...

Versteh ich jetzt auch nicht, das es immer wieder Probleme
mit diesen Primitiv-Schaltungen gibt. Das ist mir völlig
unverständlich !?

Meine positiv Liste mit richtigen Pegelkonvertern:

MMC
===
Canon 16MB
extrememory 32MB
SanDisk  128MB
MMC plus extrememory 256MB PREMIUM
MAXflash 1GB MMC PLUS

SD
==
Mini SD Nokia 64MB
SD takeMS 128MB
SD Toshiba 128MB
SD SanDisk 256MB
SD hama  256MB
SD NoName 60x 512MB
SD Qimonda 512MB
SD Kingston 512MB
SD Stone 1GB
SD extreMEmory   1GB PERFORMANCE
SD CnMemory   1GB Firstclass Silver 60x
SD memorex 2GB
SD NoName   2GB XF00068850  (Reichelt)

SDHC Toshiba 4GB

10 Stück davon habe ich selbst ausprobiert, der
Rest wurde als positiv gemeldet.

von Thilo M. (Gast)


Lesenswert?

> Bringen alle SD/MMC wirklich mindestens 3V am Ausgang
> damit der AVR das auch noch als High erkennt ?

Ich hatte in meinem ersten Layout ärgerlicherweise auch in der MISO - 
Leitung einen Spannungsteiler drin, hat nicht die Bohne gestört, hat 
trotzdem einwandfrei funktioniert. :)

von gast (Gast)


Lesenswert?

ich bin grad auch dabei ne sd/mmc karte anzusteuern. außer der karte und 
nem resettaster hängt im prinzip nix am µc. steck ich die karte rein und 
drücke reset bekomme ich auf den initbefehl auch ne falsche antwort. 
erst nach dem zweiten reset läuft alles ohne problem. keine ahnung warum 
und ich hab schon alles ausprobiert um das zu ändern. ohne erfolg.
das mit den pegelwandlern halte ich für nicht notwendig. bei mir läuft 
das mit spannungsteiler und 10Mhz SPI-frequenz ohne probleme

von Johannes (Gast)


Lesenswert?

@fubu1000: Ja, das wäre Nett, wenn du mir dein Assemblerprogramm mal zum 
Testen geben könntest.
@Thilo M.: Bei mir ist der MISO Eingang direkt mit der Karte verbunden.

Ich glaube nicht, dass das Problem in meiner Software zu suchen ist, da 
ich ja Befehle senden kann und auch die zu erwarteden Antworten von der 
Karte bekomme. Das Problem ist nur, dass die Karte nicht aus ihrem 
Idle-Zustand heraus will.
Ich benutze SD-Karten der Firma Kingston und Jenoptik

von Thilo M. (Gast)


Lesenswert?

>Bei mir ist der MISO Eingang direkt mit der Karte verbunden.

Bei mir jetzt auch ;)
Wollte nur sagen dass der µC-Eingang schon recht kleine Spannungen als 
high erkennt. Muss mal testen wo die Grenzen sind (ob's Datenblatt recht 
hat) ..

von Simon K. (simon) Benutzerseite


Lesenswert?

gast wrote:
> ich bin grad auch dabei ne sd/mmc karte anzusteuern. außer der karte und
> nem resettaster hängt im prinzip nix am µc. steck ich die karte rein und
> drücke reset bekomme ich auf den initbefehl auch ne falsche antwort.
> erst nach dem zweiten reset läuft alles ohne problem. keine ahnung warum
> und ich hab schon alles ausprobiert um das zu ändern. ohne erfolg.
> das mit den pegelwandlern halte ich für nicht notwendig. bei mir läuft
> das mit spannungsteiler und 10Mhz SPI-frequenz ohne probleme

Wie schon gesagt, es kann sein, dass man CMD0 in einer Schleife so oft 
senden muss, bis die SD Karte aus dem Idle heraus ist. Ich weiß es aber 
nicht mehr, es stand aber in meinem Code drin (oben). Und das beste: 
Dieser Code funktioniert.

von gast (Gast)


Lesenswert?

@simon küppers: bei mir aber nicht. ich hab CMD1 in ner schleife, so 
dass es öfter gesendet wird, und diese schleife schonmal bis 100 
gesetzt. immer das gleiche, erst nach dem zweiten reset gehts. vieleicht 
liegts an der karte

von Daniel S. (dschwab)


Lesenswert?

Hallo

Euer Initialisierungsproblem liegt darin, dass z.T. selbst die gleiche 
Karte z.T. unterschiedliche Zeiten hat beim initialisieren. Entweder 
nimmt man es sehr gemütlich, oder man wartet so lange, bis der Befehl 
die korrekte Antwort zurück gibt. In der Funktion MMC_0_Init(void) (C 
Code fast am anfang der Seite) kannst du sehen, dass max. 255 mal das 
Kommando gesendet wird. Da kam es schon mal vor, dass der Befehl 7mal, 
1mal, 30mal aufgerufen wird.

Genauso gibt es Fehler, wenn du eine Card detect Funktion einbaust und 
man die Karte zu initialisieren beginnt, wenn der Benützer gerade die 
Karte einlegt. Da heisst es ebenfalls Geduld. Entweder nicht sofort die 
Karte zu Initialisieren oder man lässt ein paar dummy Daten länger über 
den SPI zur Karte senden um die Karte in den SPI Modus zu schalten. 
Beides bewirkt eine Verzögerung.

Sollte die initialisierung fehlschlagen, unbedingt mit dem SPI Modus 
umschalten wieder beginnen. Gasz billige Karten, schaffen ab und zu 
nicht mal das und dann kann man lange versuchen zu initialisieren.

Sollte jemand auch ein Filesystem verwenden, dann die Karte auf keinen 
Fall mit Wi***ws Formatieren. Nimm Li**x, dann ist auch ein rechter MBR 
(Master Boot Record) drauf. Sonst gibt es so Geduldspiele wie: such den 
Anfang der Partition. Je nach OS Version ist es etwas besser oder 
schlechter.

Gruss, Daniel

von fubu1000 (Gast)


Lesenswert?

hallo johannes,
sry das ich mich jezt erst wieder melde, hatte viel zu tun.
wenn du noch interressiert bist, dann schreib deine email addresse hier 
ins forum. dann kann ich dir den code schicken und womöglich 
weiterhelfen!!!
gruss

von Johannes (Gast)


Lesenswert?

@Daniel Schwab:

Ich habe versucht den Befehl CMD1 über 65536 mal zu senden und es kommt 
nichts bei heraus..

@fubu1000:

meine EMail Adresse : Johannes-Thull@web.de

von Matze (Gast)


Lesenswert?

Hallo,

hab ein ganz ähnliches Problem:

Die hardwaremäßige Anbindung scheint zu funktionieren (zumindest lässt 
sich den Signalen gut hinterheroszillographieren), aber:

Auf CMD0 antwortet meine SD-Karte (1GB, Platinum, quasi NoName von 
Reichelt) mit 00000101, also "Idle" und "Illegal Command".

Sowohl das ausgehende CMD0, als auch die Antwort kann ich mit dem 
Oszillographen beobachten und habe die Bits von Hand nachgezählt - die 
stimmen mit dem überein, was mein Atmega168 behauptet.

Habt Ihr einen Verdacht, woran es liegen könnte, dass die Karte nicht 
mag?

Danke

Mathias

von Johannes (Gast)


Lesenswert?

@Matze:

Um CMD0 zu senden musst du $40 an die SD karte senden, für CMD1 
$41..usw!

hast du das bedacht?

von Uwe (Gast)


Lesenswert?

Hi!
ich hatte mal das selbe Problem nachdem ein falscher Befehl ,durch ne 
kalte Lötstelle,gesendet wurde. Aus Verzweiflung habe ich sie in den PC 
gesteckt, die Eigenschaften und den Inhalt betrachtet -nichts 
auffälliges.
Danach in meinen Kartenhalter und was soll ich sagen, die Karte geht 
heute noch->?????
Zu den Pegelkonvertern, manche Karten haben so schwache Ausgänge das der 
AVR, wenn an 5V, die Signale manchmal nicht sauber empfängt. Seit ich 
einen drinn habe, habe ich auch keine Probleme mehr.
Was mir an deinem Code auffällt, du sendest kein Dummybyte bevor du die 
Daten empfangen willst. Auch ans Ende jeder Übertragung gehören min 8 
Takte besser 16.
Der SPI Takt darf, bis CMD1 ok ist, nicht über 400kHz sein.

Viel Erfolg, Uwe

von holger (Gast)


Lesenswert?

@ uwe

>Was mir an deinem Code auffällt, du sendest kein Dummybyte bevor du die
>Daten empfangen willst. Auch ans Ende jeder Übertragung gehören min 8
>Takte besser 16.

Meinst du Dummybytes wenn CS High ist ?
Die braucht man nicht.

von Hagen R. (hagen)


Lesenswert?

aha, da sagen die SD Card Datenblätter was anderes. Ist das jetzt von 
dir nur eine Feststellung aus der Praxis oder hats du dazu offizielle 
Datenblätter die das besagen ?

Gruß Hagen

von holger (Gast)


Lesenswert?

>aha, da sagen die SD Card Datenblätter was anderes.

Ok, beim Init vor CMD0 muss man das natürlich.
Danach aber nicht mehr.

An welcher Stelle sagen die Datenblätter das man
bei CS High noch takten MUSS ? Es ist wohl eher
das man takten KANN ! SPI halt. Alles andere wäre
bei einer SPI Schnittstelle schlicht Unsinn.

>Ist das jetzt von dir nur eine Feststellung aus der Praxis oder
>hats du dazu offizielle Datenblätter die das besagen ?

Das ist eine Feststellung aus der Praxis. Siehe oben.
18 verschiedene getestete Karten und keine Probleme
wenn man bei CS High KEINE Dummys sendet.

Hast du eine Karte wo es nicht so ist ?
Verkauf sie mir !

von Hagen R. (hagen)


Lesenswert?

Ganz einfach, die SD Karte ist vom Takt abhängig, der Takt steuert die 
interne FSM. Werden zb. Daten geschrieben so benötigt die Karte einen 
Takt und der muß par Zyklen nach dem Senden des Datenblockes 
weiterlaufen.

So habe ich die Datenblätter interpretiert.
In meiner mmcSendCommand() Funktion sende ich bei deaktiviertem CS der 
Karte erstmal 8 Bits, danach aktiviere ich die SD Karte und sende den 
Kommandoblock. Beim Warten auf das Response sende ich weiter  immer 0xFF 
und warte auf die Antwort der SD Karte. Also VOR und NACH dem 
Kommandoblock lege ich schon einen Takt für die Karte an. Und.. das 
funktioniert bei mir mir mit allen Karten die ich testen konnte, ohne 
die üblichen Fehler bei anderen Libs.

Gruß Hagen
1
#ifdef MMC_CALC_CRC7
2
uint8_t mmcCRC7(uint8_t crc, uint8_t data) {
3
4
    crc ^= data;
5
    unsigned char poly = 0x89;
6
    for (unsigned char i = 8; i > 0; i--) {
7
      if ((crc & 0x80) != 0) crc ^= poly;
8
      crc <<= 1;
9
    }
10
    return(crc);
11
}
12
#endif
13
14
uint8_t mmcCommand(uint8_t command) {
15
16
    return(mmcCommandParam(command, 0, 0));
17
}
18
19
uint8_t mmcCommandExpected(uint8_t command, uint16_t expected) {
20
21
    return(mmcCommandParam(command, 0, expected));
22
}
23
24
uint8_t mmcCommandParam(uint8_t command, uint32_t address, uint16_t expected) {
25
26
    uint8_t result;
27
    uint8_t data = 0xFF;
28
29
    mmcDisable();        // CS=HIGH
30
    mmcSend(data);
31
32
    uint8_t crc = 0;
33
#ifdef MMC_CALC_CRC7
34
    crc = mmcCRC7(crc, command);
35
    crc = mmcCRC7(crc, (uint8_t)(address >> 24));
36
    crc = mmcCRC7(crc, (uint8_t)(address >> 16));
37
    crc = mmcCRC7(crc, (uint8_t)(address >> 8));
38
    crc = mmcCRC7(crc, (uint8_t)(address));
39
    crc = crc | 1;
40
#else
41
    crc = 0x95;
42
#endif
43
44
45
    mmcWait();
46
    mmcEnable();
47
    for (uint8_t i = MMC_COMMAND_TRIALS; i > 0; i--) {
48
      mmcSend(command);
49
      mmcWait();
50
      mmcSend((uint8_t)(address >> 24));
51
      mmcWait();
52
      mmcSend((uint8_t)(address >> 16));
53
      mmcWait();
54
      mmcSend((uint8_t)(address >> 8));
55
      mmcWait();
56
      mmcSend((uint8_t)(address));
57
      mmcWait();
58
      mmcSend(crc);
59
      mmcWait();
60
61
      for (uint8_t j = MMC_RESPONSE_TRIALS; j > 0; j--) {
62
        mmcSend(data);
63
        mmcWait();
64
        result = mmcRead();
65
        if ((result & 0x80) == 0) break;
66
      }
67
68
      if ((result >= (uint8_t)(expected >> 8)) && (result <= (uint8_t)(expected))) break;
69
70
      mmcDisable();
71
      mmcSend(data);
72
      for (uint8_t j = MMC_COMMAND_DELAY -1; j > 0; j--) {
73
        mmcWait();
74
        mmcSend(data);
75
      }
76
      mmcWait();
77
      mmcEnable();
78
    }
79
    return(result);
80
}
81
82
uint8_t mmcInit(void) {
83
84
    MMC_PORT |= (1 << MMC_CS);
85
    MMC_DDR |= (1 << MMC_CS) | (1 << MMC_SCLK) | (1 << MMC_MOSI);
86
    MMC_DDR &= ~(1 << MMC_MISO);
87
    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
88
    SPSR = 0;
89
90
    uint8_t result = mmcCommandExpected(0x40, 0x0101);
91
    if (result <= 0x01) {
92
      for (uint8_t i = 20; i > 0; i--) {
93
        result = mmcCommand(0x41);
94
        if (result != 0x01) break;
95
      }
96
      if (result == 0x00) {
97
        SPCR = (1 << SPE) | (1 << MSTR);
98
        SPSR = (1 << SPI2X);
99
        #ifdef MMC_CALC_CRC7
100
        result = mmcCommandParam(0x7B, 1, 0x0000);  // activate CRC checking
101
        #endif
102
        if (result == 0) {
103
          result = mmcReadCSD(MMC_Buffer);
104
105
        }
106
      }
107
    }
108
    mmcDisable();
109
    return(result);
110
}

von holger (Gast)


Angehängte Dateien:

Lesenswert?

>Ganz einfach, die SD Karte ist vom Takt abhängig, der Takt steuert die
>interne FSM. Werden zb. Daten geschrieben so benötigt die Karte einen
>Takt und der muß par Zyklen nach dem Senden des Datenblockes
>weiterlaufen.

Nein, muss er nicht. Das ist bei SPI NICHT erforderlich.

>Und.. das
>funktioniert bei mir mir mit allen Karten die ich testen konnte, ohne
>die üblichen Fehler bei anderen Libs.

Welche Karten ? Hast du eine Liste ?

Meine Lib ist keine der üblichen. Siehe Anhang.
Lesen und schreiben von MMC/SD macht OHNE
diese Dummybytes keine Probleme. Bei immerhin 18 Karten.
Da sind ziemlich alte Dinger dabei und moderne SDHC Karten.

von Hagen R. (hagen)


Lesenswert?

Stop mal in MMCCommand hast du

1.) SPI_WRITE(DUMMY_WRITE); noch bevor du das Commando Byte sendest und 
dabei schon CS=LOW !? Das widerspricht den SD Card Spezifikationen, also 
das CS schon LOW ist beim DUMMY_WRITE.
2.) du wartest auf das Response Byte par Sourcezeilen später. Da sendest 
du auch solange das DUMMY_BYTE bis du ein Response bekommst

Und davon rede ich die ganze Zeit. Du musst vor und nach dem Senden des 
Commandos auf die SD Karte warten und dabei muß die SD Karte weiterhin 
getaktet werden, weshalb auch in deinen Code, weiterhin getaktet wird.

Und auch bei deiner Funktion MMCReadSector machst du das gleiche !
Auch da taktest du die SD Karte solange bis ein Timeout entsteht oder 
das gültig Response der SD Karte empfangen wurde. Diese Dummy Writes 
sind essentiell nur dazu da das die FSM der SD Karte weiterarbeiten 
kann. Denn die  SD Karte hat keinen eigenen Takt aber ehrwohl einen 
Prozessor, sogar Kryptoprozessor. Der braucht nen Takt ;)

Nicht verärgert sein, aber ist das der Source den du anhängen wolltest ? 
"Kennst du deinen Source ?" könnte man versucht sein zu fragen ;=)

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

>Welche Karten ? Hast du eine Liste ?

Nöö kann aber versuchen eine zu machen, dazu muß ich nur alle Karten 
einsammeln. Auf alle Fälle einige Nonames von eBay, überwiegend SanDisk 
ab 16Mb aufwärts und par Kingsten (sind doch die grünen) und 
ExtremMemory, die ich aber nur noch für die DigiCam benutzen werde, wäre 
mir zu schade.
Ach und Nomame MMC Karte, die habe ich geschrottet, bei meinen ersten 
Tests ;)

Es ist aber kein Indiz das eine Library sauber funktioniert. Ich halte 
mich an die Datenblätter des Standards und das hat gereicht.

So, jetzt kommt die Frage ob ich das Datenblatt noch habe. Sicherlich, 
muß aber erstmal suchen immerhin war das vor 2 Jahren.

Gruß hagen

von Hagen R. (hagen)


Angehängte Dateien:

Lesenswert?

Absatz 4.5. Clock Control im ProdManual von Sandisk Version 1.9.

Anhängen werde ichs hier nicht, es ist eh schon schwierig legal an diese 
Datenblätter zu kommen.

In meinem Code sende ich bei CS=HIGH 8 Bits bevor ich das eigentliche 
Kommando sende. Laut Spezifikation sollten diese 8Bits aber nach eienr 
Aktion gesendet werden. Das spare ich mir.

D.h die besagten 8 Bits bei CS=HIGH die man der Karte nach einer Sequenz 
senden sollte mache ich VOR dem senden des nächsten Kommandos.

Gruß Hagen

von holger (Gast)


Lesenswert?

@ Hagen
>"Kennst du deinen Source ?" könnte man versucht sein zu fragen ;=)

Scheinbar nicht :(

Du hast natürlich recht. Ich hab Unsinn erzählt.
Dieses Dummy vor dem Kommando hatte ich mal entfernt.
Funktioniert bei MMC und einigen noname SD übrigends hervorragend.
Hab ich gerade noch mal ausprobiert. Bei ner Sandisk und Toshiba SD
gehts so gar nicht. Irgendwann muss ich das Dummy wieder eingebaut
haben. Und dann sofort vergessen.

Es funktioniert aber bisher problemlos das Dummy Byte zu senden
ohne die CS Leitung nach der Response auf High zu ziehen.
Vieleicht sollte man nach der Response CS aber besser doch
auf High ziehen, um Ärger mit empfindlichen Karten zu vermeiden.
Meine Karten tun es auch so, aber ich schreibs mir mal auf !

Danke für den Tritt in den Hintern ;)
 Holger

von Hagen R. (hagen)


Lesenswert?

Ja CS ist anscheindend egal, es zählen nur die Takte auf der 
Clockleitung. Allerdings sollte Dummy=0xFF sein. Laut SD Spec, irgendso 
ein inoffizielles Datenblatt, sollte aber CS=HIGH sein, um unnötige 
Fehlcodierungen des Commandobytes zu verhindern.

Gruß Hagen

von Matze (Gast)


Lesenswert?

@Johannes: Ja, dass jeder Befehl im Prinzip |0x40 genommen werden muss 
ist beachtet - hab es mit den Quellcodes von Ulrich Radig und Roland 
Riegel ausprobiert (die tun das ja alles korrekt und sind sehr gut 
nachvollziehbar).

Hab in einem Handy noch ne RS-MMC gefunden, die freundlich und zufrieden 
antwortet - es scheint also ein Problem mit genau dieser SD-Karte zu 
geben - hab mir erstmal noch eine Sandisk-Karte bestellt und werde 
schauen, was die so macht.

Wenn die auch nicht klappt, dann muss ich wohl mal drüber nachdenken, ob 
ich ein Hardwareproblem habe (Spannungsversorgung oder sowas - die 
RS-MMC sind ja im möglichen Spannungsbereich etwas toleranter...).

Oder fällt Euch noch irgendwas ein?

Mathias

von Chris (Gast)


Lesenswert?

Hallo,

habe demnächst auch vor erste Versuche mit SD-Karten zu machen. Eine 
Frage dazu:

Man ließt immer wieder von SD-Karten die mit bestimmten Sourcecodes 
nicht funktionieren usw. Gibt es eigentlich Sourcecode der mit allen 
Karten arbeitet? Oder anders ausgedrückt: Gibt es auch kommerzielle 
Software (in Digi-Cams, Kartenlesern usw.) die nicht mit allen SD-Karten 
funktioniert?

Ciao
Chris

von Johannes (Gast)


Lesenswert?

Ich habe nun mal eine Karte der Marke "Intenso" versucht, und habe die 
Karte erfolgreich initialisiert. Deshalb muss es einfach an den Karten 
liegen und nicht an meiner Software.

@Chris: Ich denke der Königsweg für SD-Karten auszulesen geht über den 
normalen SD-Karten-Bus. Ich denke nicht, dass die SD-Reader an meinem Pc 
über die langsamere SPI-Schnittstelle kommunizieren, aber das wäre dann 
noch auszuprobieren ;-)

von Obelix (Gast)


Lesenswert?

Ich habe bis jetzt keine SD- oder MMC-Karte, die bei meiner Hard- und 
Software nicht lief. Ich habe aber keine Lust, mir von allen Herstellern 
alle Typen zu Kaufen.

von Johannes (Gast)


Lesenswert?

@Obelix: könntest du mir deinen Code mal geben?

von Bernhard S. (bernhard)


Lesenswert?

Hallo,

die "normalen" SD-Karten kann ich initialisieren. Hab den 
Assembler-Code,
hoffentlich halbwegs verständlich, hier veröffentlicht.

Beitrag "SD-Karte Initialisierung Read Write FAT ATmega8 (Assembler)"


Jedoch eine 4GB (SDHC) Karte lässt sich nicht initialisieren.

CMD0 wird korrekt beantwortet aber bei ACMD41 bzw. CMD1 lautet die 
Antwort immer x01.

Werden die SDHC Karten anders initialisiert ?


Bernhard

von neuling (Gast)


Lesenswert?

hallo, unten in de pdf sind die zeiten beschrieben für das ansprechen 
der mmc-karte

http://www.mikrocontroller.net/attachment/24687/spitiming.pdf

wer kann mir diese werte unten mal erläutern, verstehe die nicht ganz 
mit fixed und multiples usw.

8x4= fixed multiple of 8 clocks
8x= multiples of  8 clock
8 =number of dummy clocks
8 =number of clocks

danke

mfg

von Martin (Gast)


Lesenswert?

> 8x4= fixed multiple of 8 clocks

Es ist eine feste Anzahl an Tackten vorgeschrieben und zwar muss die 
Anzahl ein vielfaches von 8 sein. In diesem Fall 8 x 4 = 32

> 8x= multiples of  8 clock

Die Tackt anzahl muss ein vielfaches von auch sein. Wieviel mal 8 Tacke 
ist egal.

> 8 =number of dummy clocks

8 Tackte bei denen aber keine Daten gesentet oder empfangen werden.

> 8 =number of clocks

Feste Anzahl von 8 Tackten.

von neuling (Gast)


Lesenswert?

jup, danke.

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.