Forum: Mikrocontroller und Digitale Elektronik FatFs + STM32F4 SDIO. DMA Speicheralignment


von M. Н. (Gast)


Lesenswert?

Guten Tag,

ich habe vor einiger Zeit selbst einen SDIO Unterbau für FatFS 
programmiert.
Ich würde nun gerne die Schreibgeschwindigkeit etwas erhöhen. Allerdings 
läuft mir ab einer SDIO_CLK von >= 8 MHz das Sende-FIFO leer.
(Wenn ich die Funktion mit höchster Optimierung kompiliere geht etwas 
mehr; Mit einer Assemblerroutine könnte man auch noch vielleicht etwas 
herausholen. Das ist aber alles irgendwie total gepfuscht)

Ansich könnte ich den HW_FLOW_CONTROL des SDIO Moduls nutzen, der die 
Clock Stoppt, wenn die FIFOs leer/voll werden. Allerdings funktioniert 
dieser Modus nicht korrekt. Die Karte ist danach immer 
kaputtgeschrieben. Ein Blick ins Errata-Sheet offenbart:
1
When enabling the HW flow control by setting bit 14 of the SDIO_CLKCR register to ‘1’,
2
glitches can occur on the SDIOCLK output clock resulting in wrong data to be written into
3
the SD/MMC card or into the SDIO device. As a consequence, a CRC error will be reported
4
to the SD/SDIO MMC host interface (DCRCFAIL bit set to ‘1’ in SDIO_STA register).
5
6
 Do not use the HW flow control. Overrun errors (Rx mode) and FIFO underrun (Tx mode)
7
should be managed by the application software.

Ich schreibe das SDIO FIFO monentan immer mit 8 vorgepufferten 32-bit 
worten voll, sobald dafür genügend Platz verfügbar ist. Das ist nicht 
optimal alles über die CPU zu schaufeln. Und genau hier kommt jetzt mein 
Problem:

Ich würde sehr sehr gerne den DMA des STMs nutzen um die Daten zu 
schreiben, allerdings ist das mit FatFS nicht möglich.

1) Der DMA erfordert, dass die 32 bit Worte auch 32-bit "aligned" sind.
2) wenn im Burst Modus betrieben (wie von ST im Reference manual 
beschrieben), darf der Burst keine 1K-Speichergrenze überschreiten, da 
ein solcher Zugriff nicht auf dem internen AHB Bus möglich ist.

Beides ist bei der Nutzung von FATFs nicht garantiert.
Die Beispiele, die ich online finde, ignorieren gekonnt dieses Problem 
und nutzen einfach den DMA.

Hat sich damit schon jemand beschäftigt? Interpretiere ich das falsch? 
Ich würde ungern auf den DMA verzichten, da dieser notwendig ist die 
Datenrate zu erreichen.

von Nico W. (nico_w)


Lesenswert?

Hast dir schonmal ChibiOS angesehen? Zumindest nutze ich das mit fatfs, 
SDIO und DMA. Allerdings auf nem F103. Wie ich Giovanni aber kenne, 
sollte das auf dem F4 auch laufen.


Die HAL von ChibiOS läuft unter Apache 2.0. Kann man also gemütlich in 
allen Projekten nutzen.

von M. Н. (Gast)


Lesenswert?

Nico W. schrieb:
> Hast dir schonmal ChibiOS angesehen?

Habe mir gerade die DMA Config angeschaut. Es wird der DMA für 
Wort-größe konfiguriert.

Laut ST muss in diesem Fall der Speicher-Puffer Word-aligned sein. Ich 
sehe aber auch hier keine Garantie dafür.

Ausschnitt aus dem Reference Manual:
1
When the data width (programmed in the PSIZE or MSIZE bits in the DMA_SxCR register)
2
is a half-word or a word, respectively, the peripheral or memory address written into the
3
DMA_SxPAR or DMA_SxM0AR/M1AR registers has to be aligned on a word or half-word
4
address boundary, respectively.

Dieser Beitrag zeigt ebenfalls eine Config (zum Lesen). Diese schlägt 
bei mir jedoch fehl, sobald der Speicherpuffer nicht mehr aligned ist.
Beitrag "Re: STM32 SDIO Blöcke lesen"

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Elm chans FatFS kopiert um wenn es nicht Sektoraligned ist was du 
schreiben willst.
Ein SD Karten Sektor ist ja meist 512Byte aligned (oder eben mehr).
http://elm-chan.org/fsw/ff/doc/appnote.html
Unter Performance Effective File Access

