www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SD card: STOP_TRANSMISSION beim MULTIPLE BLOCK WRITE


Autor: Dimitri M. (dimitri)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Das Wichtigste vorweg: Multiple Block Write gelingt sehr gut und ich 
bekomme sagenhafte 2.5 MBytes/s! Ich tickse das FAT-System aus, indem 
ich die leere Karte mit grösseren ebenfalls leeren Dateien fülle und mit 
dem Startsektor der ersten Datei beginne. Mein Chip ist PIC24Hxxxx.

Was nicht geht, ist, den Datentransfer zu stoppen, ohne ohne die 
Brechstange zu verwenden, sprich die Karte neu initialisieren zu müssen. 
Irgendwie will die Karte weder STOP_TRANS_TOKEN (0xFD) noch CMD12 
fressen. Ich wüsste auch nicht, welchen Responce zu erwarten, wenn sie 
es fressen würde.

In so mancher Dokumentation steht geschrieben, dass STOP_TRANS_TOKEN für 
SPI-Modus angedacht, während CMD12 für dem SD-Modus bestimmt ist. Die 
anderen unterscheiden gar nicht dazwischen.

Ähm... ja...

Gruss
Dimitri

Autor: Daniel R. (zerrome)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich mache das bei Multiblock so wie in der Spezifikation, und das 
klappt, wenn die Karte das halt unterstützt.

Erstmal muss das block alligned sein. Also nur nach einem 512 Byte block 
klappt das.
Dann wie folgt:
unsigned char cmd[]={0x40+13,0x00,0x00,0x00,0x00,0xFF}; // cmd13 response R2

mmc_write_byte(0xFD);  // stop token

mmc_wait_ready();

response=mmc_write_command (cmd); // cmd13, response R2, alles ok?

mmc_wait_ready();

denke die Funktionen sind sprechend genug :)

Grüße Daniel

Autor: Dimitri M. (dimitri)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Daniel,

hier ist meine bis auf den Abschluss lauffähige Variante mit 
freundlicher Unterstützung von Microchip ;-) :
unsigned int MDD_SDSPI_SetStartSector(DWORD sector_addr)
{
    MMC_RESPONSE    response; 

    // send the cmd
  if (gSDMode == SD_MODE_NORMAL)
    response = SendMMCCmd(WRITE_MULTI_BLOCK,(sector_addr << 9));
  else
    response = SendMMCCmd(WRITE_MULTI_BLOCK,(sector_addr));
        
  // see if it was accepted
  if(response.r1._byte != 0x00) return 0;  // failed
  
  return 1;              // success
}

