Forum: Mikrocontroller und Digitale Elektronik Und nochmal SD-Karte.


von H.Joachim S. (crazyhorse)


Angehängte Dateien:

Lesenswert?

Benutze mehr oder weniger den Code von Stefan Seegel, ein paar 
Anpassungen auf CodeVision.

unsigned char mmc_init(void)
{       char cmd[] = {0x40,0x00,0x00,0x00,0x00,0x95};    //CMD0
  //cbi(MMC_DDR, SPI_MISO);  //MMC Data Out -> Input
  //sbi(MMC_DDR, SPI_CLK);  //MMC Clock -> Output
  //sbi(MMC_DDR, SPI_MOSI);  //MMC Data In -> Output
  //sbi(MMC_DDR, MMC_CS);  //MMC Chip Select -> Output

  //sbi(MMC_PORT, MMC_CS);  //MMC Chip Select -> High (deactivate)

  //SPCR = 1<<SPE | 1<<MSTR | SPI_INIT_CLOCK; //SPI Enable, SPI Master 
Mode
  //SPSR = SPI_DOUBLE_SPEED << SPI2X;

  unsigned char i;
  unsigned char res;
  for (i=0; i<15; i++)          //Pulse 80+ clocks to reset MMC
       {mmc_send_byte(0xFF);
        }


  res=mmc_write_cmd(cmd); //store result of reset command, should be 
0x01
  SPI_CS_SDcard=1; //MMC Chip Select -> High (deactivate);
  mmc_send_byte(0xFF);



  if (res != 0x01) {  //Response R1 from MMC (0x01: IDLE, The card is in 
idle state and running the initializing process.)
    return(1);
  }

  cmd[0]=0x41;
  cmd[5]=0xFF;

  i=0;

  while((mmc_write_cmd(cmd) != 0) && (i < 0xff)) {
    SPI_CS_SDcard=1; //MMC Chip Select -> High (deactivate);
    mmc_send_byte(0xFF);
    i++;
  }
  SPI_CS_SDcard=1; //MMC Chip Select -> High (deactivate);

  if (i < 0xff) {
    SPCR = 1<<SPE | 1<<MSTR | SPI_CLOCK; //SPI Enable, SPI Master Mode
    return(0);
  }

  return(2);
}

Funktioniert auch - aber nur mit kleinen Karten (128MB, 256MB). Mit 1 
oder 2GB aber nicht.
Der erste Teil init funktioniert bei allen Karten (antwortet mit 0x01), 
der zweite Teil aber nicht.
Die kleinen Karten mit return 0, die grossen mit return 2.
Was kann das sein? Habe in den letzten Tagen soviel gelesen und 
probiert, aber keine Lösung gesehen.
Hardware: Mega32A mit 11.0592MHz, alles auf 3,3V, also keine 
Pegelwandler. Spannungseinbrüche gibt es keine, SPI-Takt sind 172kHz

Schaltbild ist für ne micro-SD, Platinen sind aber noch nicht da, also 
Luftverdrahtung für normale SD.

Irgendwelche Ideen?

von H.Joachim S. (crazyhorse)


Lesenswert?

Hm, hat wohl doch nichts mit der Kapazität zu tun.
Ein bisschen in der Kartenkiste gekramt:

Panasonic SD 1GB: keine Reaktion
no-name 4GB SD: ok
Verbatim 2GB micro-SD: keine Reaktion, mehrere ausprobiert
Kingston micro-SD 2GB: eine funktioniert, die andere nicht
Sandisk micro-SD 1GB: funktioniert

Im Kartenleser alle völlig unauffällig.
So richtig zufriedenstellend ist das nicht :-(

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Du führst den 2. Teil nicht oft genug aus. Außerdem vermisse ich CMD55 
vor CMD41. Diese Kommandos musst Du ständig wiederholen und auf die 
Rücknahme des Busy warten. Manche Karten benötigen dafür etliche 10 ms.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?


von H.Joachim S. (crazyhorse)


Lesenswert?

http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf

Ich wollte eigentlich nur einen billigen grossen Speicher :-), da 
bekommt man ja graue Haare, wenn man sich die spec komplett durchlesen 
will..