von Johannes S. (Gast)


Lesenswert?

Ich benutze SDIO auch mit DMA, die Initialisierung stammt aus dem HAL 
Code:
https://github.com/JojoS62/COMPONENT_SDIO/blob/master/TARGET_STM/TARGET_STM32F4/sdio_device.c
In dem Repo sind auch Tests, die sind alle positiv durchgelaufen.
Am Anfang hatte ich auch das Polling benutzt, aber ebenfalls Probleme 
mit Buffer over/underrun Fehlern. Vor allem wenn der Code mit Debug 
Option übersetzt wurde.
In den Tests sind statische Buffer, die werden immer Word aligned sein. 
In anderem Code hole ich den Datenbuffer per malloc, da weiss ich nicht 
ob der immer word aligned ist, das könnte ich mal mit einer krummen 
Adresse testen. Du meinst doch das das ein Problem ist?

von M. Н. (Gast)


Lesenswert?

Mw E. schrieb:
> Elm chans FatFS kopiert um wenn es nicht Sektoraligned ist was du
> schreiben willst.
> Ein SD Karten Sektor ist ja meist 512Byte aligned (oder eben mehr).

Du verwechselst hier den Sektor der SD karte mit dem Speicher des STMs.
Das Problem ist, dass der Speicherpuffer im Speicher des STMs zumindest 
4 byte (word) aligned sein muss. Bei der Nutzung von busts muss er sogar 
16 byte aligned sein und darf keine 1k Speichergrenze überschreiten.