unsigned int MDD_SDSPI_SectorMultiWriteDMA(DWORD sector_addr, BYTE* buffer, unsigned int SectorsToWrite)
{
    WORD            index, k, m, Timeout = 0;
    BYTE            data_response;
    MMC_RESPONSE    response; 
    //BYTE            status = TRUE, ByteToWrite, StayInTheLoop = 1;
  unsigned int j;

  if(MDD_SDSPI_SetStartSector(sector_addr))
  {
    for(j = 0; j < SectorsToWrite; j++)
    {
      CloseSPIM();
      OpenSPIM(SYNC_MODE_CRAZY);

      DMA0CONbits.CHEN = 1; 
      DMA3CONbits.CHEN = 1;
      _LATA1 = 1;
      // Force First word after Enabling SPI
        DMA0REQbits.FORCE = 1;
      // wait until the first transfer is finished
        while(DMA0CONbits.CHEN == 1);
      _LATA1 = 0;
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      DMA3CONbits.CHEN = 0;
      
      CloseSPIM();
      OpenSPIM(SYNC_MODE_SLOW);

            data_response = MDD_SDSPI_ReadMedia();  //Read response
            
      if((data_response & 0x0F) != DATA_ACCEPTED) return(0);
      else
      {
        index = 0;  //using i as a timeout counter
        do  //Wait for write completion
                {
                    SPIBUF = 0xFF;
                    while(!SPISTAT_RBF);
                    data_response = SPIBUF;
                    index++;
                } while((data_response == 0x00) && (index != 0));

                  //if(index == 0) return(j);
            }
            //mSend8ClkCycles();
      //if(status == FALSE) break;
      
        }
  }  
    //SD_CS = 1;

    return(SectorsToWrite);
} //end SectorMultiWrite
In der ersten for-Schleife starte in den DMA-Transfer für SPI. Ich 
schicke 1 + 512 + 2 Bytes, wobei das erste Byte 
DATA_START_MULTIBLOCK_TOKEN ist, gefolgt von 512 Bytes Daten und 2 Bytes 
Pseudo-CRC. Danach wird DMA deaktiviert, damit ich SPI wieder manuell 
ansteuert kann. Ich sende eine Anfrage, ob meine Daten akzeptiert 
wurden, und bekomme eine saubere Antwort (DATA_ACCEPTED = 0b101). Dann 
wird die SPO-Leitung der Karte gepolt, bis sie wieder hochgeht. Je nach 
Alter der Karte dauert es unterschiedlich lang. Aber OK. Ich musste 
feststellen, dass ich das Dummy-Byte (mSend8ClkCycles) eigentlich nicht 
brauche, um im Geschäft zu bleiben.

Meine Frage ist nun, wo soll ich STOP_TRANS_TOKEN reinwürgen und welche 
Reaktion darauf von der Karte zu erwarten wäre. Es muss doch danach 
sofort möglich sein, SendMMCCmd(WRITE_MULTI_BLOCK,(sector_addr << 9)) zu 
senden, so dass es akzeptiert wird.

Nach jedem Block während des Schreibens geht die SPO-Leitung der Karte 
recht schnell hoch (not busy). Muss ich denn mit längeren Wartezeiten 
rechnen, wenn ich den Transfer abschliesse?

Ich sehe, Du schickst, CMD13, um den Status zu ermitteln, stimmt's?

Gruss
Dimitri

P.S. nop's sind nötig, weil offensichtlich DMA0CONbits.CHEN bereits auf 
Null gesetzt wird, noch before das letzte Byte vollständig übertragen 
wurde. Wenn ich DMA3CONbits.CHEN = 0 sofort ausführe, schneidet es mir 
die letzten Bits ab.

Autor: Dimitri M. (dimitri)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube, ich hab's :-)

Nachdem der letzte Block der Sequenz akzeptiert wurde und die Leitung 
wieder auf HIGH gegangen ist, macht man Folgendes:
WriteSPIM(STOP_TRAN_TOKEN); // 1 Byte : 0xFD
mSend8ClkCycles(); // <= wichtig!
index = 0;  //using i as a timeout counter
do  //Wait for write completion
{
  SPIBUF = 0xFF;
  while(!SPISTAT_RBF);
  data_response = SPIBUF;
  index++;
} while((data_response == 0x00) && (index != 0));
Wichtig ist, nach dem Senden von STOP_TRAN_TOKEN ein Dummy-Byte zu 
senden, denn erst dann geht die Leitung runter auf BUSY und kann gepolt 
werden.

Hier auf der Seite 6 bekommt man ungefähr mit, was geschieht:
http://forums.parallax.com/forums/attach.aspx?a=32012

Je nach Karte dauert's dann um 2 ms, bis die restlichen Daten geflasht 
sind.

Gruss
Dimitri

Autor: Daniel R. (zerrome)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sieht ja spannend aus :)

Ja ich frage mit cmd13 ob die Karte alles flaschen konnte und ob alles 
Ok gelaufen ist. Das ist so weit ich weiß die korrekte Methode bei 
multiblock-write Operationen bzw. beim beenden einer solchen.

Ja, nach dem stop-tran-token müsste ein dummy byte rein.


Grüße Daniel

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.