i hatte ich schon deutlich erhöht, brachte gar nichts. Wenn es 
funktioniert, lag i immer bei 1 oder 2. Ob man dann bis 255 oder 1000 
oder 2000 wartete, änderte gar nichts.

Aber jetzt bin ich dem Problem auf der Spur:
Bei den fraglichen Karten funktioniert es nur nicht direkt nach power 
on. Macht man dann noch mal nen reset des MC - alles gut.

brown out steht auf 2,7V, Ext. crystal, startup 16k + 64ms (habe ich bis 
dahin erhöht, ohne Erfolg)

Ebensowenig brachte das Warten vor mmc_init (habe ich bis auf 1000ms 
erhöht), Porteinstellungen und SPI sind i.O.

#asm("sei")
delay_ms (100);
temp=mmc_init();

if (!temp)
   {temp=mmc_read_cid(buffer);
    for (loop=0;loop<16;loop++) printf ("%02X ",buffer[loop]);
    printf ("    ");
    temp=mmc_read_csd(buffer);
    for (loop=0;loop<16;loop++) printf ("%02X ",buffer[loop]);
    printf ("\r\n");
    } else printf ("Kartenfehler");
while (1);

Stromversorgung sollte potent genug sein (12V Schaltnetzteil + 
MIC2940-3,3)

verrückt das ganze...

von H.Joachim S. (crazyhorse)


Lesenswert?

Und so funktionierts, mmc_init() zweimal aufrufen.
Klappt mit allen fraglichen Karten, und wahrscheinlich werde ich das 
erstmal so lassen. Es sei denn, einer hat ne zündende Idee, woran es 
liegt.
Ganz befriedigend ist das nicht, normalerweise rächen sich solche 
Ungenauigkeiten irgendwann :-)

#asm("sei")
temp=mmc_init();
temp=mmc_init();

if (!temp)
   {temp=mmc_read_cid(buffer);
    for (loop=0;loop<16;loop++) printf ("%02X ",buffer[loop]);
    printf ("    ");
    temp=mmc_read_csd(buffer);
    for (loop=0;loop<16;loop++) printf ("%02X ",buffer[loop]);
    printf ("\r\n");
    } else printf ("Kartenfehler");


while (1);

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Komisch. Bei mir funktionieren alle Karten auch nach Power on. 
Vielleicht geht´s bei Dir deswegen nach der 2. Init, weil Du CMD41 nur 
einmal sendest. Du mußt das aber immer wieder senden, solange bis Du im 
Response eine 0 erhältst. Und nicht vergessen, immer nochmal mindestens 
8 Clocks zu geben, wenn die Karte nach einem Zugriff per /CS abgewählt 
wurde.

von H.Joachim S. (crazyhorse)


Lesenswert?

Und noch ne (wahrscheinlich blöde) Frage:
Adressiert man logische oder physikalische Blocks? Also, wenn ich Block 
0 beschreibe mmc_write_sector via  CMD24 - landet das dann tatsächlich 
in physikalischen Block 0 oder ist da die "Intelligenz" der Karte 
dazwischen?
Ich muss 512 Byte/s schreiben, also eigentlich recht wenig. Wenn ich 
zusätzlich in Block0 die gerade aktive Adresse schreibe, wären diese 
Zellen innerhalb eines Tages platt.
Bitte um Nachsicht, habe noch nie was mit SD-Karten gemacht :-)

von Sascha W. (sascha-w)


Lesenswert?

H.joachim Seifert schrieb:
> Und noch ne (wahrscheinlich blöde) Frage:
> Adressiert man logische oder physikalische Blocks?
physikalische

> Also, wenn ich Block
> 0 beschreibe mmc_write_sector via  CMD24 - landet das dann tatsächlich
> in physikalischen Block 0
ja

> oder ist da die "Intelligenz" der Karte
> dazwischen?
nein

