Forum: Mikrocontroller und Digitale Elektronik komplexes Problem mit Grafik und Dateisystem auf Disco-F746NG


von Johannes S. (Gast)


Angehängte Dateien:

Lesenswert?

ich quäle mich schon den ganzen Tag mit einem Problem mit lvgl Grafik 
und einer SD Karte unter Mbed.
Das Programm ist groß, zuviel Code um alles zu zeigen, ich versuche es 
zu beschreiben.
Symptom: das mounten der SD-Karte schlägt fehl wenn die Zeile mit dem 
Instantiieren des lvgl Treibers im Code ist.  Das Lesen des Bootsektors 
schlägt fehl und es wird '-22' (kein gültiges Volume) gemeldet, auch 
beim Zeilenweisen Ausführen im Debugger.
Wenn ich aber die Zeile mit dem lvgl Treiber danach auskommentiere, dann 
funktioniert das Dateisystem und das rootdir wird korrekt ausgegeben.
Da der Treiber noch nicht instantiiert wurde, kann es eigentlich nur an 
statischem Code, der durch den Treiber dazugelinkt wird, liegen. Das ist 
schon einiges weil ich das BSP zum Disco-F746 verwende. Ich habe aber 
bisher nichts gesehen was stören könnte.
Die SD Karte benutzt DMA, der Grafiktreiber optional. Das war meine 
erste Vermutung, deshalb habe ich die Grafik auf Pixelweises Ausgeben 
geändert, das hatte aber keinen positiven Effekt. Puffer im lvgl Treiber 
habe ich kleiner gemacht, statisch oder dynamisch angelegt, NAK.
Speicher hat da Board reichlich, daran sollte es auch nicht liegen. Was 
kann so blöde Fehler verursachen?
1
SDIOBlockDevice sd;
2
FATFileSystem fs("sda");
3
4
bool mountFilesystem()
5
{
6
    volatile int err = 0;
7
8
    err = sd.init();
9
    printf("sd init result: %d\n", err);
10
11
    err = fs.mount(&sd);
12
    debug_if(err != 0, "mount error: %d\n", err);
13
14
    return (err == 0);
15
}
16
17
void printDirectory(FileSystem *fs, const char* dirname) {
18
    Dir dir;
19
    struct dirent ent;
20
21
    dir.open(fs, dirname);
22
    printf("contents of dir: %s\n", dirname);
23
    printf("----------------------------------------------------\n");
24
25
    while (1) {
26
        size_t res = dir.read(&ent);
27
        if (0 == res) {
28
            break;
29
        }
30
        printf(ent.d_name);
31
        printf("\n");
32
        fflush(stdout);
33
    }
34
    dir.close();
35
}
36
37
38
// main() runs in its own thread in the OS
39
int main()
40
{
41
#if 0
42
    mbed_trace_init();
43
#endif 
44
45
    printf("Hello from "  MBED_STRINGIFY(TARGET_NAME) "\n");
46
    printf("Mbed OS version: %d.%d.%d\n\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
47
48
    if (mountFilesystem()) {
49
       printDirectory(&fs, "/");
50
    }
51
52
#if 1
53
    LVGLDispDriver*  lvglDisplay = LVGLDispDriver::get_target_default_instance();
54
    LVGLInputDriver::get_target_default_instance_touchdrv(lvglDisplay);
55
#endif
56
57
    // Bring up the ethernet interface
58
    volatile nsapi_error_t err;
59
    SocketAddress localAddr;
60
61
    printf("starting network...\n");

von Johannes S. (Gast)


Angehängte Dateien:

Lesenswert?

ich bin etwas weiter, es hat schon etwas in Verbindung mit DMA zu tun. 
Auch das Display zeigt garbage an wenn ich per DMA2D vom Renderbuffer 
(in internen SRAM1) in den framebuffer (im ext. SDRAM) kopiere. Es 
funktioniert korrekt wenn der Renderbuffer im DTCM RAM Bereich liegt.
Genauso bei der Dir Ausgabe, wenn die Grafik nicht dazugelinkt wird, 
dann verschieben sich die Daten ins 64 KB DTCM und das Lesen per DMA2 
funktioniert. Wenn die Daten im SRAM1 liegen, dann gibt es Fehler und 
die Daten sind komplett oder teilweise falsch.
Etwas am Takt falsch konfiguriert oder gibt es noch was bei DMA 
Initialsierung?

von Seppel (Gast)


Lesenswert?

Hallo,

nicht alle RAM Bereiche sind vom DMA aus ansprechbar, im Handbuch ist 
eine Verbindungsmatrix.

Ich hatte ein Problem dass ich vom RAM der CPU nicht mit dem DMA in den 
DAC schreiben konnte, bzw. nur const Werte.

Bin unterwegs, ich schicke später die Anleitung für die Umsetzung, 
Anpassung der Linkerscripts,... ST hatte mir dabei geholfen.

Grüße, Seppel.

von Johannes S. (Gast)


Lesenswert?

Die Abbildung 1 im RM0385 ? Danach haben DMA2/DMA2D ja Verbindungen zu 
allen RAM. Das es Limits gibt hatte ich beim F407, dann ging es aber gar 
nicht WIMRE.
Aber jetzt habe ich wenigstens die richtige Suchrichtung. Auf jeden Fall 
wird es übel kompliziert wenn RAM nicht gleich RAM ist, beim H7 sieht 
das ja noch heftiger aus...

Auch das die Dir Ausgabe teilweise ging war verwirrend, bei Fehlern hat 
das Chan-FAT die Dateinamen wie 8.3 abgekürzt:
1
sd init result: 0
2
printDirectory, dir_entry addr: 0x200138c8  SRAM1 (240 KB)
3
contents of dir: /
4
----------------------------------------------------
5
FILORDER.BIN
6
blue_flower.jpg
7
blue_flower_16.bin
8
blue_flower_16_swap.bin
9
blue_flower_32.bin
10
blue_flower_8.bin
11
blue_rose_16.bin
12
BLUE_R~1.PNG
13
flower_icon_alpha.c
14
flower_icon_alpha.png
15
lv_tutorial_images.c
16
BLUE_R~1.BIN
17
RED_FL~1.C
18
red_flower.png
19
RED_RO~1.C
20
RED_RO~1.PNG
21
BLUE_R~1.BIN
22
bmp.bin
23
GAUGE_~1.JS

so sieht es aus wenn die Daten im DTCM liegen:
1
sd init result: 0
2
printDirectory, dir_entry addr: 0x2000b5b0  DTCM (64 KB)
3
contents of dir: /
4
----------------------------------------------------
5
FILORDER.BIN
6
blue_flower.jpg
7
blue_flower_16.bin
8
blue_flower_16_swap.bin
9
blue_flower_32.bin
10
blue_flower_8.bin
11
blue_rose_16.bin
12
blue_rose_16.png
13
flower_icon_alpha.bin
14
flower_icon_alpha.c
15
flower_icon_alpha.png
16
lv_tutorial_images.c
17
lv_tutorial_images.h
18
lv_tutorial_images.mk
19
red_flower.c
20
red_flower.png
21
red_rose_16.c
22
red_rose_16.png
23
test.txt
24
bmp.bin
25
logo.bin
26
gauge_min.js

von Nils (Gast)


Lesenswert?

Ich kenn jetzt deine CPU nicht,  aber ein klassiker, der zu solchen 
Fehlern  führt: Daten per CPU in das SDRAM schreiben. Teile bleiben 
dabei im Cache und sind noch nicht im SDRAM angekommen. Ein jetzt 
gestarteter DMA liest aus dem SDRAM und beachtet den Cache nicht. So 
kommt es zu solchen Effekten.

Musst mal schauen ob Du einen Daten-Cache hast und ggf. einen 
Cache-Writeback auf den Quell Speicherbereich loslassen bevor Du den DMA 
startest.

von Johannes S. (Gast)


Lesenswert?

ja, Danke, der F7 hat D- und I-Cache.
Habe gerade den D-Cache disabled und neu kompiliert, damit sieht es auch 
gut aus, sowohl beim SDMMC als auch DMA2D, jedenfalls so auf den ersten 
Blick.
Ist natürlich die Holzhammermethode, ich habe ST Dokumente gesehen wo es 
differenziertere Lösungen gibt. Aber das muss man erstmal verstehen.

Das SDIO hatte mit DMA beim F4 wunderbar funktioniert, auf dem F7 erst 
auch, aber da hatte ich die Grafik noch nicht mit drin. Ich erzähle 
gerade auch immer die ST sind alle gleich, aber einige sind doch 
gleicher...

von Seppel (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

anbei das PDF, ich verwenden unter anderem den STM32H745, bei diesem 
trat das Problem auf.

Vielleicht hilft es Dir weiter, hoffe Du lässt uns an der Lösung 
teilhaben. :-)

Grüße, Seppel

von Johannes S. (Gast)


Lesenswert?

Danke, das ist so ähnlich. Da funktioniert der DMA aber gar nicht wenn 
man den falschen Speicher erwischt. Der F7 hat nicht soviel Auswahl und 
der schnellere DTCM mit 64  KB reicht nicht für alles.
Bei mir geht es dann eher darum wie man Cache und DMA vereint.

von Seppel (Gast)


Lesenswert?

Hallo,

mit dem ART(DMA2D) kenne ich mich leider nicht aus, wie man das im 
Detail nutzt kann ich auf die schnelle nicht nachvollziehen. Vielleicht 
kannst Du was dazu schreiben, wäre super.

Laut RM0385 Rev 8 Seite 67 hat der "DMA2D bus" Zugriff auf "SRAM1, SRAM2 
and DTCM (through the AHBS bus of Cortex®-M7), external memories through 
FMC or Quad SPI, and internal Flash memory."

Laut ReferenceManual (RM0385 Rev 8, Seite 64) des STM32F4 ist das DTCM 
und ITCM nicht durch den DMA1 und DMA2 regulär zugreifbar. Was die 
gestrichelte Linie die mit "AHBS" gekennzeichnet ist und eine Verbindung 
zum DTCM haben soll bedeutet, weiß ich noch nicht genau, scheint 
unidirektion zu sein(Pfeil)? Der Cache scheint mir nicht Adressierbar zu 
sein, auf Seiter 69 ist das zumindest nicht explizit benannt.

Was mir noch aufgefallen ist, Programming Manual, PM0253 Rev 5 Seite 
242, "Initializing and enabling the L1-cache", da scheint es auch einige 
Stoplerfallen zu geben.

Grüße, Seppel

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich hatte beim STM32F429 ein ähnliches Problem, weil ich den SRAM für 
den Framebuffer mit viel zu vielen Waitstates initialisiert hatte. Der 
DMA2D (und auch 'händisches' beschreiben) ist damit überhaupt nicht 
klargekommen und hat die ganze Kiste blockiert. Ich kenne F7xx 
allerdings nicht genug, um zu wissen, obs sowas bei dir sein könnte.

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

ein entscheidender Tipp kam ja von Nils, und mit dem deaktivieren des 
Daten Cache sehen die DMA Transfers gut aus. Nur sollte das eleganter 
gehen, indem man vor dem Transfer einen flush auslöst. Wie das geht, 
habe ich mir noch nicht angesehen. Nachdem ich gestern den ganzen Tag am 
Rechner gesessen hatte, musste das Kind heute mal an die frische Luft :)

Seppel schrieb:
> mit dem ART(DMA2D) kenne ich mich leider nicht aus, wie man das im
> Detail nutzt kann ich auf die schnelle nicht nachvollziehen. Vielleicht
> kannst Du was dazu schreiben, wäre super.

Wenn mein Code vorzeigbar ist, dann packe ich den auf github. Ist eben 
ein Rumpf mit Mbed-OS, lvgl Grafik, SD Karte über 4 Bit SDIO und 
Ethernet läuft auch. Ich wollte eigentlich nur mal eben die Grafik auf 
SDC speichern, die einzelnen Komponenten hatte ich ja schon. Das das 
Zusammenspiel dann so kompliziert wird hätte ich nicht gedacht.
DMA2D ist wie der 'normale' DMA, kann aber zusätzlich Pixelformate 
konvertieren, alpha blending mixen und Offsets für rechteckige 
Teilbereiche im Grafikspeicher berücksichtigen. Ich denke da kann man 
sich insgesamt lange mit beschäfftigen, Lvgl kann auch den alpha Kanal 
benutzen.
Im Board Support Package von dem Board war die Grafik Initialiserung 
sowie Zeichenprimitive und DMA für zeilenweises Füllen schon drin. Lvgl 
hat einen Buffer in das die Grafik gerendert wird und diesen Bereich 
muss der Grafiktreiber dann in den Framebuffer schieben. Der 
Renderbuffer muss nur n*Displayzeilenbreite groß sein, damit kann es 
auch gut mit den günstigen ILI und co. zusammenspielen. Wenn man DMA 
hat, dann kann man zwei Buffer benutzen. Während einer übertragen wird, 
kann lvgl schon den nächsten füllen.

von Seppel (Gast)


Lesenswert?

Hallo,

ok, den Datencache komplett deaktiviert,... schade dass es nicht 
ausgereicht hat den in einen anderen RAM-Bereich auszulagern.

Super dass Du es veröffentlichst, ich freue mich mal eine Blick drauf zu 
werfen, "Ich will ja nicht dumm sterben". :-)

