Forum: Mikrocontroller und Digitale Elektronik sd-Karte Elm Chan DMA


von Grundschüler (Gast)


Lesenswert?

ich möchte per DMA jeweils 2560bytes auf der sd-karte speichern.

In der Funktion disk_write lautet der code bei chan
1
....
2
  else {        /* Multiple sector write */
3
    if (CardType & CT_SDC) send_cmd(ACMD23, count);  /* Predefine number of sectors */
4
    if (send_cmd(CMD25, sector) == 0) {  /* WRITE_MULTIPLE_BLOCK */
5
      do {
6
        if (!xmit_datablock(buff, 0xFC)) break;
7
        buff += 512;
8
      } while (--count);
9
      if (!xmit_datablock(0, 0xFD))  /* STOP_TRAN token */
10
        count = 1;
11
    }
12
  }
13
  deselect();
14
15
  return count ? RES_ERROR : RES_OK;  /* Return result */
16
}

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?

von Falk B. (falk)


Lesenswert?

@ 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.

von Grundschüler (Gast)


Lesenswert?

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) 
3
4
u32 PRE_SIZE=2*240*320;//153600bytes
5
res = f_open(&Fil, "testfile.h", FA_WRITE | FA_CREATE_ALWAYS);
6
res = f_lseek(&Fil, PRE_SIZE);   // Expand file size (cluster  //   
7
res = f_lseek(&Fil, 0); 
8
    //...  write data 
9
CS_LOW();
10
for (i=0;i<1000;i++){
11
SPDR=i;
12
while(!(SPSR & (1<<SPIF)));
13
}
14
CS_HIGH(); 
15
                                  // DATA_START and 
16
//res = f_truncate(&Fil);                    // Truncate unused area 
17
res = f_lseek(&Fil, 0);                    // Put file header 
18
res = f_close(&Fil);
19
20
//--

Ist das  ungefähr richtig?

von holger (Gast)


Lesenswert?

>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.

von Falk B. (falk)


Lesenswert?

@ 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.

von Marcel (Gast)


Lesenswert?


von Grundschüler (Gast)


Lesenswert?

holger schrieb:
> Nein, voll daneben.

das streamwrite Beispiel ist direkt von elm chan. Was meint elm chan mit 
streamwrite?

von Falk B. (falk)


Lesenswert?

@ 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.

von Falk B. (falk)


Lesenswert?

@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).

von Grundschüler (Gast)


Lesenswert?

es gab diesen Thread:
Beitrag "Geschwindigkeitsfrage AVR auf SD"
so völlig abwegig scheint das direkte Schreiben in eine bestehende Datei 
nicht zu sein.

von holger (Gast)


Lesenswert?

>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.

von Grundschüler (Gast)


Lesenswert?

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
3
res=f_open(&Fil, Dateiname, FA_WRITE | FA_CREATE_NEW);
4
res = f_lseek(&Fil, 300000);
5
res = f_lseek(&Fil, 0);
6
uitoa(kksectors,buffer,16);
7
//res = f_write(&Fil, &kksectors, 4, &bw);//Anfangssektor in Datei schreiben
8
res = f_write(&Fil, buffer, 4, &bw);//Anfangssektor in Datei schreiben
9
f_close(&Fil);
10
}

von Grundschüler (Gast)


Lesenswert?

ein kleiner Erfolg. mit
1
for(i=0;i<512;i++)buffer[i]=i;
2
res=send_cmd(CMD24,31049);//Datei test_000.txt
3
res=xmit_datablock(buffer,512);
4
//xmit_spi_multi(buffer,512);
5
for(i=0;i<512;i++)buffer[i]='a';
6
res=send_cmd(CMD17,31049);//Datei test_000.txt
7
res=rcvr_datablock(buffer,512);

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...

von holger (Gast)


Lesenswert?

>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.

von holger (Gast)


Lesenswert?

>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.

von Grundschüler (Gast)


Lesenswert?

holger schrieb:
> xmit_datablock()

sind original elm-chan-funktionen:
1
/*-----------------------------------------------------------------------*/
2
/* Receive a data packet from the MMC                                    */
3
/*-----------------------------------------------------------------------*/
4
5
static
6
int rcvr_datablock (  /* 1:OK, 0:Error */
7
  BYTE *buff,      /* Data buffer */
8
  UINT btr      /* Data block length (byte) */
9
)
10
{
11
  BYTE token;
12
13
14
  Timer1 = 200;
15
  do {              /* Wait for DataStart token in timeout of 200ms */
16
    token = xchg_spi(0xFF);
17
    /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */
18
  } while ((token == 0xFF) && Timer1);
19
  if(token != 0xFE) return 0;    /* Function fails if invalid DataStart token or timeout */
20
21
  rcvr_spi_multi(buff, btr);    /* Store trailing data to the buffer */
22
  xchg_spi(0xFF); xchg_spi(0xFF);      /* Discard CRC */
23
24
  return 1;            /* Function succeeded */
25
}

