Forum: Mikrocontroller und Digitale Elektronik ARM Cortex M3: SRAM mit Muster füllen


von Walter T. (nicolas)


Lesenswert?

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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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)

von Overflow (Gast)


Lesenswert?

Es geht um dynamischen Speicher ohne Speichermanagerin C.
Wer kann noch dynamisch Speicher verbrauchen? Und was passiert, wenn 
dieser Speicherfresser einen bestimmten Wert übeschreitet?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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?

von Overflow (Gast)


Lesenswert?

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?

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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

von Walter T. (nicolas)


Lesenswert?

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?

von nix Versteher (Gast)


Lesenswert?

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?

von Klaus R. (klausro)


Lesenswert?

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!

von nix Versteherr (Gast)


Lesenswert?

No, mit nem Pionter gehts ganz einfach durch den ganzen Adressraum. asm 
ist hier voll überflüssig!

von Klaus R. (klausro)


Lesenswert?

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%

von Walter T. (nicolas)


Lesenswert?

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?

von gar nix mehr Versteher (Gast)


Lesenswert?

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. ;->

von Arne S. (Gast)


Lesenswert?

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.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.