Vielen Dank, Grüße, Seppel

von m.n. (Gast)


Lesenswert?

Johannes S. schrieb:
> Nur sollte das eleganter
> gehen, indem man vor dem Transfer einen flush auslöst.

Ich kenne das Problem vom H7xx.
Du kannst per MPU den RAM-Bereich vom Cache aussparen.

von Seppel (Gast)


Lesenswert?

Hallo,

die MPU ist bei mir aus, denn ich brauche die nicht, keine Security,... 
.

Grüße, Seppel

von m.n. (Gast)


Lesenswert?

Seppel schrieb:
> die MPU ist bei mir aus, denn ich brauche die nicht, keine Security,...

Du weißt nur nicht, daß Du die MPU brauchst. Um Sicherheit geht es 
überhaupt nicht.
Per MPU sorgt man dafür, daß ein RAM-Bereich nicht per D-Cache 
beschleunigt wird. Andere Bereiche schon, was höchste Geschwindigkeit 
ermöglicht.

von Johannes S. (Gast)


Lesenswert?

es gibt ein API für die MPU und das init() wird auch ausgeführt, das 
Cache Flag ist auch gesetzt.
Ich habe die Zuordnung der Regions noch nicht verstanden, sind die 
vorgegeben oder ist eine gewisse Anzahl frei definierbar?
https://github.com/ARMmbed/mbed-os/blob/master/hal/source/mpu/mbed_mpu_v7m.c

das ARM_MPU_SetRegion ist in der CMSIS definiert, ist das ein Feature 
der ARM cores?
https://github.com/ARMmbed/mbed-os/blob/7279ae2cd09257f5d8cc93dccfcc64a3102030b7/cmsis/CMSIS_5/CMSIS/TARGET_CORTEX_M/Include/mpu_armv7.h#L228

Die Region Sizes sind wie es aussieht auch fixed in 2^n Größen 
einstellbar, mit n = 4...31.

ok, sehe schon, muss mir die AN4838 unters Kopfkissen legen.

von m.n. (Gast)


Lesenswert?

Johannes S. schrieb:
> das ARM_MPU_SetRegion ist in der CMSIS definiert, ist das ein Feature
> der ARM cores?

So ist es. Die Regionen kann man sich frei aussuchen.
Bei meiner Anwendung verwende ich internes RAM als Bildspeicher und 
schreibe die Bilddaten per DMA über FMC (TFT_ADR = 0x60000000) an das 
"nackte" Display. Die MPU wird wie folgt initialisiert:
1
// Zugriffe FMS-Bank1    
2
#define MPU_DEFS_RASR_SIZE_1MB          (19<<MPU_RASR_SIZE_Pos)
3
#define MPU_DEFS_RASE_AP_FULL_ACCESS    (3 << MPU_RASR_AP_Pos)   
4
  MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | // allow privileged code to use default memory map
5
              MPU_CTRL_ENABLE_Msk;
6
  MPU->RNR = 1;                             // Region 1 verwenden
7
  MPU->RBAR = TFT_ADR & MPU_RBAR_ADDR_Msk;  // Schutz ab TFT-Adresse
8
  MPU->RASR = MPU_RASR_XN_Msk |             // ausführbarer Code gesperrt
9
              MPU_DEFS_RASR_SIZE_1MB |      // 1 MB Adressbereich
10
              MPU_RASR_B_Msk |              // pufferbar
11
              MPU_DEFS_RASE_AP_FULL_ACCESS |  //full read/write access for privileged and unprivileged code
12
              MPU_RASR_ENABLE_Msk;          // Region freigeben

von Johannes S. (Gast)


Lesenswert?

das Ding will immer noch nicht. Habe schon jede Menge Einstellungen 
getestet, es wird immer ein gestörtes Bild angezeigt.

Ich habe probiert die Zieladresse im SDRAM als auch die Quelladresse vom 
Cache auszuschliessen. Die Adressen passen, wenn ich die Zugriffsrechte 
auf 'none' stelle, dann gibts hardfaults. Ausser beim DMA, der darf 
trotzdem.
Es ist aber reproduzierbar, wenn xbuf (also die DMA Quelle) im DTCM 
liegt, gibt es keine Fehler, liegt es im SRAM1, dann gibt es diesen 
Datenmüll.
Mit SRAM1 funktionierte es interessanterweise wenn Ethernet auch 
aktiviert war, da habe ich aber gefunden das im EMAC Treiber auch die 
MPU konfiguriert wird, aber für einen anderen RAM Bereich. Das ist eine 
Unschärfe im OS weil diese globale Resource nicht zentral verwaltet 
wird, der EMAC überschreibt eine schon beim Systemstart konfigurierte 
Region.
1
    /* Disable the MPU */
