Ich möchte die do-Schleife durch den dma-Aufruf ersetzen, die
Kotrollabfrage und deselect weglassen da die dma im Hintergrund läuft
und die Funktion mit RES_OK beenden. Kann das funktionieren oder ist der
Ansatz völlig daneben?
In der Funktion xmit_datablock wird nach 512bytes eine CRC abgefragt.
Kann man das weglassen oder muss die dma auf 512bytes reduziert werden?
@ Grundschüler (Gast)
>Ich möchte die do-Schleife durch den dma-Aufruf ersetzen, die>Kotrollabfrage und deselect weglassen da die dma im Hintergrund läuft>und die Funktion mit RES_OK beenden. Kann das funktionieren oder ist der>Ansatz völlig daneben?
Das klappt nur, wenn andere, nachfolgende Funktion NICHT davon ausgehen,
dass der Datenblock schon vollständig übertragen wurde.
Ich denke eine derartig parallele Verarbeitung durch die DMA ist nicht
soo einfach einzubauen. Schau dir am besten die Beispiele von ELM Chan
an, dort ist vielleicht auch ein DMA-Beispiel dabei.
Danke für die Antwort. Es ist tatsächlich nicht so einfach. Ich versuche
es jetzt erst einmal mit streamwrite. Wenn das klappt, kann man relativ
einfach auf dma umstellen:
1
//++
2
// Cluster pre-allocation (to prevent buffer overrun on streaming write)
>Ist das ungefähr richtig?
Nein, voll daneben. Die Karte verlangt ein Protokoll
beim schreiben das einzuhalten ist. Einfach mal 1000
Byte per SPI da reinzublasen wird nicht gehen.
@ Grundschüler (Gast)
>Ist das ungefähr richtig?
Du willst an der Lib vorbei einfach Daten auf den SPI schreiben?
Vergiss es!
http://elm-chan.org/fsw/ff/00index_e.html
Schreib na Anfrag dort im Forum oder frag den meister persönlich. Ich
sage immer noch, dass ein umstricken auf DMA mit quasi paralleler
Datenübertragung eine grundlegende Überarbeitung der ganzen Lib nötig
macht, zumindest großer Teile davon.
@ Marcel (Gast)
>http://mikrocontroller.bplaced.net/wordpress/?page_id=621
Hmm, aber hast du die Lib derartig geändert, dass DMA parallel zum
aufrufenden Programm läuft? Sprich, ich rufe f_write mit z.B. 10kB auf
und die Funktion kommt nach kurzter Zeit zurück und die DMA überträgt
die Daten dann parallel zur CPU, die erstmal andere Sachen macht? Denn
DAS war ja die zentrale Frage des OP.
"Einfach" die Daten per SDIO oder meinetwegen auch DMA zu übertragen und
dann in den Funktionen genauso auf das Ende der Übertragung zu warten
ist ja kein allzugroßer Gewinn und eher einfach. Man kommt bestenfalls
sehr nah an die Bruttodatenrate von 25 Mbit/s ran, was ~3MB/s sind. Hast
du ja anscheinend mit 2,4 MB/s beim Lesen. 0,5MB/s schreiben scheint
noch etwas mau.
@Grundschüler (Gast)
>das streamwrite Beispiel ist direkt von elm chan.
Aber nicht mit deinem reingefrickelten Zeug!
http://elm-chan.org/fsw/ff/en/lseek.html>Was meint elm chan mit streamwrite?
Das man einen relativ konstanten, dauerhaften Datenstrom schreiben will.
Damit zwischendrin die Karte bzw. die Lib nicht ins Stottern kommt, weil
sie neue Cluster für die Datei suchen und in die FAT eintragen muss,
macht man das VORHER. Sprich, man legt eine (leere) Datei mit der
maximalen Größe an und schreibt dann ohne Unterbrechung mit den normalen
Funktionen die Daten dort rein. Mit der Option fast seek geht es sogar
noch besser, welche noch zusätzliche Infromationen im Prozessor
speichert, um noch einfacher ohne Unterbrechung die Daten schreiben zu
können (Cluster Link Table, damit kennt man ALLE Cluster bzw. Sektoren
der Datei und kann direkt reinschreiben, ohne in der FAT auf der
SD-Karte suchen zu müssen, das bringt vor allem bei recht vollen,
fragmentierten SD-Karten viel).
>Es gab diesen Thread:>Beitrag "Geschwindigkeitsfrage AVR auf SD">so völlig abwegig scheint das direkte Schreiben in eine bestehende Datei>nicht zu sein.
So wie du es vorhast geht es aber nicht.
Die Sektoren einer Datei müssen nicht hintereinander liegen.
Und das SD Karten Protokoll muss eingehalten werden.
Da beisst die Maus keinen Faden ab. Der grösste Block
den du per SPI und DMA übertragen kannst ist 512Byte.
Mehr schaffst du nur mit einem echten SDIO Controller.
Und selbst da musst du aufpassen das die Daten auch wirklich
hintereinander auf der Karte liegen.
holger schrieb:> Die Sektoren einer Datei müssen nicht hintereinander liegen.
Ich habe noch nicht aufgegeben. Auf einer frisch formatierten Karte
werden 10 FAt-Dateien angelegt. Da müssten die Sektoren doch dann
hintereinanderliegen. Der Anfangssektor Fil->dsect wird ausgelesen und
in den Dateien gespeichert.
In diese Dateien müsste ich doch dann mit cmd24/cmd25 beginnend ab dem
gespeicherten Anfangssector hintereinander Schreiben können. Welchen
Stäte hat die sd-Karte nach f-close? idle oder native oder spi?
1
for(i=0;i<10;i++){//10 leere Dateien anlegen
2
res=f_mount(&xFatFs,"",0);// Give a work area to the default drive
wird etwas direkt auf die sd geschrieben. Allerdings gibt es beim
Zurücklesen eine noch unerklärliche Verschiebung (n-1)*2:
Schreiben: 0,1,2,3,4,5,6...
Lesen: 0,0,2,4,6,8,10...
Warum????
31049 soll der Anfangssektor Fil->dsect einer vorher angelegten Datei
sein. Es wird aber offenbar außerhalb dieser Datei geschrieben.
Warum????
Bin für jeden Hinweis dankbar...
>Warum????
Woher soll das jemand wissen?
Dein xmit_datablock() kennt niemand.
rcvr_datablock() kann auch keiner sehen.
>Bin für jeden Hinweis dankbar...
Schau in disk_read(), disk_write() oder besser benutze sie.
Je nach SD Karte muss die Sektornummer noch mit 512
multipliziert werden.
>Je nach SD Karte muss die Sektornummer noch mit 512>multipliziert werden.
Nachtrag: Was für eine SD Karte benutzt du?
Bei SDHC wird die Sektornummer nicht mit 512 multipliziert.
holger schrieb:> Schau in disk_read(), disk_write() oder besser benutze sie.
Ziel ist die Ausgliederung des Schreibvorgangs aus dem
CPU-Programmablauf per DMA.
Problem ist, dass nach Übertragung eines 512 Byte Datenpaketes + Senden
von Bytes für die Dataresponse auf die Ready-Meldung der Karte gewartet
werden muss. Wenn es gelänge dieses Warten in eine Interruptroutine
auszulagern, die dann die DMA aufruft, müsste es mit einer
DMA-Übertragung klappen.
@ Grundschüler (Gast)
>Ziel ist die Ausgliederung des Schreibvorgangs aus dem>CPU-Programmablauf per DMA.>Problem ist, dass nach Übertragung eines 512 Byte Datenpaketes + Senden>von Bytes für die Dataresponse auf die Ready-Meldung der Karte gewartet>werden muss. Wenn es gelänge dieses Warten in eine Interruptroutine>auszulagern, die dann die DMA aufruft, müsste es mit einer>DMA-Übertragung klappen.Beitrag "Re: sd-Karte Elm Chan DMA"
> Wenn es gelänge dieses Warten in eine Interruptroutine> auszulagern, die dann die DMA aufruft, müsste es mit einer> DMA-Übertragung klappen.
Bei meinem Projekt (ARM7) bin ich so vorgegangen:
1. Initialisierung der Übertragung eines 512-Bytes Blocks.
2. Übertragung des Blocks per DMA
3. DMA setzt Flag nach der Beendigung der Übertragung.
4. Deinitialiserung der Übertragung eines 512-Bytes Blocks.
Punkt 4 kann in einer Interruptroutine, die vom Flag in Punkt 3
ausgelöst wird, bearbeitet werden.
Wenn man nur die Zugriffe f_read bzw. f_write umstrickt, KÖNNTE es
einfacher werden. Am grundlegenden Ansatz, dass man gezielt mit Know How
in der Lib ändern muss, ändert sich nichts. Man braucht eine
Statemachine in der ISR sowie in den Funktionen. Ausserdem braucht
man einen Mechanismus, um zu erkennen, ob der aktive Schreibvorgang
schon abgeschlossen ist und ein neuer gestartet werden kann. Machbar,
aber einiges an Arbeit. Mit einem vermurksten Zuggiff auf interne
Funktion der Lib ausserhabl der Funktionen kriegt man das nicht solide
hin.
Proband schrieb:> Bei meinem Projekt (ARM7) bin ich so vorgegangen:
Das wäre genau das, was ich seit längerer Zeit suche. Hast du das
irgendwo veröffentlicht?
Falk Brunner schrieb:> Beitrag "Re: sd-Karte Elm Chan DMA"
Cluster Link habe ich probiert, ich brauche aber eine Lösung, in der der
Schreibvorgang nicht über die CPU gesteuert wird.
@ Grundschüler (Gast)
>Das wäre genau das, was ich seit längerer Zeit suche. Hast du das>irgendwo veröffentlicht?Beitrag "Re: sd-Karte Elm Chan DMA">Cluster Link habe ich probiert, ich brauche aber eine Lösung, in der der>Schreibvorgang nicht über die CPU gesteuert wird.
Um Cluster Link geht es doch erstmal gar nicht! Sondern um die
Übertragung der Sektoren parallel zum restliche Programm!
Ich würde so vorgehen. Die Funktion f_write() Schritt für Schritt
analysieren und dann so zerlegen, dass sie als Statemachine in der ISR
läuft, welche nach jeder Übertragung eines Sektors per DMA aufgerufen
wird. D.h. den seqentiellen Aublauf incl. Wartezeiten in States ohne
Warten umsetzen. Der Aufruf von f_write() generiert nur ein Startsignal
bzw. macht halt die Initialaisierung der Datenübertragung. Die
Steuerbefehle vor bzw. zwischen den Datenübertragungen würde ich nicht
per DMA machen sondern klassisch per einzelner SPI-Operation, diese
natürlich dann auch in der Statemachine im Interrupt.
Wenn das dann läuft, kann man f_read() ähnlich leicht umstellen.
Falk Brunner schrieb:> ähnlich leicht...
bis auf diese Einschätzung einverstanden.
f_write schreibt letzlich nach cmd25 mit xchg_spi_(multi) und
wait_ready.
diesen Schreibvorgang kann ich analysieren und durch DMA ersetzen. Ob
meine Fähigkeiten reichen, dass dann wieder in f_write einzubinden, habe
ich Zweifel. Der erste Schritt - direktes Schreiben per DMA - ist
jedenfalls überschaubar. Die Funktion
/* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */
17
}while(d!=0xFF&&Timer2);/* Wait for card goes ready or timeout */
18
19
return(d==0xFF)?1:0;
20
}
soll also durch eine Interruptroutine ersetzt werden. Ein Timer, der
nach Beendigung der DMA-Übertragung gestartet wird, bei Ablauf der
normalen Verarbeitungszeit mit d = xchg_spi(0xFF) schaut, ob SSPDR!=
0xFF ist und dann die nächste DMA-Übertragung startet.
Vielleicht hilft auch der Hinweis auf rot_rdq() weiter
@ Grundschüler (Gast)
>> ähnlich leicht...>bis auf diese Einschätzung einverstanden.
Naja, geschiebe ist sowas halt schnell ;-)
>f_write schreibt letzlich nach cmd25 mit xchg_spi_(multi) und>wait_ready.
Wahrscheinlich.
>diesen Schreibvorgang kann ich analysieren und durch DMA ersetzen.
Das allein reicht nicht! Denn f_write wartet ja in seinem Verlauf auf
das Ende der Transaktion. Das geht dann aber nicht!
>Ob>meine Fähigkeiten reichen, dass dann wieder in f_write einzubinden, habe>ich Zweifel. Der erste Schritt - direktes Schreiben per DMA - ist>jedenfalls überschaubar. Die Funktion>soll also durch eine Interruptroutine ersetzt werden.
Reicht nicht und ist sinnfrei. Du willst ja, das f_write in minimaler
Zeit wieder verlassen wird und im Hintergrund per DMA die Daten
übertragen werden und ab und an mal per Interrupt der Prozess von
f_write vorwärts kommt.
>Ein Timer, der>nach Beendigung der DMA-Übertragung gestartet wird, bei Ablauf der>normalen Verarbeitungszeit mit d = xchg_spi(0xFF) schaut, ob SSPDR!=>0xFF ist und dann die nächste DMA-Übertragung startet.
Nein. Einen Timer brauchst du eher nicht, wohl aber die Statemachine.
>Vielleicht hilft auch der Hinweis auf rot_rdq() weiter
???
Was ist das?
Ein anderer Ansatz wäre die Verwendung eines präemtiven RTOS, dann kann
man f_write in einem andern Thread laufen lassen, das ist dann nahezu so
parallel wie die Interruptlösung. Aber auch dort braucht man dann
zwischen deinem Hauptthead und dem SD-Kartenthread eine Kommunikation
incl. Protokoll, wenn gleich auf einfacher Ebene. Der Vorteil wäre, dass
man das FatFs nicht anfassen muss, zumindest nur minimal. Man könnte die
Übertragung einzelner Sektoren per DMA laufen lassen und währenddessen
den Thread schlafen legen.
Überlegung zu Wait_ready:
statt d = xchg_spi(0xFF);
eine Übertragung des sspxDR per DMA auf PORT0. PORT0 lößt einen Interupt
aus, wenn PORT0.7 auf high(?) geht. Der Interrupt startet die nächste
DMA-Datenübertragung.
Problem ist der Verbrauch von 8Portpins, um nur ein Bit abzufragen.
Dafür könnte sowohl Datenübertragung wie auch Ready-Abfrage komplett per
DMA laufen. Gibt es eine andere Möglichkeit, um über den Wert von sspxDR
einen Interrupt auszulößen?
Im Beispiel von Chan für den LPC23xx wird auch DMA genutzt (allerdings
über das MCI Intterface).
http://elm-chan.org/fsw/ff/ffsample.zip
Ich habe das aber bisher nicht vernünftig in meine Anwendung integriert
bekommen. Muss aber nicht unbedingt etwas mit dem DMA zu tun haben, den
Verdacht hatte ich aber auch schon...
Siehe meinen Beitrag hier:
Beitrag "Re: LPC2378 SD-Karte blockiert Reset"
Horst schrieb:> Ich habe das aber bisher nicht vernünftig in meine Anwendung integriert
Du hast noch mehr als ich das Problem, dass LPC23xx - leider - ein
Nieschenprodukt ist, für das es aufgrund der geringen Zahl der Anwender
wenig Erfahrungsaustausch gibt. Wenn es dir nur auf die sd-Karte und
nicht auf sdio ankommt, könntest du den lpc17xx code von chan nehmen,
der funktioniert einwandfrei.
Bei der Aufdrößelung des SSP-codes habe ich ein Verständnisproblem mit
dem Fifo. Elm chan führt nach der Übertragung der 512 Datenbyte diese
Code-sequenz aus:
1
for(n=0;n<8;n++){
2
while(!(SSPxSR&SSPSR_RNE));
3
SSPxDR;
4
}
Hier soll wohl der fifo geleert werden. Warum? es werden doch
anschließend noch 2xCRC-Bytes und ein Response-Byte gesendet.
Was bewirkt SSPxDR;
Ist das identisch mit SSPxDR=0 ?
nach
while (!(SSPxSR & SSPSR_RNE)) ;
müsste der fifo doch leer sein?
Grundschüler schrieb:> Was bewirkt SSPxDR;> Ist das identisch mit SSPxDR=0 ?Nein. Das ist identisch mit:
1
voidfoo(void)
2
{
3
intdummy;
4
dummy=SSPxDR;/* Diese Beiden Zeilen */
5
//SSPxDR; /* sind identisch! */
6
}
Da wird einfach das register geleert und der gelesene Wert weggeworfen.
Und weil der Wert nicht gebraucht wird, legt er dafür halt keine extra
Variable an. Wie kommst du überhaupt zu der Annahme, das man ein
Datenregister dadurch leert, indem man etwas reinschreibt? Ein
schreiben führt in der regel dazu das etwas gesendet wird, und lesen
führt dazu, das das register geleert wird.
Grundschüler schrieb:> nach> while (!(SSPxSR & SSPSR_RNE)) ;> müsste der fifo doch leer sein?
Nope. In der Schleife wird das Status register (SSPxSR) abgefragt. Um
den fifo zu leeren must du das Daten register (SSPxDR) lesen.
Grundschüler schrieb:> for (n = 0; n < 8; n++) {> while (!(SSPxSR & SSPSR_RNE)) ;> SSPxDR;> }> Hier soll wohl der fifo geleert werden
Nein, der fifo wird geleert!
Grundschüler schrieb:> Hier soll wohl der fifo geleert werden. Warum? es werden doch> anschließend noch 2xCRC-Bytes und ein Response-Byte gesendet.
Frag doch einfach mal den ELM Chan, der wird dir das sagen können, was
er sich dabei gedacht hat.
Grundschüler schrieb:> das streamwrite Beispiel ist direkt von elm chan. Was meint elm chan mit> streamwrite?
Frag ihn doch einfach mal...
"Because I am always very busy, I cannot answer particular questions
quickly. If you have any question, please post it into BBS and somebody
might answer it." BBS: http://elm-chan.org/bbs/?lang=enGrundschüler schrieb:> Auf einer frisch formatierten Karte> werden 10 FAt-Dateien angelegt.
Es gibt keine Fat-Dateien! FAT ist das Dateisystem, und auf dem
Dateisystem kannst du Dateien anlegen, nicht mehr und nicht weniger!
Grundschüler schrieb:> Da müssten die Sektoren doch dann> hintereinanderliegen.
Wie kommst du zu dieser annahme?
Grundschüler schrieb:> Bei der Aufdrößelung [...] habe ich ein Verständnisproblem
Merkt man... und das nicht nur beim Code sondern auch bei anderen
sachen...
Kaj schrieb:> ... und das nicht nur beim Code sondern auch bei anderen> sachen...
Das sagt meine Frau auch immer, muss wohl was dran sein...
diese Erklärung von dir ist gut
dummy = SSPxDR; /* Diese Beiden Zeilen */
da kann ich was mit anfangen. Danke. Im Übrigen stelle ich hier Fragen,
weil ich etwas nicht weiß. Da du mich mit meinen Fragen an elm chan
verweist, scheinst du auch nicht allwissend zu sein.
Ich denke die Besonderheit beim Chan-Code ist, dass er den SSP-Fifo
einsetzt. Da ich in der Regel das Bussy-Bit und nicht das
Fifo-Empty-Bit abfrage, kann ich das Leeren des Fifo wahrscheinlich auch
weglassen.
Ebenso erschließt sich mir der Sinn des wechsels auf 16bit Modus nicht,
da nur 8bit Werte eingelesen werden, die auf den 16bit Modus umgestellt
werden müssen:
SSPxCR0 = 0x000F; /* Select 16-bit mode */
*buff++ = d >> 8;
*buff++ = d;
werde ich auch weglassen
>Es gibt keine Fat-Dateien! FAT ist das Dateisystem, und auf dem>Dateisystem kannst du Dateien anlegen, nicht mehr und nicht weniger!
Mit Fat-Dateien meine ich die Dateien, die mit dem Fat-System angelegt
sind. nicht mehr und nicht weniger!. Ich bemühe mich derzeit um die
reine Schreibfunktion ohne Fat.
>> Da müssten die Sektoren doch dann>> hintereinanderliegen.>Wie kommst du zu dieser annahme?
durch das Stellen von dummen Fragen habe ich inzwischen auch das Problem
der Claster-Ketten verstanden. die cluster einer mit Fat angelegten
Datei müssen nicht zwangsläufig hintereinanderliegen. Da ich ohne Fat
schreibe, interessiert mich das erstmal nicht. Wenn das Schreiben ohne
Fat mit DMA als erster Teilschritt funktioniert, kann man mit Auslesen
der cluster-Tabelle versuchen, das ganze wieder in das Fat-System zu
bekommen. Das ist aber noch ein sehr weiter Weg, den ich mir auch nicht
unbedingt zutraue.
Kaj schrieb:>>Was meint elm chan mit streamwrite?> Frag ihn doch einfach mal...
muss ich nicht, hat Falk weiter oben schon verständlich beantwortet. Es
wird anhand der cluster-Tabelle ohne Fat-Überbau direkt geschrieben.
Reicht mir aber nicht, weil der Schreibvorgang per DMA komplett im
Hintergrund laufen muss...
Es wäre schön, wenn man gleich in eine bestehende Datei schreiben
könnte. Dazu müsste man die Cluster link map table auslesen. Das
Beispiel von chan scheint sich auf ältere Programmversionen zu beziehen
und lässt sich leider nicht ohne weiteres umsetzen. Ist es schon mal
jemandem gelungen, eine link map erfolgreich auszulesen? Irgendwelche
Tips dazu?
1
/* Using fast seek feature */
2
3
DWORDclmt[SZ_TBL];/* Cluster link map table buffer */
4
res=f_lseek(fp,ofs1);/* This is normal seek (cltbl is nulled on file open) */
5
fp->cltbl=clmt;/* Enable fast seek feature (cltbl != NULL) */
Kaj schrieb:> Grundschüler schrieb:>> nach>> while (!(SSPxSR & SSPSR_RNE)) ;>> müsste der fifo doch leer sein?> Nope. In der Schleife wird das Status register (SSPxSR) abgefragt. Um> den fifo zu leeren must du das Daten register (SSPxDR) lesen.
Das Status-Register wird doch danach abgefragt ob das Flag
ReceivefifoNotEmpy=SSPSR_RNE gesetzt ist. Bei Bedingungseintritt für das
Verlassen der While-Schleife müsste der Fifo doch dann wohl leer sein?
falls es noch jemanden interessiert, cmd25 klappt jetzt auch per dma.
Allerdings habe ich inzwischen ein stm32f429-disco. Angesichts der
Möglichkeiten mit sdram und sdio/crc sind für mich die m3-Zeiten - so
schön sie auch im Vergleich zu den ebenfalls schon schönen AVR-Zeiten
auch waren - wohl vorbei.
Direktes Schreiben auf sd-Karte:
Mit f_write wird der Anfangssektor festgestellt. Mit f_lseek wird die
Fragmentierung festgestellt. Bei leerer Karte sind die meisten Dateien
nicht fragmentiert, d.h., 151 sektoren hintereinander.
Dann kann man mit cmd25 614400 Byte - oder mehr - in 512byte-Blöcken
hintereinander weg schreiben. Die Datei kann dann ganz normal geöffnet
werden.
// init_ssp0_2();//erforderlicher wechsel auf normale ssp
18
// xchg_spi(0xfd);
19
speedtest=TimeTick;
20
}
21
// break;
22
// }//switch
23
return;
24
}
Problem war der Wechsel zwischen DMA und normaler SSP
SSP-Einzelbefehle wie // xchg_spi(0xfc);//token_cmd25
führen zu Konflikten. deshalb musste der token in den dMA-Buffer
eingesetzt werden.
Geschwindigkeit mit DMA ca. 1,2 Mbyte/sec, ohne ca 0,45 MBYte/sec