von Grundschüler (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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"

von Proband (Gast)


Lesenswert?

> 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.

von Falk B. (falk)


Lesenswert?

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.

von Grundschüler (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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.

von Grundschüler (Gast)


Lesenswert?

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
1
/*-----------------------------------------------------------------------*/
2
/* Wait for card ready                                                   */
3
/*-----------------------------------------------------------------------*/
4
5
static
6
int wait_ready (  /* 1:Ready, 0:Timeout */
7
  UINT wt      /* Timeout [ms] */
8
)
9
{
10
  BYTE d;
11
12
13
  Timer2 = wt;
14
  do {
15
    d = xchg_spi(0xFF);
16
    /* 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

von Falk B. (falk)


Lesenswert?

@ 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.

von Grundschüler (Gast)


Lesenswert?

Ü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?

von Horst (Gast)


Lesenswert?

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"

von Grundschüler (Gast)


Lesenswert?

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?

von Kaj (Gast)


Lesenswert?

Grundschüler schrieb:
> Was bewirkt    SSPxDR;
> Ist das identisch mit SSPxDR=0 ?
Nein. Das ist identisch mit:
1
void foo(void)
2
{
3
  int dummy;
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=en

Grundschü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...

von Grundschüler (Gast)


Lesenswert?

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...

von Grundschüler (Gast)


Lesenswert?

Der erste Datenblock komplett per DMA ohne delays im Hauptprogramm 
übertragen:
1
void DMA_IRQHandler(void)
2
{
3
  uint32_t regVal;
4
  regVal = LPC_GPDMA->DMACIntStat;
5
  if ( regVal ){//not error
6
   DMATCCount++;
7
  LPC_GPDMA->DMACIntTCClear = regVal;
8
9
  switch(DMA_STATUS){
10
  case 0://ready abfrage
11
    if(buffer[4]!=255){
12
      DMA3_transfer_from_SSP0_to_buffer(16);
13
      return;
14
    }else{//512 Databytes
15
      zl_bsy_rpt=DMATCCount;
16
      xchg_spi(0xfe);//token_cmd24
17
      DMA_STATUS = 1;
18
      DMA0_512bytes_transfer_to_SSP0(0,512); //buffer_offset,Anzahl_bytes
19
    }break;
20
  case 1://2xcrc
21
    DMA_STATUS = 2;
22
    DMA2_3bytes_transfer_to_SSP0();
23
    break;
24
  case 2://"fifo leeren" nur Wartezeit
25
    DMA_STATUS = 3;
26
    DMA3_transfer_from_SSP0_to_buffer(32);//rxfifo leeren
27
    break;
28
  case 3://response -wird nicht ausgewertet
29
    xchg_spi(0xFF);        // Receive data resp
30
    break;
31
  }
32
  }else{
33
34
  regVal = LPC_GPDMA->DMACIntErrStat;
35
  if ( regVal )
36
  {
37
  DMAErrCount++;
38
  LPC_GPDMA->DMACIntErrClr = regVal;
39
  }
40
  }
41
  return;
42
}

von Grundschüler (Gast)


Lesenswert?

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
    DWORD clmt[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) */
6
    clmt[0] = SZ_TBL;                      /* Set table size */
7
    res = f_lseek(fp, CREATE_LINKMAP);     /* Create CLMT */
8
    ...
9
    res = f_lseek(fp, ofs2);               /* This is fast seek */

von Grundschüler (Gast)


Lesenswert?

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?

von Grundschüler (Gast)


Lesenswert?

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.

von Grundschüler (Gast)


Angehängte Dateien:

Lesenswert?

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.

1
zl_Dateiname_plus1();
2
prepare_cmd25_write();
3
4
if(kkcltbl[2]==151){
5
6
u32 ii;
7
res=send_cmd(CMD25,kksectors);//Datei test_000.txt
8
TimeTick=0;
9
for(ii=0;ii<1200;ii++){//640x480x2=614400 Byte
10
11
abfr_busy();
12
xchg_spi(0xfc);
13
for(i=0;i<512;i++)xchg_spi(i);
14
xchg_spi(0xff);
15
xchg_spi(0xff);
16
for(i=0;i<9;i++)res=xchg_spi(0xff);
17
18
}
19
abfr_busy();
20
xchg_spi(0xfd);
21
speedtest=TimeTick;
22
23
lgi(1,1,speedtest);
24
}//151

von Grundschüler (Gast)


Lesenswert?

Problem sd_Karte mit DMA gelöst.
1
void DMA_IRQHandler(void){
2
  uint32_t regVal, x=0,tmp;
3
  regVal = LPC_GPDMA->DMACIntStat;
4
5
  LPC_GPDMA->DMACIntTCClear = regVal;
6
7
//  switch(DMA_STATUS){
8
//  case 1://startsequenz beendet
9
    abfr_busy();
10
    if(DMA_zl_blocks--){
11
      DMA_STATUS = 1;
12
//      xchg_spi(0xfc);//token_cmd25
13
      DMA0_from_buffer_to_SSP0_start(0,516); //buffer_offset,Anzahl_bytes
14
    }else{
15
      DMA_STATUS = DMA_STATUS_END;
16
//      LPC_SSP0->DMACR=0;// ->DMACR=2;//tx en//176x
17
//      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

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.