In der Doku von FatFs steht (http://elm-chan.org/fsw/ff/doc/dread.html):
1
There are some considerations about the memory addres passed via buff. It is not that always aligned with the word boundary because the argument is defined as BYTE*.

Das ist genau das Problem. Meine Tests zeigen auch, dass das in der 
regel gut geht. Ich kann das aber auch so hinbasteln, dass der Puffer 
nicht aligned ist und dann knallt es.

von Niklas Gürtler (Gast)


Lesenswert?

M. H. schrieb:
> Bei der Nutzung von busts muss er sogar 16 byte aligned sein und darf
> keine 1k Speichergrenze überschreiten.

Nur einzelne Bursts dürfen die 1k-Grenzen nicht überschreiten; der ganze 
Transfer schon. IIRC ist das automatisch richtig wenn die Adresse 16Byte 
aligned ist.
Durch Implementierung eines eigenen FAT32-Treibers mit eigener Puffer 
Verwaltung kann man die DMA-Anforderungen erfüllen und hohe 
Geschwindigkeiten erreichen, beim Lesen und Schreiben. Das kann dank DMA 
sogar komplett parallel zum sonstigen Programmablauf laufen.

von M. Н. (Gast)


Lesenswert?

Niklas Gürtler schrieb:
> Durch Implementierung eines eigenen FAT32-Treibers

Richtig. Nur will ich ungern die Fat Library selber schreiben bzw den 
Code von FatFS anfassen. Die einzige Möglichkeit die mir einfällt, wäre 
tatsächlich voher zu Prüfen, ob der Puffer aligned ist. Wenn ja, dann 
DMA, ansonsten umkopieren oder langsamer über CPU ins SDIO schaufeln.

von Jim M. (turboj)


Lesenswert?

M. H. schrieb:
> Das Problem ist, dass der Speicherpuffer im Speicher des STMs zumindest
> 4 byte (word) aligned sein muss. Bei der Nutzung von busts muss er sogar
> 16 byte aligned sein und darf keine 1k Speichergrenze überschreiten.

Dann würde ich für die Read/Write Block Funktion einen passenen Block 
statisch anlegen und den benutzen wenn der übergebene Datenbereich nicht 
passt. Kostet dann halt ein zusätzliches memcpy().

von M. Н. (Gast)


Lesenswert?

Jim M. schrieb:
> Dann würde ich für die Read/Write Block Funktion einen passenen Block
> statisch anlegen und den benutzen wenn der übergebene Datenbereich nicht
> passt. Kostet dann halt ein zusätzliches memcpy().

Ja. Und den Nachteil, dass Multi-Block operationen nicht gehen bzw. nur 
wenn ich den Puffer auf mehrere Blöcke ausweite.

Ich verstehe nur nicht, warum das sämtliche Libraries inklusive von 
CubeMX etc mit DMA machen. Entweder funktioniert das dort durch Glück 
und ein wenig Magie, oder ich verstehe da etwas nicht richtig und mache 
mir umsosnt so nen Kopf. Habe halt gar keine Lust darauf, dass der code 
irgendwann versagt, nur weil irgendwo ein Puffer um ein Byte verrutscht.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

M. H. schrieb:
> Du verwechselst hier den Sektor der SD karte mit dem Speicher des STMs.
> Das Problem ist, dass der Speicherpuffer im Speicher des STMs zumindest
> 4 byte (word) aligned sein muss. Bei der Nutzung von busts muss er sogar
> 16 byte aligned sein und darf keine 1k Speichergrenze überschreiten.

Ne eigentlich verechsle ich da nichts.
Auf die SD Karte kann man nur Blockweise lesen/schreiben.
Wenn man nur einen Teil davon ließt/schreibt muss er eh den ganzen 
Sektor lesen und intern zwischenspeichern (dann verändern und 
zurückschreiben). DER Speicher muss aligned sein.

Bei der von mir verlinkten Beschreibung las sich das eben so als würden 
unalignde Schreibzugriffe kopiert, weils eh in den Sektorbuffer muss.

Daher merkt sich das FS einen Sektor zwischen, das ist ein großes Array 
in dem struct.
Das kannste ja mal alignen auf 16 o. 4 byte.
http://elm-chan.org/fsw/ff/doc/sfile.html
"BYTE    buf[FF_MAX_SS];" <- da mal ein gcc align attribute drauf werfen

Aber wenn er sich bei disk_read selber widerspricht ist das etwas doof.

M. H. schrieb:
> Meine Tests zeigen auch, dass das in der
> regel gut geht. Ich kann das aber auch so hinbasteln, dass der Puffer
> nicht aligned ist und dann knallt es.

Also wenn man bei f_write mal einen unaligned Pointer reinreicht?

von M. Н. (Gast)


Lesenswert?

Mw E. schrieb:
> Also wenn man bei f_write mal einen unaligned Pointer reinreicht?

Das hängt ein wenig davon ab, wie groß der Puffer ist. Und wie viel 
FatFs mit dem Dateisystem sonst noch zu tun hat bei der Operation. 
Prinzipiell hast du aber recht. Wenn du aber bspw. genau 512 Byte 
schreibst, dann geht der Puffer einfach durch.

Ich werde mich wohl mal durch den Code von FatFs wurschteln und schauen, 
ob es mit ein paar align-Attributen getan ist. Die Puffer, die ich in 
die Funktionen reingebe, kann ich ja bequem bestimmen.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

So siehts wohl aus, wenn der f_write eine Größe von vielfachen der SD 
Sektoren bekommt gehts 1zu1 durch. Wenn dann noch der Buffer unaligned 
ist krachts.

In der disk_read Beschreibung steht ja auch, dass man dafür sorgen soll, 
dass der Buffer dann aligned ist. Das kann durchaus fummlig werden wenn 
man in Dateien rumließt und structs füllen will.

Ansonsten noch was, weil ne Frage zum alignment von malloc aufkam:
https://en.cppreference.com/w/c/types/max_align_t

von M. Н. (Gast)


Lesenswert?

Naja.. ich werde mir das im Laufe der Woche mal anschauen und 
herumspielen.
aber ich gehe richtig in der Annahme, dass meine Überlegungen begründet 
sind, oder?

Ich war nämlich sehr verwirrt, dass das irgendwie niemanden interessiert 
hat bei den Implementierungen, die man so findet.

Mw E. schrieb:
> Ansonsten noch was, weil ne Frage zum alignment von malloc aufkam:
> https://en.cppreference.com/w/c/types/max_align_t

malloc verwende ich in diesem Projekt nicht. Da ist alles statisch :)

von Johannes S. (Gast)


Lesenswert?

wenn ich ein 'fread(fileBuffer, 1, 8*1024, f);' aufrufe dann sehe ich 
das schon beim _read() nur 1 kB Blöcke gelesen und umkopiert werden. Das 
muss ja schon die clib machen, ist diese Blockgröße auch konfigurierbar?
Da wird das Alignment Problem eliminiert, beim f_read im Chan Code 
werden auch nur 1 k Blöcke in einen fixen Buffer gelesen.

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.