STM32F7 - DCache & DMA

OP #5256681
Lesenswert?

Grüß euch

Ich hab über die Weihnachtsfeiertage ein neues kleines Hobbyprojekt 
angefangen bei dem ich zum ersten Mal mit einem von STs (relativ) neuen 
F7 Prozessoren herumspielen darf.

Leider hab ich ein Problem damit den zur Verfügung stehenden Cache 
(Daten) voll auszunutzen, wenn ich gleichzeitig DMA Übertragungen 
tätigen will. Folgendes funktioniert nämlich schlichtweg nicht:
1
uint8_t x[] = {'a', 'b', 'c', 'd'}; // hier am Stack
2
cmd::Serial::transmitDma(&x[0], sizeof(x)); // Konfiguriert und startet DMA

Das Problem ist, dass x zwar eine Ram-Adresse bekommt, die Daten dort 
aber schlichtweg nie ankommen. Wie sich später herausstellte landet x 
zur Gänze im Cache! Jetzt dachte ich eigentlich, dass es unter anderem 
für genau solche Probleme die dmb/dsb-Instruktion gibt nur führen die 
leider nicht zu dem gewünschten Ergenis.

Sprich auch
1
uint8_t x[] = {'a', 'b', 'c', 'd'}; // hier am Stack
2
__DMB();
3
cmd::Serial::transmitDma(&x[0], sizeof(x)); // Konfiguriert und startet DMA

sendet alles andere nur nicht "abcd".


Die einzige Methode die ich ad-hoc gefunden hab ist, den Cache gänzlich 
via
1
SCB_DisableDCache();
zu deaktiveren. Aber das kann ja nicht sein?


Wie geht man mit jenem Problem um ohne den DCache ständig auf und 
abdrehn zu müssen?

tia
#5256713
Lesenswert?

Es gibt bei Prozessoren dieser Komplexität oft mehrere Speicherbereiche 
mit unterschiedlichen Eigenschaften hinsichtlich Coherency und Caching. 
Da das DTCM RAM wohl nicht gecached wird, treten dort auch keine 
Probleme mit dem Cache auf. Barriers/Syncs brauchts trotzdem.
#5256715
Lesenswert?

Bei DMA und Caches gilt genrell:

* Wenn per DMA aus dem RAM gelesen wird:

Vor dem Transfer einen Cache Writeback auslösen. Ansonsten liegen die 
Daten möglicherweise noch im Cache und nicht im RAM.

* Wenn per DMA in das RAM geschrieben wird:

Vor dem Transfer einen Cache Invalidate auslösen. Ansonsten liest Du 
möglicherwise nicht den neuen Inhalt aus dem RAM sondern alten Kram aus 
dem Cache. Der Invalidate sollte immer vor dem Transfer sein, ansonsten 
kann es passieren das Du gleichzeitig DMA machst, den Inhalt aber mit 
altem Zeugs aus deinem Cache überschreibst.

Wenn Du diese beiden Regel beherzigst sollte es funktionieren. Achja, 
und Du musst nicht immer den gesammten Cache Invalidieren bzw. Writeback 
auslösen. Es reicht den Bereich zu bearbeiten, auf dem DMA läuft.
OP #5256749
Lesenswert?

Nils P. schrieb:
> Bei DMA und Caches gilt genrell:
>
> * Wenn per DMA aus dem RAM gelesen wird:
>
> Vor dem Transfer einen Cache Writeback auslösen. Ansonsten liegen die
> Daten möglicherweise noch im Cache und nicht im RAM.
>
> * Wenn per DMA in das RAM geschrieben wird:
>
> Vor dem Transfer einen Cache Invalidate auslösen. Ansonsten liest Du
> möglicherwise nicht den neuen Inhalt aus dem RAM sondern alten Kram aus
> dem Cache. Der Invalidate sollte immer vor dem Transfer sein, ansonsten
> kann es passieren das Du gleichzeitig DMA machst, den Inhalt aber mit
> altem Zeugs aus deinem Cache überschreibst.
>
> Wenn Du diese beiden Regel beherzigst sollte es funktionieren. Achja,
> und Du musst nicht immer den gesammten Cache Invalidieren bzw. Writeback
> auslösen. Es reicht den Bereich zu bearbeiten, auf dem DMA läuft.


Richtige Antwort, Danke!

Benutzt man die CMSIS Funktionen (core_cm7.h), dann funktioniert 
folgendes:
1
uint8_t x[] = {'a', 'b', 'c', 'd'};
2
SCB_CleanInvalidateDCache_by_Addr(reinterpret_cast<uint32_t*>(&x), sizeof(x));
3
cmd::Serial::transmitDma(&x[0], sizeof(x));

bzw.
1
uint8_t x[] = {'a', 'b', 'c', 'd'};
2
SCB_CleanDCache();
3
cmd::Serial::transmitDma(&x[0], sizeof(x));


Eine reine DSB Instruktion bringt nichts.


/edit
Ja die AN4839 hatte ich auch grad entdeckt :)
Gast #5256751
Lesenswert?

A. K. schrieb:
> Da das DTCM RAM wohl nicht gecached wird, treten dort auch keine
> Probleme mit dem Cache auf. Barriers/Syncs brauchts trotzdem.

Vorher aber gut schauen ob der DMA Controller auf das dtcm zugreifen 
kann. War bei den f4 nicht so, bei Cortex m7 scheint aber ein Trend 
dahin zu existieren.

Weiter kann die MPU des m7 Speicherbereiche mit verschiedenen Attributen 
bzgl. Cachebarkeit versehen. Das wäre explizit.

Und zu guter Letzt gäbe es in cmsis Funktionen um Teile des Caches zu 
invalidieren oder ins RAM zu schreiben.

Die Frage ist halt immer ob es lohnt. M7 ist nochmals ein anderes beast 
als M4.
#5256757
Lesenswert?

Vincent H. schrieb:
> Die Frage ist vermutlich eher, ob es sich lohnt den DCache überhaupt
> aufzudrehen, wenn man einen Großteil seiner Daten via DMA
> herumschriebt...?

... oder ob man sich vorher Gedanken darüber macht, welche Daten mit DMA 
beharkt werden und welche nicht. Und ob man das trennt und in 
verschiedene Speicherbereiche legt.

Immerhin gibts bei den Cortext M7 Cores verschiedene Speicherbereiche 
und -interfaces, die u.U. verschiedene Eigenschaften haben, was Caching 
angeht. Manchmal gibts auch eine MPU, die ebenfalls dabei mitreden kann.
OP #5257022
Lesenswert?

Dr. Sommer schrieb:
> Vincent H. schrieb:
>> SCB_CleanInvalidateDCache_by_Addr(reinterpret_cast<uint32_t*>(&x),
>> sizeof(x));
>> cmd::Serial::transmitDma(&x[0], sizeof(x));
>
> So ist's sauberer:
>
1
SCB_CleanInvalidateDCache_by_Addr(reinterpret_cast<uint32_t*>(x), 
2
> sizeof(x));
3
> cmd::Serial::transmitDma(x, sizeof(x));


Ehm, jo...
Ich bin ja generell offen für "cleaner Code" Gschichtln, aber das war 
sowieso nur Pseudo-Code zum erläutern des Problems. Ich verwend (fast) 
nie built-in Arrays.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren