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
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
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.