2
    HAL_MPU_Disable();
3
4
#if 1
5
    // Select region 7 and use it for framebuffer
6
    ARM_MPU_SetRegion(
7
        ARM_MPU_RBAR(
8
            7,                          // Region
9
//            (LCD_FB_START_ADDRESS)),    // Base  (32 Byte granularity) ((uint32_t)0xC0000000)
10
            (uint32_t)xbuf1),
11
        ARM_MPU_RASR(
12
            1,                          // DisableExec
13
            ARM_MPU_AP_FULL,            // AccessPermission
14
            0,                          // TypeExtField
15
            0,                          // IsShareable
16
            0,                          // IsCacheable
17
            0,                          // IsBufferable
18
            0,                          // no-Subregion Disable
19
            ARM_MPU_REGION_SIZE_16KB)    // Size
20
    );
21
#endif
22
23
    /* Enable the MPU */
24
    HAL_MPU_Enable(MPU_HFNMI_PRIVDEF);
25
26
#if 0
27
    uint32_t* fb = (uint32_t*)LCD_FB_START_ADDRESS;
28
29
    fb[0] = 0xff00ff00;     // access background
30
    fb[480*272] = 0xffff0000;     // access foreground 
31
#endif

von Johannes S. (Gast)


Lesenswert?

arrrgh... Ethernet hat nicht die MPU umkonfiguriert, das war nur für H7 
aktiv. Für F7 wurde der Holzhammer rausgeholt und der D-Cache wieder 
komplett abgeschaltet.
Das erklärt das Verhalten und riecht schwer nach Errata.

von Johannes S. (Gast)


Lesenswert?

Noch ein Update:
es gibt doch einen Zauberspruch wenn der D-Cache aktiviert ist:
1
    SCB_CleanInvalidateDCache();
vor die DMA Operation und es klappt. Ebenso beim SD Karte lesen.
Will mich aber nicht selber loben, das habe ich beim Stöbern im lvgl 
github Repo gefunden, da gab es für das F769 schon einen Treiber. Der 
hat auch noch so ein Anti-Tearing drin was ich noch nicht übernommen 
habe.

auf einem Discovery STM32F769NI (da hatte ich das gleiche Problem) sieht 
das so aus:
https://youtu.be/yxNnvWAxlx4

von m.n. (Gast)


Lesenswert?

Johannes S. schrieb:
> es gibt doch einen Zauberspruch wenn der D-Cache aktiviert ist:
> SCB_CleanInvalidateDCache();
> vor die DMA Operation und es klappt. Ebenso beim SD Karte lesen.

Das ist dann soetwas wie ein Abblockkondensator in Software.
Wenn es nicht hilft, gibt es ja noch andere SBC_xxxx ;-)

von Johannes S. (Gast)


Lesenswert?

habe mir auch gerade das aktuelle CubeH7 angesehen, da sind auch aktuell 
interessante Änderungen reingekommen:
https://github.com/STMicroelectronics/STM32CubeH7/commit/5975bffae9358bc2b2890a35a203d940a395efef#diff-e5eaf8e424ade5cd24bbfca40871c6406a6d90b9b3dad4e7b743256df156c6b4

das ist ja schon blöd das man den ganzen 32 oder 16 kB Cache vor dem DMA 
putzen muss.

von m.n. (Gast)


