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


von Dimitri M. (dimitri)


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

von Daniel R. (zerrome)


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:
1
unsigned char cmd[]={0x40+13,0x00,0x00,0x00,0x00,0xFF}; // cmd13 response R2
2
3
mmc_write_byte(0xFD);  // stop token
4
5
mmc_wait_ready();
6
7
response=mmc_write_command (cmd); // cmd13, response R2, alles ok?
8
9
mmc_wait_ready();

denke die Funktionen sind sprechend genug :)

Grüße Daniel

von Dimitri M. (dimitri)


Lesenswert?

Hallo Daniel,

hier ist meine bis auf den Abschluss lauffähige Variante mit 
freundlicher Unterstützung von Microchip ;-) :
1
unsigned int MDD_SDSPI_SetStartSector(DWORD sector_addr)
2
{
3
    MMC_RESPONSE    response; 
4
5
    // send the cmd
6
  if (gSDMode == SD_MODE_NORMAL)
7
    response = SendMMCCmd(WRITE_MULTI_BLOCK,(sector_addr << 9));
8
  else
9
    response = SendMMCCmd(WRITE_MULTI_BLOCK,(sector_addr));
10
        
11
  // see if it was accepted
12
  if(response.r1._byte != 0x00) return 0;  // failed
13
  
14
  return 1;              // success
15
}
16
17
unsigned int MDD_SDSPI_SectorMultiWriteDMA(DWORD sector_addr, BYTE* buffer, unsigned int SectorsToWrite)
18
{
19
    WORD            index, k, m, Timeout = 0;
20
    BYTE            data_response;
21
    MMC_RESPONSE    response; 
22
    //BYTE            status = TRUE, ByteToWrite, StayInTheLoop = 1;
23
  unsigned int j;
24
25
  if(MDD_SDSPI_SetStartSector(sector_addr))
26
  {
27
    for(j = 0; j < SectorsToWrite; j++)
28
    {
29
      CloseSPIM();
30
      OpenSPIM(SYNC_MODE_CRAZY);
31
32
      DMA0CONbits.CHEN = 1; 
33
      DMA3CONbits.CHEN = 1;
34
      _LATA1 = 1;
35
      // Force First word after Enabling SPI
36
        DMA0REQbits.FORCE = 1;
37
      // wait until the first transfer is finished
38
        while(DMA0CONbits.CHEN == 1);
39
      _LATA1 = 0;
40
      asm volatile("nop");
41
      asm volatile("nop");
42
      asm volatile("nop");
43
      asm volatile("nop");
44
      asm volatile("nop");
45
      asm volatile("nop");
46
      asm volatile("nop");
47
      asm volatile("nop");
48
      asm volatile("nop");
49
      asm volatile("nop");
50
      asm volatile("nop");
51
      asm volatile("nop");
52
      asm volatile("nop");
53
      asm volatile("nop");
54
      asm volatile("nop");
55
      asm volatile("nop");
56
      asm volatile("nop");
57
      asm volatile("nop");
58
      asm volatile("nop");
59
      asm volatile("nop");
60
      asm volatile("nop");
61
      asm volatile("nop");
62
      asm volatile("nop");
63
      asm volatile("nop");
64
      asm volatile("nop");
65
      asm volatile("nop");
66
      asm volatile("nop");
67
      asm volatile("nop");
68
      asm volatile("nop");
69
      asm volatile("nop");
70
      asm volatile("nop");
71
      asm volatile("nop");
72
      asm volatile("nop");
73
      asm volatile("nop");
74
      asm volatile("nop");
75
      asm volatile("nop");
76
      asm volatile("nop");
77
      asm volatile("nop");
78
      asm volatile("nop");
79
      asm volatile("nop");
80
      asm volatile("nop");
81
      asm volatile("nop");
82
      asm volatile("nop");
83
      asm volatile("nop");
84
      asm volatile("nop");
85
      asm volatile("nop");
86
      asm volatile("nop");
87
      asm volatile("nop");
88
      asm volatile("nop");
89
      asm volatile("nop");
90
      asm volatile("nop");
91
      asm volatile("nop");
92
      DMA3CONbits.CHEN = 0;
93
      
94
      CloseSPIM();
95
      OpenSPIM(SYNC_MODE_SLOW);
96
97
            data_response = MDD_SDSPI_ReadMedia();  //Read response
98
            
99
      if((data_response & 0x0F) != DATA_ACCEPTED) return(0);
100
      else
101
      {
102
        index = 0;  //using i as a timeout counter
103
        do  //Wait for write completion
104
                {
105
                    SPIBUF = 0xFF;
106
                    while(!SPISTAT_RBF);
107
                    data_response = SPIBUF;
108
                    index++;
109
                } while((data_response == 0x00) && (index != 0));
110
111
                  //if(index == 0) return(j);
112
            }
113
            //mSend8ClkCycles();
114
      //if(status == FALSE) break;
115
      
116
        }
117
  }  
118
    //SD_CS = 1;
119
120
    return(SectorsToWrite);
121
} //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.

von Dimitri M. (dimitri)


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:
1
WriteSPIM(STOP_TRAN_TOKEN); // 1 Byte : 0xFD
2
mSend8ClkCycles(); // <= wichtig!
3
index = 0;  //using i as a timeout counter
4
do  //Wait for write completion
5
{
6
  SPIBUF = 0xFF;
7
  while(!SPISTAT_RBF);
8
  data_response = SPIBUF;
9
  index++;
10
} 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

von Daniel R. (zerrome)


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

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.