Hallo zusammen, für den AVR in http://rn-wissen.de/wiki/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc#Dynamischer_RAM-Verbrauch beschrieben, wie man den SRAM mit einem Muster fluten kann, um die Speicherbelegung testen zu können. Das hat sich in der Vergangenheit als sehr praktisch erwiesen. Gibt es für den ARM-GCC für den ARM Cortex M3 (arm-none-eabi-gcc) eine Möglichkeit, auch das SRAM mit Mustern zu füllen? Viele Grüße W.T.
Vielleicht verstehe ich das Problem / Aufgabe nicht, aber was spricht dagegen im Start-Up code in einer Schleife über das gesamte Ram zu gehen und das mit einem Muster zu füllen? mfg Torsten (der auch gerade M3 macht)
Es geht um dynamischen Speicher ohne Speichermanagerin C. Wer kann noch dynamisch Speicher verbrauchen? Und was passiert, wenn dieser Speicherfresser einen bestimmten Wert übeschreitet?
Naja malloc/etc. sind ja Speichermanager. Die einzige, andere dynamisch s Speicherverwaltung, die mir sonst noch einfällt, wäre der Stack. Du möchtest nach Memory-Leaks suchen?
Torsten Robitzki schrieb: > Die einzige, andere dynamisch > s Speicherverwaltung, die mir sonst noch einfällt, wäre der Stack. Und was passiert beim Cortex bei Ovrflow?
Torsten Robitzki schrieb: > Vielleicht verstehe ich das Problem / Aufgabe nicht, Den Speicher mit Mustern zu füllen und anschließend den Inhalt auf einem Display auszugeben ist eine einfache Möglichkeit, die Sicherheitsmarge zwischen Stack und Heap darzustellen und kann per Fotoapparat sogar dabei helfen, einen Memory-Dump herzustellen, ohne daß der Nutzer Hardware hat. Im Bild im Anhang ist das für einen AVR zu sehen: Der RAM wurde im .init3 mit 0xAA gefüllt, so daß der Platz zwischen Stack und Heap direkt ins Auge fällt. Torsten Robitzki schrieb: > aber was spricht > dagegen im Start-Up code in einer Schleife über das gesamte Ram zu gehen > und das mit einem Muster zu füllen? Nichts - wenn man weiß wo und wie. Wer weiß das? Viele Grüße W.T.
Ich habe das Projekt mit den cmsis file von ST aufgesetzt. Da gibt es ein liker file, in dem ist die Länge des Ram-Bereichs und die Start-Adresse des Ram-Bereichs definiert:
1 | /* Specify the memory areas */ |
2 | MEMORY |
3 | {
|
4 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K |
5 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 80K |
6 | } |
das Linkerscript beschreibt da einige RAM-Bereich (welche, die mit Werten aus dem Rom initialisiert werden und welche, die mit 0 gefüllt werden müssen. Danach könntest Du ein Symbol definieren, dass dann auch von C aus zugreifbar wäre:
1 | /* User_heap_stack section, used to check that there is enough RAM left */ |
2 | ._user_heap_stack : |
3 | {
|
4 | . = ALIGN(4); |
5 | _head_start = .; |
6 | PROVIDE ( end = . ); |
7 | PROVIDE ( _end = . ); |
8 | . = . + _Min_Heap_Size; |
9 | . = . + _Min_Stack_Size; |
10 | . = ALIGN(4); |
11 | } >RAM |
Die Funktion, die bei mir den Ram-Bereich initialisiert, wäre in Assembler und hat den Namen Reset_Handler. Jetzt könnte man die Funktion in Assembler schreiben, oder (was vielleicht einfacher ist), einen zusätzlichen Initialisierungsschritt in Form eines zusätzlichen Funktionsaufrufs einfügen:
1 | /* Call memory intitialization function.*/ |
2 | bl WalterInit |
3 | /* Call the clock system intitialization function.*/ |
4 | bl SystemInit |
Dann könnte man in WalterInit() den Bereich von _heap_start bis Ende-Ram füllen. mfg Torsten
Der Default_Reset_Handler() in startup_stm32f10x_md.c stellt den Reset-Handler und ist leicht überschreibbar, da definiert ist:
1 | #pragma weak Reset_Handler = Default_Reset_Handler
|
Hier sind u.A. ein paar Zeilen Assembler, die mir den Bereich zwischen _sbss und _ebss mit Nullen füllen. Also mal das Ganze für mich angepaßt:
1 | void Reset_Handler(void) |
2 | {
|
3 | /* Initialize data and bss */
|
4 | unsigned long *pulSrc, *pulDest; |
5 | |
6 | // Segment mit 0xAAAAAAAA fuellen.
|
7 | __asm(" ldr r0, =_ebss\n" |
8 | " ldr r1, = #33574912\n" // 0x20000000 + 20*1024 |
9 | " mov r2, #2147483647\n" // 0xAAAAAAAA |
10 | " .thumb_func\n" |
11 | "data_loop:\n" |
12 | " cmp r0, r1\n" |
13 | " it lt\n" |
14 | " strlt r2, [r0], #4\n" |
15 | " blt data_loop"); |
16 | |
17 | /* Copy the data segment initializers from flash to SRAM */
|
18 | pulSrc = &_sidata; |
19 | |
20 | for(pulDest = &_sdata; pulDest < &_edata; ) |
21 | {
|
22 | *(pulDest++) = *(pulSrc++); |
23 | }
|
24 | |
25 | /* Zero fill the bss segment. This is done with inline assembly since this
|
26 | will clear the value of pulDest if it is not kept in a register. */
|
27 | __asm(" ldr r0, =_sbss\n" |
28 | " ldr r1, =_ebss\n" |
29 | " mov r2, #0\n" |
30 | " .thumb_func\n" |
31 | "zero_loop:\n" |
32 | " cmp r0, r1\n" |
33 | " it lt\n" |
34 | " strlt r2, [r0], #4\n" |
35 | " blt zero_loop"); |
36 | |
37 | |
38 | |
39 | /* Setup the microcontroller system. */
|
40 | SystemInit(); |
41 | |
42 | /* Call the application's entry point.*/
|
43 | main(); |
44 | }
|
Beim Dump des SRAMs sehe ich allerdings keine AAAAAAAA im SRAM-also vermutlich das falsche Segment?
Walter Tarpan schrieb: > Hier sind u.A. ein paar Zeilen Assembler Warum glauben die Hobbybastler, dass sie in asm besser codieren als ein C Compiler?
nix Versteher schrieb: > Warum glauben die Hobbybastler, dass sie in asm besser codieren als ein > C Compiler? Weil es einem der C-Compiler möglicherweise übel nimmt, wenn man den gesamten RAM Speicher überschreibt! Stichwort: Variablen auf dem Stack. Bin auch kein Fan von (längerem) Assemblercode, aber es gibt nun mal Situationen, da macht es schlicht und ergreifend Sinn!
No, mit nem Pionter gehts ganz einfach durch den ganzen Adressraum. asm ist hier voll überflüssig!
nix Versteherr schrieb: > No, mit nem Pionter gehts ganz einfach durch den ganzen Adressraum. asm > ist hier voll überflüssig! Du kannst dir nicht sicher sein, dass die Variable im Register liegt. Die Wahrscheinlichkeit ist zwar hoch, aber du hast keine 100%
nix Versteher schrieb: > arum glauben die Hobbybastler, dass sie in asm besser codieren als ein > C Compiler? Als Hobbybastler glaube ich zumindest, daß ich das nicht besser in C implementiert bekomme als die Leute von STM, die den Startup-Code in ASM gemacht haben. Kennt jemand eine gute Übersicht über das Speicher-Layout der STM32?
Walter Tarpan schrieb: > Als Hobbybastler glaube ich zumindest, daß ich das nicht besser in C > implementiert bekomme als die Leute von STM, die den Startup-Code in ASM > gemacht haben. Und dort kann man keine C aufrufen? Dann musst du die main ja auch in ASM implementieren. ;->
Walter Tarpan schrieb: > Kennt jemand eine gute Übersicht über das Speicher-Layout der STM32? Was genau meinst Du damit? Die Memory Map (wo die einzelnen Peripherieeinheiten liegen, steht ja im RM) wirst Du wohl nicht meinen und wie das int. SRAM sich in Vektortabelle, DATA, BSS, Heap und Stack aufteilt, sollte aus dem Linkerscript/Mapfile hervor gehen. Zu Ramtest: http://www.ganssle.com/articles/ramtest.htm http://www.ganssle.com/testingram.htm Wobei diese m.E. eher bei ext. RAM wg. Verdrahtungsfehlern, Lötbrücken und nicht angelöteten IC-Beinchen Sinn machen. Bei int. SRAM kann/sollte dies ja nicht vorkommen.
Walter Tarpan schrieb: > Beim Dump des SRAMs sehe ich allerdings keine AAAAAAAA im SRAM-also > vermutlich das falsche Segment? Das bss ist in meinem Linker-Script auch das letzte Segment. Du füllst ab Ende-BSS bis Ende-BSS + 20k. Das klingt relativ willkürlich, ist für einen ersten Test aber ggf. ok. Wenn das bss das letzte Segment ist, dann möchtest Du eigentlich von ebbs bis Ende-Ram (Anfang-Ram + Größe Ram) mit Deinem Füllmuster füllen. Alternativ könntest Du natürlich als allerersten Schritt den gesamten Ram-Bereich mit Deinem Muster füllen. Dann wird ein Teil wieder überschrieben, aber ggf. stört Dich das nicht. Vielleicht initialisiert Dir Deine Runtimelibrary aber auch zumindest den Bereich, in dem der Heap liegt. Vielleicht gibst Du im Dump auch den flahscen Bereich aus? Und den Stack bekommst Du natürlich mit Assembler zuverlässig initialisiert, weil Du dort keine auf dem Stack liegenden Laufvariablen verwenden möchtest. mfg Torsten Edit: Und meine Idee mit der zusätzlichen Funktion funktioniert natürlich auch nicht, da die Funktion beim initialisieren des Stacks natürlich auch die auf dem Stack liegende Rücksprungadresse zuschießen würde.
Warum können solch engagierte Programmierer sich bloß nicht einen
simplen RAM-Test selber schreiben?
Ich zitiere hier mal nen steinalten RAM-Test, den ich in meinen Annalen
gefunden habe:
/* ein billiger RAM Test: Bereich ist eigentlich A0000000 .. AFFFFFFF
aber ab A1000000 friert der uC ein - anstelle Data Abort.
*/
void ExtRamTest(void)
{ dword* PDW;
dword* PDW0;
dword* PDEND;
PDEND = (dword*) CgBWSP;
PDW0 = PDW = (dword*) ExtRamBegin;
*PDW0 = 0x4711AFFE;
++PDW;
while ((PDW < PDEND) && (*PDW0 == 0x4711AFFE))
{ *PDW = 0xFFFEFFFE;
++PDW;
}
*PDW0 = 0xFFFEFFFE;
while (PDW0 < PDW)
{ if (*PDW0 == 0xFFFEFFFE) *PDW0 = *PDW0 + 0x10002;
++PDW0;
}
PDW0 = (dword*)ExtRamBegin;
while ((PDW0 < PDW) && (*PDW0==0)) ++PDW0;
ExtRamSize = (dword)PDW0 - (dword)ExtRamBegin;
}
/* ende */
So, wer will, der mache sich was draus.
W.S.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.