Lesenswert?

Johannes S. schrieb:
> das ist ja schon blöd das man den ganzen 32 oder 16 kB Cache vor dem DMA
> putzen muss.

Ich hätte ja auch eher gedacht, es abschließend zu machen. Aber dazu 
müßte man einen Einblick ins Programm haben.
Egal, wichtig ist, daß man bei eigener Programmierung die "Fallen" im 
Hinterkopf hat.

von Johannes S. (Gast)


Lesenswert?

m.n. schrieb:
> Ich hätte ja auch eher gedacht, es abschließend zu machen.

der Ablauf bei lvgl ist:
- CPU rendert in Buffer, der muss Vielfache von Displayzeile groß sein.
- Buffer wird Pixelweise per CPU oder per DMA in Framebuffer übertragen

Meine Beobachtung war ja schon vorher das es funktioniert hat wenn der 
Buffer im DTCM Bereich liegt. Das könnte man auch im Linker erzwingen, 
aber dieser Bereich ist bei den Controllern unterschiedlich groß und der 
DMA bei der SD Karte hatte das Problem ja auch.
Es sieht also so aus das der Renderbuffer noch (teilweise) im Cache ist 
und erst ins SRAM muss bevor er per DMA in den Framebuffer kopiert 
werden kann. So wäre meine Erklärung.

von Darth Moan (Gast)


Lesenswert?

Moin,

was ist denn aus dem Versuch geworden, den DMA buffer via MPU uncached 
zu konfigurieren?

Das ist doch bei Caches immer das Gleiche. Und man muss nicht immer das 
komplette DCache invalidieren oder flushen, dafür gibt es doch auch 
SCB_InvalidateDCache_by_Addr() usw. Natürlich sollten die DMA Buffer auf 
Cache Lines ausgerichtet sein.

Bei dem Input Buffer für DMA2D könnte man den Cache auf WriteThrough 
konfigurieren. Das müsste da schon reichen, da die CPU schreibt und der 
DMA nur liest.

von Johannes S. (Gast)


Lesenswert?

Darth Moan schrieb:
> was ist denn aus dem Versuch geworden, den DMA buffer via MPU uncached
> zu konfigurieren?

habe ich nicht hinbekommen, Beispiel war
Beitrag "Re: komplexes Problem mit Grafik und Dateisystem auf Disco-F746NG"
ich hatte aber viele viele verschiedene Varianten probiert, wurden alle 
ignoriert. Wenn du einen Vorschlag hast wie es aussehen müsste, dann 
kann ich es testen.

> dafür gibt es doch auch
> SCB_InvalidateDCache_by_Addr()

ja, das wäre auch eine sinnvolle Optimierung, kann ich auch noch 
probieren.

von Darth Moan (Gast)


Lesenswert?

Moin,

Johannes S. schrieb:
> ignoriert. Wenn du einen Vorschlag hast wie es aussehen müsste, dann
> kann ich es testen.

Hmm, auf die Schnelle nicht. Da müsste ich das F7 board mal wieder 
rauskramen und ein entsperechendes Beispiel konstruieren.
Ich hatte jetzt mal schnell in die AN4838 reingeschaut, da war ein 
Beispiel drin, von dem ich gehofft hätte, das es das tut, was es 
verspricht. Ob ich das heute noch ausprobiert bekomme, kann ich nicht 
versprechen.

Internal SRAM Normal memory 0x2000 0000 Region0 8 Kbytes Shareable, 
write through, no write allocate
C=1, B = 0, TEX = 0, S=1
SRD = 0, XN= 0, AP = full access

Flash memory Normal memory 0x0800 0000 Region1 1 Mbyte Non-shareable 
write through, no write allocate
C=1, B = 0, TEX = 0, S=0
SRD = 0, XN= 0, AP = full access