> Ich muss 512 Byte/s schreiben, also eigentlich recht wenig. Wenn ich
> zusätzlich in Block0 die gerade aktive Adresse schreibe, wären diese
> Zellen innerhalb eines Tages platt.
sicher nicht, denn der Controller der Karte verteilt die Daten mit einem 
Wear Leveling so auf den Flashspeicher, das dort alle Blöcke gleichmäßig 
"abgenutzt" werden. Wie oft willst du denn den Block pro Tag 
überschreiben?

> Bitte um Nachsicht, habe noch nie was mit SD-Karten gemacht :-)
macht nix

Sascha

von Hast es jetzt fertig? (Gast)


Lesenswert?

H.joachim Seifert schrieb:
> Hm, hat wohl doch nichts mit der Kapazität zu tun.

Beitrag "SD-Karte als Kondendensator"

scnr

von H.Joachim S. (crazyhorse)


Lesenswert?

Sascha Weber schrieb:
> sicher nicht, denn der Controller der Karte verteilt die Daten mit einem
> Wear Leveling so auf den Flashspeicher, das dort alle Blöcke gleichmäßig
> "abgenutzt" werden.

Genau das meinte ich mit "Intelligenz" der Karte. Zugriff auf Block0 
landet also auch in dieser Betriebsweise nicht ständig auf denselben 
Speichzellen - das wars, was ich wissen wollte.

>Wie oft willst du denn den Block pro Tag
> überschreiben?
Dieser Block würde jede Sekunde beschrieben werden, wenn ich dort die 
aktuelle Schreibadresse hinterlege, also knappe 100.000/Tag.
Gerätchen wird öfters ein- und ausgeschaltet werden, und das direkte 
Suchen nach dem nächsten freien Block dauert bei 100kB/s und einer 
halbwegs gefüllten Karte viel zu lange.
Aber ich kann das ja auch kombinieren, beispielsweise nur jeden 
256.Block zählen und dann dort suchen, wo es weitergeht mit schreiben.
Ich hätte mal einen kleinen FRAM mit vorsehen sollen :-)

von Sascha W. (sascha-w)


Lesenswert?

H.joachim Seifert schrieb:
>>Wie oft willst du denn den Block pro Tag
>> überschreiben?
> Dieser Block würde jede Sekunde beschrieben werden, wenn ich dort die
> aktuelle Schreibadresse hinterlege, also knappe 100.000/Tag.
das würde ich der Karte nicht auf Dauer zumuten wollen

> Gerätchen wird öfters ein- und ausgeschaltet werden, und das direkte
> Suchen nach dem nächsten freien Block dauert bei 100kB/s und einer
> halbwegs gefüllten Karte viel zu lange.
> Aber ich kann das ja auch kombinieren, beispielsweise nur jeden
> 256.Block zählen und dann dort suchen, wo es weitergeht mit schreiben.
schon eher eine brauchbare Lösung

> Ich hätte mal einen kleinen FRAM mit vorsehen sollen :-)
oder eine RTC (eine Zeit braucht man eh oft), die haben meist einige 
Byte freien SRAM der dann Batteriegepuffert ist.

Sascha

von udo (Gast)


Lesenswert?

Sascha Weber schrieb:
>> Gerätchen wird öfters ein- und ausgeschaltet werden, und das direkte
>> Suchen nach dem nächsten freien Block dauert bei 100kB/s und einer
>> halbwegs gefüllten Karte viel zu lange.

es gibt doch einen einfachen algorithmus fuer das problem, der bei einer 
karte mit n speicherzellen nur log(n) zugriffe braucht

zuerst liesst du genau in der mitte der karte und weisst dann, ob die 
karte schon bis zur haelfte voll ist oder nicht. wenn ja, nimmst du dir 
die zweite haelfte vor, liesst dann die speicherzelle, die genau in der 
mitte liegt und testest sie wieder nach dem gleichen prinzip. im andern 
fall machst du das gleiche mit der ersten haelfte.. damit beginnt das 
spiel von vorne, .... klar geworden???

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.