Hallo zusammen,
ich brauche ein Array der Größe ~100.000 Floats (=400kB). Ich stelle
aber fest, dass es nicht größer als ~30000 nicht packt (120kB).
Es geht um STM32H743 mit 1MB Ram. Die entsprechende Stelle des
Linkerscripts sieht momentan so aus:
1
/* Highest address of the user mode stack */
2
_estack = 0x20020000; /* end of RAM */
3
/* Generate a link error if heap and stack don't fit into RAM */
4
_Min_Heap_Size = 0x200; /* required amount of heap */
5
_Min_Stack_Size = 0x400; /* required amount of stack */
Ich verstehe nicht so ganz, wo das Programm überhaupt versucht, das
Array anzulegen.
Ich habe versucht, direkt auf RAM_D2 über die Addresse zuzugreifen: Ohne
Erfolg:
1
uint32_t arr_size=100000;
2
3
// uint32_t buf[arr_size]; //Funktioniert nicht.
4
uint32_t address= 0x24000000;
5
6
uint32_t* buf = (uint32_t*)0x40000; //Funktioniert auch nicht
Kann mir jemand bitte auf die Sprünge helfen? Wo stelle ich das ein? Wie
lege ich mein Array dort an?
Anbei das Linkerscript
Danke und beste Grüße
Im Linkerfile ein eigenen Bereich zu benennen könnte schon mal gut sein.
Beim gcc (AtollicTrueSTUDIO 9.1.0) hatte ich neulich den Wunsch das
Flash quasi als EEPROM zu mißbrauchen und fand coole Hinweise im Netz.
Linker file:
1
MEMORY
2
{
3
RAM(xrw):ORIGIN=0x20000000,LENGTH=20K
4
FLASH(rx):ORIGIN=0x08000000,LENGTH=124K
5
EEPROM_0(rx):ORIGIN=0x0801F000,LENGTH=1K
6
EEPROM_1(rx):ORIGIN=0x0801F400,LENGTH=1K
7
...
8
}
9
SECTIONS
10
{
11
/* prepare 1K from the FLASH as speudo EEPOM */
12
.flash_eeprom_0:
13
{
14
.=ALIGN(4);
15
KEEP(*(.flash_eeprom_0))
16
.=ALIGN(4);
17
}>EEPROM_0
18
19
.flash_eeprom_1:
20
{
21
.=ALIGN(4);
22
KEEP(*(.flash_eeprom_1))
23
.=ALIGN(4);
24
}>EEPROM_1
25
26
27
...
und im c-file
1
// data structures placed in the reserved FLASH space which is configured in the linker file xxx.ld
Das klappt und die Daten wurden in den gewünschten Bereich angelegt.
Wichtig ist wohl
Sowas im RAM würde vermutlich auch gehen nur eben mit 100.000 float
Werten.
Pointer drauf ansetzen und den reservierten Speicherblock einfach dafür
nutzen.
Könnte klappen.
Solocan Z. schrieb:> ich brauche ein Array der Größe ~100.000 Floats (=400kB). Ich stelle> aber fest, dass es nicht größer als ~30000 nicht packt (120kB).
Erste Grundregel bei so einer Frage: führ die Fehlermeldung auf, die der
Compiler odr Linker wirft. Der wird ja wohl kaum sagen "ah geh i packs
net".
Nop schrieb:> Solocan Z. schrieb:>>> ich brauche ein Array der Größe ~100.000 Floats (=400kB). Ich stelle>> aber fest, dass es nicht größer als ~30000 nicht packt (120kB).>> Erste Grundregel bei so einer Frage: führ die Fehlermeldung auf, die der> Compiler odr Linker wirft. Der wird ja wohl kaum sagen "ah geh i packs> net".
Ich muss leider sagen: Genau so ist es. Das Programm läuft nicht. Ohne
Fehlermeldung. Ohne nichts. Compiler interessiert das nicht. Den Linker
wohl auch nicht, wenn ich in meinem Code irgendwelche Speicherbereiche
unzulässig inkrementiere und irgendwelche andere wichtige RAM-Bereiche
überschreibe.
Sonst hätte ich die Fehler gepostet.
Also wie stelle ich fest, dass es "nicht läuft": Ich habe erstens paar
Prints und LED Meldungen am Anfang. Wenn ich bestimmte Größe
überschreite, sind diese Weg. Zweitens tritt das nur auf, wenn ich mein
Array auch initialisiere, also beschreibe. Wenn ich diese nur definiere,
ist das nur ein Pointer und stört sonst keine Speicherbereiche. Also das
Ganze ist für mich ein klarer Fall für nicht passenden Speicherbereich.
Das Linkerskript gibt auch die ersten Hinweise, warum es nicht
funktionieren soll.
Komischerweise habe ich in einem anderen Programm bereits ein Array mit
100000 Elementen schon am Laufen! Das kann aber auch ein Zufall sein, da
das Programm größer ist und das Array vermutlich woanders abgelegt wird,
wo die anderen Speicherbereiche nicht missbraucht werden.
... schrieb:> Scheinbar eine Nummer zu gross.
Genau, weil die kleineren STM32 ganz anders zu handlen sind...
Wenn du aber sonst so schlau bist, kannst du mir gerne verraten, warum
und wie der freier RAM-Bereich RAM_D1 nicht ausreicht, obwohl in
MAP-Datei keine Verstöße zu verzeichnen sind. Ich würde mich dafür
bedanken. Ansonsten kannst du deine Kräfte, die du zum anonymen Dissen
verballerst, sinnvoller einsetzen.
NichtWichtig schrieb:> Im Linkerfile ein eigenen Bereich zu benennen könnte schon mal gut sein.
Mein Problem ist, dass dort bereits einen Speicherbereich gibt, der groß
genug ist: RAM_D1.
Ich kann trotzdem versuchen, einen eigenen Custom-RAM-Bereich zu öffnen
und andere zu verkleinern. Aber mal was anderes: Die Idee mit der
Teilung vom Flash ist echt cool. Ich hatte davon schon gehört aber
gescheut, da der Flash nicht so viele Schreibzyklen verkraftet. Besteht
der ganze Hack nur daraus? Oder gibt es noch was dafür zu machen?
Flashen geht danach ganz normal?
> obwohl in MAP-Datei keine Verstöße zu verzeichnen sind
Ja wo hat er denn das/die Array(s) hingelegt?
Zu faul mal zu suchen?
Scheinbar ja wohl nicht im RAM_D1.
Im uebrigen benutze ich IAR. Dort geht das einfach mit einer
Region im Linkerfile und einem Pragma. Falls es nicht sowieso
schon eine passende Region gibt.
define region RAMD1_region = mem:[from _ICFEDIT_region_RAMD1_start_
to __ICFEDIT_region_RAMD1_end__];
#define RAMD1 _Pragma("location=\"RAMD1\"") __root __no_init
RAMD1 float array[MAX];
Die EEPROM Simulation ist schon eine Krücke welche die endliche
Schreibbarkeit berücksichtigen möchte.
Man verballert mal eben 2 1K Bänke um abwechselnd seine Daten dort
abzulegen.
Ist die eine Bank voll wird der letzte Wert/Datensatz in die 2. Bank
geschrieben und die erste gelöscht.
Je kleiner die Datenmenge ist desto öfters läßt sie sich flashen.
Ob das jetzt gut ist muß man je nach Projekt abschätzen.
Wenn der Speicher eh frei ist kann man das so machen.
Tips von ST finden man u.a. damit:
AN2594
Application note EEPROM emulation in STM32F10x microcontrollers
das klappt schon solange es in eine komplette RAM section passt
MEMORY
{
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
demnach MUSS das array in RAM_D1
standardmößig legt Cube eine einzige section fest die dummerweise
sollche effekte hat
du musst dein linkerfile komplett anpassen
Stack an das ende vom DTCM RAM
heap und variablen (.bss ) auf den D3 ram ( aufpassen ob nicht die 16
eth/USB mit drinhängen )
den D3 RAM legst du auf eine eigene section
das array legst du dann auf diese section .. und NUR das
ITCM RAM kannst du nicht als RAM für variablen nutzen
das ist für ausführbare funktionen
( ohne waitstates ausführen -> sack schnell )
den DTCM RAM kannst du natürlich auch für variablen nutzen
musst diese aber auch manuell zuweisen das sie dort liegen sollen
bsp von mir ... es läuft zumindest ...
1
MEMORY
2
{
3
RAM4(xr):ORIGIN=0x00000000,LENGTH=16K
4
ROM(xr):ORIGIN=0x08010000,LENGTH=960K
5
RAM(xrw):ORIGIN=0x20010000,LENGTH=240K
6
RAM2(xrw):ORIGIN=0x2004C000,LENGTH=16K
7
RAM3(xrw):ORIGIN=0x20000000,LENGTH=64K
8
}
9
10
.data:
11
{
12
.=ALIGN(8);
13
_sdata=.;/* create a global symbol at data start */
14
*(.data)/* .data sections */
15
*(.data*)/* .data* sections */
16
17
.=ALIGN(8);
18
_edata=.;/* define a global symbol at data end */
19
}>RAMAT>ROM
20
21
_siitcm=LOADADDR(.itcm);
22
/* ITCM RAM for critical functions */
23
.itcm:
24
{
25
.=ALIGN(8);
26
_sitcm=.;/* create a global symbol at itcm start */
Solocan Z. schrieb:> Das Linkerskript gibt auch die ersten Hinweise, warum es nicht> funktionieren soll.
Das Mapfile würde noch viel bessere geben.
Was allerdings auffällt: der erste Speicherbereich ist 128kB groß. 30000
mal 4 Byte ist 117kB. Zusammen mit noch ein paar Variablen von Dir
könnte DTCMRAM voll sein, wenn das Array wesentlich größer wird.
Also, poste doch erstmal das Mapfile, damit man das schonmal
verifizieren kann.
Und zwar sowohl das Mapfile, wenn Du das Array 30000 groß machst und
alles geht, als auch das Mapfile, was bei 100000 rauskommt.
Ok. Ich hatte mir eingebildet, dass das Array in RAM_D1 gemappt würde.
War natürlich falsch. Es war in DTCM drin. Facepalm. Nun habe ich eine
neue Section im Linkerskript definiert und das Array dorthin gelegt.
STM32H743ZI_FLASH.ld
Cool! Merkwürdig, daß Dein Linker keinen Fehler gemeldet hat.
Du könntest ansonsten am Ende jeder RAM-Sektion im Linkerfile noch ein
Linker-Label einfügen, etwa so am Ende der DTCMRAM-Sektion:
Nop schrieb:> Cool! Merkwürdig, daß Dein Linker keinen Fehler gemeldet hat.>> Du könntest ansonsten am Ende jeder RAM-Sektion im Linkerfile noch ein> Linker-Label einfügen, etwa so am Ende der DTCMRAM-Sektion:>>
>> Dann sollte bei Overflow ein Fehler kommen, so daß Du nächstesmal nicht> erst debuggen brauchst.
Ja, danke auch für diesen Tipp. Es hat mich reichlich verärgert, dass
das Ding ohne Hinweis einfach abstürzte.
Nop schrieb:> Das Mapfile würde noch viel bessere geben.>
Hier würde ich voll und ganz zustimmen. Aber der TO will oder kann wohl
nicht.
> Was allerdings auffällt: der erste Speicherbereich ist 128kB groß. 30000> mal 4 Byte ist 117kB. Zusammen mit noch ein paar Variablen von Dir> könnte DTCMRAM voll sein, wenn das Array wesentlich größer wird.
Man kann übrigens - wenn man will - das Array auch gleich im Linker
Script anlegen (und damit ganz genau bestimmen, wo es liegt).
Also beispielsweise im .bss-Segment:
1
.bss :
2
{
3
_sbss = .; /* define a global symbol at bss start */
4
__bss_start__ = _sbss;
5
*(.bss)
6
*(.bss*)
7
*(COMMON)
8
9
. = ALIGN(8);
10
myLargeGlobalArray = .;
11
. = . + MY_LARGE_ARRAY_SIZE;
12
_ebss = .; /* define a global symbol at bss end */
So, jetzt habe ich bisschen weitergespielt und hänge am nächsten Limit.
Ich habe nun den RAM-Bereich RAM_D1 auf 768K vergrößert, um größere
Arrays zu speichern. Damit sollten 190000 Floats speichern möglich sein.
Nun habe ich allerdings das Problem, dass es ab 130000 Elementen zwar
ohne Fehler kompiliert und verlinkt wird, aber das Loading fehlschlägt.
1
Failure at line:9 in "Target Software Startup Scripts". Please edit the debug configuration settings.
2
3
Load Failed.
Ich finde gerade leider keinen Hinweis, warum es nicht geladen werden
kann.
Wenn es am Debug Skript liegt, ist es vielleicht off topic für hier aber
ich bin mir irgendwie nicht so ganz sicher, ob ich beim Verändern des
Speichers alles richtig gemacht habe. Habe ich da etwas übersprungen?
Viele Grüße und danke nochmals
Solocan Z. schrieb:> Ich habe nun den RAM-Bereich RAM_D1 auf 768K vergrößert, um größere
rechne mal nach
512k block ab 0x2400 0000
512k bytes sind 0x80000
der Ram block hört bei 24080000 also auf
der nächste block geht ab 0x3000 0000 erst los
das ist kein zusammenhängender block
du könntest also nur 2 getrennte arrays dort speichern
oder ein discovery holen wo schon 8-16MB ram drauf sind
Solocan Z. schrieb:
> Ich habe nun den RAM-Bereich RAM_D1 auf 768K vergrößert
Die Speicherverteilung ist doch eine Lotterie.
Nur, er hat er die Niete gezogen.
LOL.
gre schrieb:> Solocan Z. schrieb:>> Ich habe nun den RAM-Bereich RAM_D1 auf 768K vergrößert, um größere>> rechne mal nach>> 512k block ab 0x2400 0000>> 512k bytes sind 0x80000>> der Ram block hört bei 24080000 also auf> der nächste block geht ab 0x3000 0000 erst los>>> das ist kein zusammenhängender block
Ja, ich habe auch später gelesen, dass STM nicht eine einzige1056kB
physikalische RAM mit 3 logischen konfigiurierbaren Regionen hat,
sondern tatsächlich 3 getrennte RAMs, die auch HWmäßig fest adressiert
sind. War ein Missverständnis von mir.