FMC Normal memory 0x6000 0000 Region2 512 Mbytes Shareable, write 
through, no write allocate
C=1, B = 0, TEX = 0, S=1
SRD = 0, XN= 0, AP = full access
1
void MPU_RegionConfig(void)
2
{
3
MPU_Region_InitTypeDef MPU_InitStruct;
4
/* Disable MPU */
5
HAL_MPU_Disable();
6
/* Configure RAM region as Region N°0, 8kB of size and R/W region */
7
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
8
MPU_InitStruct.BaseAddress = 0x20000000;
9
MPU_InitStruct.Size = MPU_REGION_SIZE_8KB;
10
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
11
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
12
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
13
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
14
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
15
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
16
MPU_InitStruct.SubRegionDisable = 0x00;
17
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
18
HAL_MPU_ConfigRegion(&MPU_InitStruct);
19
/* Configure FLASH region as REGION N°1, 1MB of size and R/W region */
20
MPU_InitStruct.BaseAddress = 0x08000000;
21
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
22
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
23
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
24
HAL_MPU_ConfigRegion(&MPU_InitStruct);
25
/* Configure FMC region as REGION N°2, 0.5GB of size, R/W region */
26
MPU_InitStruct.BaseAddress = 0x60000000;
27
MPU_InitStruct.Size = MPU_REGION_SIZE_512MB;
28
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
29
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
30
HAL_MPU_ConfigRegion(&MPU_InitStruct);
31
/* Enable MPU */
32
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
33
}

von Johannes S. (Gast)


Lesenswert?

es gibt noch eine AN4839, da geht es auch direkt um den F7/H7 L1 Cache.

das ist ja mal gut erklärt, das setzen auf WT für den Renderbuffer 
sollte eigentlich die Lösung sein, ich probiere es noch mal.

edit2:
wobei das WB für den Renderbuffer und das abschliessende Invalidieren 
des Caches (für diesen Bereich) ja nicht per se schlecht sein muss. Wenn 
das Rendern die gleichen Pixel mehrfach überschreibt, dann kann das ja 
wieder ein Vorteil sein. Da ist die Frage wie lange das Cache putzen 
dauert.
So oder so, für einen µC sind diese F7/H7 schon rattenschnell.

von Johannes S. (Gast)


Lesenswert?

Darth Moan schrieb:
> Internal SRAM Normal memory 0x2000 0000 Region0 8 Kbytes Shareable,
> write through, no write allocate
> C=1, B = 0, TEX = 0, S=1
> SRD = 0, XN= 0, AP = full access

mit diesen Einstellungen hat es jetzt funktioniert. Mein Fehler war 
noch, das der Buffer nicht an der Region Size ausgerichtet war. Ich 
hatte angenommen das ein 32 Byte Alignment (Cache Line Size) reichen 
würde, aber dem ist scheinbar nicht so. Ein 64 kB Buffer muss auch auf 
einer geraden 64 k Adresse liegen, was bei so großen Bereichen dann auch 
das Zusammenspiel mit dem Linker nötig macht.
1
    {
2
        /* Disable the MPU */
3
        HAL_MPU_Disable();
4
5
//     lv_color_t* xbuf2 = (lv_color_t*)0x20060000;  // a buffer for 20*800 rows * 4 Byte
6
//     lv_color_t* xbuf1 = (lv_color_t*)0x20070000;  // double buffer
7
8
        ARM_MPU_SetRegion(
9
            ARM_MPU_RBAR(
10
                4,                          // Region 4: not (yet) used by Mbed
11
                (uint32_t)xbuf2),                // Base, must be aligned 
12
            ARM_MPU_RASR(
13
                1,                          // DisableExec
14
                ARM_MPU_AP_FULL,            // AccessPermission
15
                0,                          // TypeExtField
16
17
                1,                          // IsShareable
18
                1,                          // IsCacheable
19
                0,                          // IsBufferable
20
                
21
                0,                          // subregions
22
                ARM_MPU_REGION_SIZE_128KB)  // Size
23
        );
24
25
        /* Enable the MPU */
26
        HAL_MPU_Enable(MPU_HFNMI_PRIVDEF);
27
    }

von Darth Moan (Gast)


Lesenswert?

Moin,

es freut mich das zu hören/lesen. Dann ist das also kein Fall für das 
Erata.

Dass die Regions immer an ihrer natürlichen Grenze liegen müssen, kenne 
ich so von der MMU auf einer anderen Plattform. Die MMU HW benutzte die 
SIZE Information dazu, die zu vergleichenden Adress Bits zu bestimmen. 
Damit fängt eine Region immer an einem Vielfachen ihrer Grösse an.

Das man das auch anders in HW giessen könnte, wäre mir gar nicht in den 
Sinn gekommen. Aber wenn man jetzt danach sucht, wird es bestimmt 
irgendwo eine HW geben, die abweichende Grenzen erlaubt. Ich kenne ja 
nur ein paar Plattformen.

von m.n. (Gast)


Lesenswert?

Johannes S. schrieb:
> Da ist die Frage wie lange das Cache putzen dauert.

Vielleicht hast Du noch einmal "Luft", um das grob zu ermitteln.

> So oder so, für einen µC sind diese F7/H7 schon rattenschnell.

So ist es, und wenn man sich dafür auch mal mit aktiven Caches und deren 
"Risiken und Nebenwirkungen" beschäftigen muß, schadet es bestimmt 
nicht.
An anderer Stelle erwähnst Du, bei umfangreicherer Grafik Cortex-A ins 
Auge zu fassen. Ich sehe die H7 als Eierlegendewollmilchsau, deren 
Preis/Leistungs-Verhältnis auch dann noch stimmt, wenn man nur 5-10% der 
Peripherie nutzt. Die Grafik-Geschichten sind nur ein kleiner Teil, der 
für Mess- und Steuerungsaufgaben völlig ausreichend ist. Meine Meinung.

von Johannes S. (Gast)


Lesenswert?

m.n. schrieb:
>> Da ist die Frage wie lange das Cache putzen dauert.
>
> Vielleicht hast Du noch einmal "Luft", um das grob zu ermitteln.

auf dem F769 Disco, das Display hat 800 * 480 mit 32 BPP (16 BPP RGB565 
ginge auch):
1
SCB_CleanDCache : 24 ... 35 µs
2
SCB_CleanDCache_by_Addr(64000 Byte) : 85 ... 95 µs
3
DMA Transfer 64000 Byte : ~350 µs (mit CleanDCache)
4
DMA Transfer 64000 Byte : ~330 µs (ohne Clean, write through SRAM)
Der Renderbuffer ist jetzt 20 Zeilen groß, ein kompletter Screen ist 
damit in 480 / 20 = 24 Transfers gefüllt, sollte also < 10 ms dauern.

Das Clean by_Addr braucht bei großen Datenbereichen länger, das sieht 
man auch im Code das es mehr Schleifendurchläufe hat. Da das write 
through jetzt funktioniert ist das clean aber nicht mehr nötig.
Unschön ist nur das man das Linkerscript anpacken muss um den Buffer 
ordentlich zu plazieren. Die 2*64 kB Buffer sind natürlich auch 
großzügig spendiert, das will man sicher nicht immer so haben.

> An anderer Stelle erwähnst Du, bei umfangreicherer Grafik Cortex-A ins
> Auge zu fassen. Ich sehe die H7 als Eierlegendewollmilchsau,

mit den Cortex-A habe ich bisher nichts gemacht, ausser Raspberrys zu 
nutzen. Die CM7 sind schon genial, nur so Boards mit HyperRAM und -Flash 
im BGA baue ich auch nicht mal eben. Bei Ali gibt es aber mittlerweile 
jede Menge schöner Displays wo man mehr als etwas SPI braucht, ich finde 
es gut sowas auch nutzen zu können.

von Johannes S. (Gast)



Lesenswert?

ich habe das nochmal mit dem buffer im DTCM RAM gemessen, ich hätte 
erwartet das es mit seinen 0 Waitstates ja noch schneller ist. 
Uberraschend war aber das der DMA Transfer jetzt deutlich länger 
gebraucht hat, 550 µs gegenüber den 330 µs aus dem SRAM1. Das verstehe 
ich nicht ganz, scheint aber an den verschiedenen Bussen zu liegen.
Insgesamt ist ein einfacher lvgl Benchmark, der den Aufbau mit ein paar 
Buttons auf einem Screen mißt, aber mit Buffer im DTDM deutlich 
schneller als mit Buffer im SRAM1: 15 zu 22 ms.

Ich habe die Tests mehrmals wiederholt und bin mir auch sicher die nicht 
vertauscht zu haben, da sind jeweils debug Ausgaben drin.
Den Treibencode mit den Testsänderungen habe ich angehängt, ist durch 
die Test #ifdefs etwas unübersichtlich. Das Linkerscript muss ich für 
den Wechsel DTCM/SRAM1 auch jeweils umschalten.
Für den lvgl Benchmark habe ich die Ausgaben auskommentiert, da wären 
sonst die Zeiten für die Ausgabe auf die serielle mit drin.

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.