Forum: Mikrocontroller und Digitale Elektronik STM32F4 - Problem mit Array größe, Variable wird überschrieben


von Stefan (Gast)


Lesenswert?

Hallo zusammen,

Ich habe ein Problem bei einem Projekt auf dem STM32f407 uC.
IDE CooCox CoIDE 1.7.8
Toolchain Arm none eabi 4.8 2014q1

(hab aber auch schon CoIDE 2.0.3 und und die neuere 4.9 2015q2 getestet)

Das gesamte Projekt ist schon etwas umfangreicher und lief bis dahin 
auch alles soweit (Taster, TFT über FSMC, UART Kommunikation mit 
externer Hardware... )

Beim Anlegen eines Arrays kam es jetzt zu dem Problem, dass sich der 
Controller aufgehangen hat wenn es mit 600 Elementen deklariert wurde.
1
uint32_t One_Second_Data_Storage[600];

Bis 100 Elemente läuft der Code und ab 1000 auch.
-> Also erstmal mit 1000 probiert.
Beim kontrollieren der Daten im Array ist dann aufgefallen das Teile 
darin Fehlerhaft sind. (Darin sind Messwerte gespeichert und die 
Fehlerhaften Daten können nicht vom Sensor kommen, das wurde 
ausgeschlossen)
Die Fehlerhaften Teile sind vermutlich durch überschreiben entstanden.

Im nächsten Schritt hab ich  versucht die exakte Stelle herauszufinden 
wo der Cotnroller sich verabschiedet.
An anderer Stelle im Programm wo ein globales Array
1
volatile uint8_t G_UART_Receive_Buffer [1000];
(Ein Receive Buffer der soweit auch richtig befüllt wird) wieder auf 0 
zurück gesetzt wird bleibt er in einer Schleife hängen.
1
void Clear_UART_Buffer (void)
2
{
3
  uint32_t count = 0;
4
  uint32_t count_add = &count;
5
  uint32_t j = 0;
6
  j++;    //Debug Function Call Counter
7
  char Buff[20];
8
  Toggle_Watchdog();
9
  sprintf(Buff, "bug: %7d", j); // Debug
10
  Font_DrawString(355,115,Buff,&Arial_7x10,G_Col_Text,G_Col_Backgroung); //Debug
11
12
  for (count = 0; count< 1000; count++)
13
  {
14
     Toggle_Watchdog();
15
    G_UART_Receive_Buffer[count] = 0;
16
     // Systick_Pause_ms(250);
17
    sprintf(Buffy, "bug: %7d", count); // Debug
18
    Font_DrawString(355,130,Buff,&Arial_7x10,G_Col_Text,G_Col_Backgroung); // Debug
19
20
  }
21
  G_UART_Buffer_Position = 0;
22
}

Problem hier scheint zu sein das die Count Variable überschrieben wird.
und zwar laut Memory Viewer von dem globalen Array (Receive Buffer)

Adresse vom Receive Buffer 0x20005FD4
Adresse von Count          0x2000607C

Zwischen dem Array und der Count Variable sind nur 168 Byte obwohl das 
Array mit 1000 deklariert wird.
Das scheint das Problem zu sein.

Wer ist denn verantwortlich für die Verteilung von Variablen im Speicher 
? Compiler ?

Vielleicht kommt es ja schon an anderer Stelle zu einem Problem und das 
zieht sich nur bis dahein durch ...

An den Grenzen vom Controller bin ich noch lange nicht angelangt, 
vorausgesetzt die Werte bei .text .data und .bss nach dem Kompilieren 
stimmen.

Hat jemand eine Idee was man hier machen kann ?

Vielen Dank schonmal & Viele Grüße
Stefan

von Little B. (lil-b)


Lesenswert?

das sieht nach einem extrem umfangreichen Projekt aus! Benutzt du ein 
RTOS?

Angenommen, du hast kein RTOS am laufen, dann hast du bis zu diesem 
genannten Punkt einen Stack von fast 90kB angehäuft.
Dann bleiben etwa noch 20kB für static und global übrig.

Das sieht nach einem "Stack overflow" aus, oder Stack collision, oder 
wie auch immer man das nennen mag.

Arm none eabi 4.8 2014q1 ist doch GCC? Dann probier mal, was der static 
stack analysis sagt. Kompiliere mit
1
-fstack-usage

: Bearbeitet durch User
von Ingo L. (corrtexx)


Lesenswert?

Little B. schrieb:
> Angenommen, du hast kein RTOS am laufen, dann hast du bis zu diesem
> genannten Punkt einen Stack von fast 90kB angehäuft.
> Dann bleiben etwa noch 20kB für static und global übrig.
Darf man fragen wie du auf die 90kB kommst?

von Little B. (lil-b)


Lesenswert?

Ingo L. schrieb:
> Little B. schrieb:
>> Angenommen, du hast kein RTOS am laufen, dann hast du bis zu diesem
>> genannten Punkt einen Stack von fast 90kB angehäuft.
>> Dann bleiben etwa noch 20kB für static und global übrig.
> Darf man fragen wie du auf die 90kB kommst?

der STM32F407 hat 112kB RAM, das ist dann Endadresse 0x2001C000

Stefan schrieb:
> Adresse von Count          0x2000607C

0x2001C000 - 0x2000607C = 0x15F84 = 89988

von Ingo L. (corrtexx)


Lesenswert?

Little B. schrieb:
> 0x2001C000 - 0x2000607C = 0x15F84 = 89988
Aber ist das nicht von hinten gezählt? Ich denke eher das ist der Platz 
den er noch frei hat! Weil Variablen werden doch bei 0 (hier 0x20000000) 
angelegt, oder landen temporäre Daten aufm Stack???

Verbraucht würde ich eher sagen 607C = 24,7kB.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Ingo L. schrieb:
> Little B. schrieb:
>> 0x2001C000 - 0x2000607C = 0x15F84 = 89988
> Aber ist das nicht von hinten gezählt?
Klar, denn der Stack beginnt hinten und wächst nach vorne.
> Ich denke eher das ist der Platz
> den er noch frei hat!
Nein
> Weil Variablen werden doch bei 0 (hier 0x20000000)
> angelegt
Nein
> oder landen temporäre Daten aufm Stack???
Ja natürlich, denn dafür ist der Stack da (neben den 
Rücksprungadressen).

von Stefan (Gast)


Lesenswert?

Vielen Dank schonmal für die bisherigen Antworten.

Ich habe nun mal das ganze mit fstack usage kompiliert und alle Werte 
aus allen files addiert. Dabei kommt was um die ca 11000 Byte raus.

Beim kompilieren steht hinterher drunter:
      text     data      bss      dec      hex
    318412     2372    25212   345996    5478c

da sehe ich also auch nicht wirklich ein Problem.

Allerdings sind im Memory View folgende Bereiche belegt:
20000000 - 20002508
20005E10 - 200060B8
200064F0 - 2001BFFF (und hier sehen die Werte irgendwie verdächtig aus 
und gehen auch über die Addresse im selben Stil weiter)


Werden bei dem fstack usage irgendwelche Sachen ausser acht gelassen ?

Sehe ich das richtig das es sich bei dem .text um den belegten Flash 
handelt und bei .bss um den belegten RAM ?

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


Lesenswert?

Stefan schrieb:
> Sehe ich das richtig das es sich bei dem .text um den belegten Flash
> handelt und bei .bss um den belegten RAM ?

So isses. Du kannst dir ja mal das *.map file anschauen, alles hinter 
der ersten '.bss' Marke wird dir bekannt vorkommen, da stehen deine 
globalen Variablen ziemlich zu Anfang, mit der jeweiligen Länge.
Ich sehe in meinen mapfiles produziert von Coocox übrigens keine Nutzung 
des 64k Corememory, mit einem entsprechenden Linkerskript sollte man die 
zusätzlich nutzbar machen können.
1
Memory Configuration
2
3
Name             Origin             Length             Attributes
4
rom              0x08000000         0x00100000         xr
5
ram              0x20000000         0x00020000         xrw
6
ram1             0x10000000         0x00010000         xrw
Erklärt ist der Bereich also schon.

von Patrick B. (p51d)


Lesenswert?

Grundsatzfrage:
Wieso brauchst du so ein grosses Array?
Mach doch ein kleiner FIFO mit einem anständigen Protokoll und 
Fehlerhandling, dann kommst du auch mit einem kleineren Array von 50-100 
aus.

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


Lesenswert?

Patrick B. schrieb:
> Grundsatzfrage:
> Wieso brauchst du so ein grosses Array?

Ich z.B. brauche sowas als Audiodaten Puffer, um die Zugriffe auf USB 
Speicher in Grenzen zu halten. Habe hier allerdings keine Probleme mit 
2*48kB Arrays.

von Little B. (lil-b)


Lesenswert?

Stefan schrieb:
> Beim kompilieren steht hinterher drunter:
>       text     data      bss      dec      hex
>     318412     2372    25212   345996    5478c
>
> da sehe ich also auch nicht wirklich ein Problem.

Du hast also 25kByte Globalen RAM, der mit 0 initialisiert wird (bss), 
und nochmals 2kByte RAM, der mit Werten aus dem Flash vorinitialisiert 
wird (data). Zusammen sind das schonmal etwa 27kByte RAM, die belegt 
sind.

Was du hier nicht siehst, ist der Stack. Dein Stack darf jetzt nicht 
mehr größer werden als 87kByte, es sei denn, du schaufelst die globalen 
daten in ein anderes SRAM (z.B. SRAM2, das hat 16kByte, oder CCM SRAM, 
das hat 64kByte)(Modifikationen im Linkerfile!)

Anderer Vorschlag:
Du legst im Linkerfile eine Marke hinter die .bss-Section und schützt an 
der Stelle vier Bytes mit Hilfe der MPU. Sobald die MPU einen Interrupt 
auslöst, hast du eine Stack-Collision.
OK, zugegeben, das behebt noch nicht dein Problem. Aber auf diese Weise 
kannst du ein unvorhergesehenes Verhalten eines Programms verhindern.

von Stefan (Gast)


Angehängte Dateien:

Lesenswert?

Danke schonmal für die Hilfe.

Leider hat bisher nichts eine Lösung ergeben.
Was mich verwundert ist wie ich >70kB Stack zusammen bekommen soll.
Und wo das herkommen soll.
Die 11kB die beim zusammenzählen der fstack-usage Files waren 
realistisch.
Die 25 + 2 kB die nach dem Build dastehen kommen auch so etwa hin.
Zusammen also noch nicht mal annähernd im kritischen Bereich.


Patrick B. schrieb:
> Grundsatzfrage:
> Wieso brauchst du so ein grosses Array?

Das Array brauch ich weil ich ohne Unterbrechung Messwerte sammeln muss 
mit denen dann hinterher noch ein paar Berechnungen gemacht werden und 
dann in einen externen Flash gespeichert werden.
Auf das Protokoll habe ich auch keinen Einfluss das die angeschlossene 
Hardware von extern kommt.

Ich habe mir das .map File mal angeschaut bin aber nicht so wirklich 
schlau draus geworden.
Daher nun im Anhang. Vielleicht könnte bitte jemand mal drüber schaun ob 
da irgendwas komisch ist.

Little B. schrieb:
> Anderer Vorschlag:
> Du legst im Linkerfile eine Marke hinter die .bss-Section und schützt an
> der Stelle vier Bytes mit Hilfe der MPU. Sobald die MPU einen Interrupt
> auslöst, hast du eine Stack-Collision.
> OK, zugegeben, das behebt noch nicht dein Problem. Aber auf diese Weise
> kannst du ein unvorhergesehenes Verhalten eines Programms verhindern.

Das werde ich mal ausprobieren. Vielleicht kann man so auch rausfinden 
welche Funktion das verursacht?


Vielen Dank schonmal

von Little B. (lil-b)


Lesenswert?

Das Mapfile zeigt keine offensichtlichen Fehler. Deshalb müsste man sich 
den Callstack mal anschaun.

Für die MPU hab ich mal folgendes zusammengepfuscht:
1
extern uint8_t _ebss;
2
MPU->RNR = 0;
3
MPU->RBAR = (uint32_t)&_ebss;
4
MPU->RASR = 0x9;
5
MPU->CTRL = 0x5;

Jetzt musst du nur noch vor die _ebss Marke im Linkerskript
1
. = ALIGN (0x20)
schreiben. Ungetestet und Benutzung auf eigene Gefahr!

: Bearbeitet durch User
von Stephan (Gast)


Lesenswert?

Hi,
hab mal ein Blick in dein MAP-File geworfen.
Du benutzt eine art malloc??? Wie viel Speicher ist da reserviert und 
welcher? (oder ist der heap = 0 ?)
Zur Zeit benutzt du nur den 'ram' Bereich, der andere ist unbenutzt? 
(ram1)
1
0x20020000                __StackTop = (ORIGIN (ram) + 0x20000)
2
0x2001f800                __StackLimit = (__StackTop - SIZEOF (.co_stack))
Das ist dein Stackbereich! 2KB

von Little B. (lil-b)


Lesenswert?

Stephan schrieb:
> Hi,
> hab mal ein Blick in dein MAP-File geworfen.
> Du benutzt eine art malloc??? Wie viel Speicher ist da reserviert und
> welcher? (oder ist der heap = 0 ?)
> Zur Zeit benutzt du nur den 'ram' Bereich, der andere ist unbenutzt?
> (ram1)
> 0x20020000                __StackTop = (ORIGIN (ram) + 0x20000)
> 0x2001f800                __StackLimit = (__StackTop - SIZEOF
> (.co_stack))
> Das ist dein Stackbereich! 2KB

Das ist mir auch aufgefallen

malloc wird von sprintf verwendet und hat seinen eigenen globalen 
Speicher in der bss-Section. Ich sehe hier kein Problem.

Ja, die Stack-Größe ist falsch angegeben, aber das wird nirgends 
evaluiert, daher egal.

von Stephan (Gast)


Lesenswert?

Dann leg doch mal zum testen den Stack in den Bereich von 'ram1', dann 
kannst du sicher sein das da kein Speicher vom Stack überschrieben 
wird!!!

Little B. schrieb:
> Ja, die Stack-Größe ist falsch angegeben, aber das wird nirgends
> evaluiert, daher egal.

Doch schon!
Dein RAM wird kleiner!

Dein Programm wird in unterschiedliche Teilbereiche(CONST,VAR...) 
zerlegt und diese werden in die von 'dir' bereit gestellten 
Speicher-Bereiche wie RAM, ROM, EEPROM zugeteilt. Werden nun die 
Teilbereiche zu groß für die Speicher-Bereiche bekommst du eine 
Fehlermeldung!!!!

von Little B. (lil-b)


Lesenswert?

Der RAM kann gar nicht kleiner werden.
Er kann höchstens unterschiedlich aufgeteilt sein.

Fakt ist, dass die Linker-Marke "__StackLimit" in der Applikation nicht 
verwendet wird, sondern nur zur Überwachung zum Link-Zeitpunkt dient.

Da der TO aber offenbar nicht so recht den Überblick über seinen Stack 
hat, kann er hier keinen aussagekräftigen Wert eintragen.

Ein Linker-Error würde erzeugt werden, wenn er im aktuellen Projekt eine 
Stack-Size von 100k angeben würde. Aber was würde das am realen 
Verhalten des Programms ändern?

von Stefan (Gast)


Lesenswert?

Little B. schrieb:
> Das Mapfile zeigt keine offensichtlichen Fehler. Deshalb müsste man sich
> den Callstack mal anschaun.

Das geht mit bt und frame Befehl in der command line von CoIDE oder ist 
damit was anderes gemeint bzw gibts nen anderen Weg ?

Little B. schrieb:
> Jetzt musst du nur noch vor die _ebss Marke im Linkerskript. = ALIGN
> (0x20)
> schreiben.

Ok dann muss ich mich erstmal mit Linkerskript schreiben generell 
auseinander setzen da ich bisher nur die Standard Link Konfigurationen 
von CoIDE nutze ohne ein extra Linkfile einzubinden.

Stephan schrieb:
> Du benutzt eine art malloc??? Wie viel Speicher ist da reserviert und
> welcher? (oder ist der heap = 0 ?)

Das ist tatsächlich das malloc von sprintf das ich für meine debug 
Ausgaben verwende. Was meinst du mit Heap in dem Zusammenhang ??

Stephan schrieb:
> Zur Zeit benutzt du nur den 'ram' Bereich, der andere ist unbenutzt?
> (ram1)
> 0x20020000                __StackTop = (ORIGIN (ram) + 0x20000)
> 0x2001f800                __StackLimit = (__StackTop - SIZEOF
> (.co_stack))
> Das ist dein Stackbereich! 2KB

Ja ich nutze nur den Bereich ab 0x20000000. die anderen Bereiche müsste 
man im Source ja explizit ansprechen damit diese genutzt werden, richtig 
?

Das mit dem Stackbereich scheint dann eine Standard Einstellung von 
CooCox zu sein. Kann ich das ändern bzw ist das auch etwas was im 
Linkerfile gemacht wird und CooCox hinter meinem Rücken macht sofern ich 
kein eigenes Linkerskript benutze ?

Little B. schrieb:
> Da der TO aber offenbar nicht so recht den Überblick über seinen Stack
> hat, kann er hier keinen aussagekräftigen Wert eintragen.

Gibt es da eine Methodik den besser im Überblick zu behalten ? Ich habe 
mir tatsächlich bisher nie große Gedanken über sowas gemacht. Muss ich 
nun etwa Buchführung darüber betreiben wieviel da jede Funktion belegt ? 
Ich dachte bisher immer wenn irgendwas Speichermäßig knapp wird, wird 
mir das nach dem build angezeigt (da war ich wohl zu naiv ...)

von Stephan (Gast)


Lesenswert?

Hey Little
ka wie es bei dir ist, aber der Heap und der Stack wird normaler weise 
von dem zur Verfügung stehendem RAM abgezogen und kann so nicht mehr als 
Variablen-. oder 'RAM-Funktion'-Speicher zur Verfügung stehen!!!!

Stefan schrieb:
> Das ist tatsächlich das malloc von sprintf das ich für meine debug
> Ausgaben verwende. Was meinst du mit Heap in dem Zusammenhang ??

Ok. Heap ist der Speicher den malloc nutzt.(dyn. Speicher + Verwaltung)
Kannst du nicht auf snprintf ausweichen. (einer Funktion ohne malloc!)

Stefan schrieb:
> Ja ich nutze nur den Bereich ab 0x20000000. die anderen Bereiche müsste
> man im Source ja explizit ansprechen damit diese genutzt werden, richtig
> ?

ja, geht aber ganz einfach. Hast du schon eine section im 'ram1'?
Du wirst ja nicht der erste sein der den Speicher nutzen will.

von Stefan (Gast)


Lesenswert?

Kleines Update.
Ich habe nun mal an einigen Stellen im Code Platz eingespart von zB. 
Arrays die etwas großzügiger dimensioniert waren.
Jetzt komme ich auf data 2364 und bss 8012. Also eine merkliche 
Verringerung
an beutztem RAM.
Das verhalten bleibt jedeoch das gleiche. Also denke ich, dass das 
Problem vielleicht doch an einer anderen Stelle liegt.
Ich werde das Projekt mal neu aufsetzen und in diesem Zuge auch noch 
alte Codestellen rauswerfen von früheren Versionen um auszuschliessen, 
dass da noch ein Fehler besteht.

Noch eine Frage bezüglich des Überbliks über den Stack Verbrauch.
Wie kann ich das denn gut im Überblick behalten ?
Schon nach dem einbinden der CMSIS Libs von ST wird ja hier bereits 
Platz belegt.
Welche Sachen kommen denn genau auf den Stack ? Zur Not schreib ich mir 
das halt wirklich auf aber vielleicht hat jemand von euch einen Tip wie 
man das strukturierter angehn kann.

Danke schonmal
Stefan

von Little B. (lil-b)


Lesenswert?

Stephan schrieb:
> Hey Little
> ka wie es bei dir ist, aber der Heap und der Stack wird normaler weise
> von dem zur Verfügung stehendem RAM abgezogen und kann so nicht mehr als
> Variablen-. oder 'RAM-Funktion'-Speicher zur Verfügung stehen!!!!

Das kommt darauf an, wie die IDE den Speicher verwaltet. Meistens wirds 
dann doch nur mit linkerfiles (wie es hier der fall ist) geregelt.

Veranschaulichen wir uns eben mal den RAM. Dieser beginnt bei 0x20000000 
und hört bei 0x20020000 auf (SRAM1 und SRAM2 sind in diesem Linkerfile 
zusammengefasst). Erst kommt .data rein, dann .bss, dann .heap und ans 
Ende wird .stack angehängt
1
0x20000000               _ebss   __HeapLimit     __StackLimit   _StackTop
2
  +--------+----------------+-------+-----------------+------------+
3
  | .data  |     .bss       | .heap |    (free)       |    .stack  |
4
  +--------+----------------+-------+-----------------+------------+

Ein Fehler wird (laut mapfile siehe oben) nur dann erzeugt, wenn 
__HeapLimit größer als __StackLimit ist!
1
ASSERT ((__StackLimit >= __HeapLimit), region ram  overflowed with stack)


Stefan schrieb:
> Gibt es da eine Methodik den besser im Überblick zu behalten ? Ich habe
> mir tatsächlich bisher nie große Gedanken über sowas gemacht.

Ich hab mich die letzten Tage mit dem Thema beschäftigt, weil ich in 
dieser Hinsicht bisher auch immer sehr blauäugig war. Der GCC kann laut 
diversen Internetforen den Befehl "-fstack-usage" und 
"-fcallgraph-info". Diese beiden Befehle spucken dann (angeblich) alle 
nötigen Informationen aus, um den Stack berechnen zu können. Dummerweiße 
kann der GNU Crosscompiler (version 4.9 2015q2) nur das "-fstack-usage".
Dass es eine Funktion gibt, die dir eine Aussage trifft wie etwas "Dein 
Programm braucht 42kByte Stack" habe ich noch nicht gefunden. (Statisch! 
Nicht in Laufzeit! Denn das wäre ja lächerlich einfach)

von foo (Gast)


Lesenswert?

Little B. schrieb:
> kann der GNU Crosscompiler (version 4.9 2015q2) nur das "-fstack-usage".
> Dass es eine Funktion gibt, die dir eine Aussage trifft wie etwas "Dein
> Programm braucht 42kByte Stack" habe ich noch nicht gefunden. (Statisch!

nun -fstack-usage gibt dir diese Information ja auf Funktionsebene. Das 
hielt ich für mich schon für ganz brauchbar.

Wie sich das jetzt aufsummiert zu einem maximalen Stackverbrauch, den 
dein Programm hat, hängt davon ab, wie die Funktionen sich aufrufen (die 
Summe vom Verbrauch aller Funktionen ist es jedenfalls nicht) Ich denke 
nicht dass ein Compiler dir letzteres abnehmen kann.

Es gibt noch -Wstack-usage=100 womit du eine Warning für jede Funktion 
bekommst die mehr als 100 Byte Stack verbraucht.

von Stefan (Gast)


Lesenswert?

Little B. schrieb:
> Veranschaulichen wir uns eben mal den RAM. Dieser beginnt bei 0x20000000
> und hört bei 0x20020000 auf (SRAM1 und SRAM2 sind in diesem Linkerfile
> zusammengefasst). Erst kommt .data rein, dann .bss, dann .heap und ans
> Ende wird .stack angehängt0x20000000               _ebss   __HeapLimit
> __StackLimit   _StackTop
>   +--------+----------------+-------+-----------------+------------+
>   | .data  |     .bss       | .heap |    (free)       |    .stack  |
>   +--------+----------------+-------+-----------------+------------+


Danke jetzt wird das ganze schon verständlicher :)

foo schrieb:
> Es gibt noch -Wstack-usage=100 womit du eine Warning für jede Funktion
> bekommst die mehr als 100 Byte Stack verbraucht.

Guter Tip bleibt ab sofort an, das Limit kann man ja auch noch ein 
bisschen runter stellen.

Ich denke ich habe jetzt das Problem gefunden. Im Startup Code war der 
Stack auf 512 Byte begrenzt, wenn ich den auf 4096 Byte einstell läuft 
alles. Mal sehn obs auch so bleibt :D

Im File startup_stm32f4xx.c
1
/*----------Stack Configuration-----------------------------------------------*/
2
#define STACK_SIZE       0x00001000      /*!< The Stack size suggest using even number    */
3
__attribute__ ((section(".co_stack")))
4
unsigned long pulStack[STACK_SIZE];


Little B. schrieb:
> Dass es eine Funktion gibt, die dir eine Aussage trifft wie etwas "Dein
> Programm braucht 42kByte Stack" habe ich noch nicht gefunden. (Statisch!
> Nicht in Laufzeit! Denn das wäre ja lächerlich einfach)

In Laufzeit würde man das über den Stackpointer machen oder ?


Vielen Dank nochmal an alle.

von Stefan (Gast)


Lesenswert?

Ich hab jetzt mal mit der __get_MSP() Funktion mir den Wert vom 
Stackpointer geholt und zwar direkt nach Programmstart. Dieser kommt mir 
jedoch etwas seltsam vor.
Nach meinem Verständnis hätte ich den Wert jetzt ca bei 0x20000000 + 
0x20000 erwartet (also ziemlich Ende vom RAM plus minus paar Byte von 
den Vars in Main).
Herausgekommen ist ein Wert von 0x20006060.
Die Adresse kommt eher an  RAM Start + .data + .bss hin.

Wenn ich nun ein uint32 anlege geht der SP auf 0x20006058. Das passt 
also zu der Theorie das es nach links wächst. Die 8 Byte kommen wohl 
wegen dem Alignment vom SP - warum auch immer.

Bleibt noch die Frage warum Ich bereits vor einem Funktionsaufruf schon 
derart viel Stack verbraucht haben soll.

von Little B. (lil-b)


Lesenswert?

was steht denn genau in deiner Vector-Tabelle? Mich verwirrt gerade die 
".co-stack" Section.
Ich hätte so etwas erwartet (man achte immer auf den ersten Eintrag):

In C:
1
// The vector table.
2
// This relies on the linker script to place at correct location in memory.
3
4
__attribute__ ((section(".isr_vector"),used))
5
pHandler __isr_vectors[] =
6
  {
7
  // Core Level - CM4
8
      (pHandler) &_estack,                      // The initial stack pointer
9
      Reset_Handler,                            // The reset handler
10
11
      NMI_Handler,                              // The NMI handler
12
      HardFault_Handler,                        // The hard fault handler
13
      ...

Oder in ASM:
1
   .section  .isr_vector,"a",%progbits
2
  .type  g_pfnVectors, %object
3
  .size  g_pfnVectors, .-g_pfnVectors
4
    
5
    
6
g_pfnVectors:
7
  .word  _estack
8
  .word  Reset_Handler
9
  .word  NMI_Handler
10
  .word  HardFault_Handler
11
  .word  MemManage_Handler
12
  .word  BusFault_Handler
13
  .word  UsageFault_Handler
14
  .word  0
15
  .word  0
16
  .word  0
17
...

Wenn dein StackPointer aber auf das ende von .co-stack initialisiert 
wird, ist es klar, dass der Stack nicht reicht.
Dann ist es auch Blödsinn mit den 90kByte Stackverbrauch, die ich zu 
anfang geschrieben hatte.

von 234897897676878844 (Gast)


Lesenswert?

ich hab auch diverse sachen mit CoIDE durch ...
damals auch anfängliche probleme mit stack und heap gehabt.

ich habe das linker file geändert
1
    
2
    . = ALIGN(4);
3
    __HeapStart = . ;
4
    __StackStart = ORIGIN(ram) + LENGTH(ram) - 32 - 16 ;  
5
    __HeapEnd   = __StackStart - 1024;

die -32-16 ist ein errata zum LPC17xx
aber so setze ich den stack wirklich ans ende
das __HeapEnd  markiert ende heap und damit anfang stack

in der startup:
1
void (* const g_pfnVectors[])(void) =
2
{  
3
  /*----------Core Exceptions------------------------------------------------ */
4
  (void *)&__StackStart,//(void *)&pulStack[STACK_SIZE-1],     /*!< The initial stack pointer         */

in der syscalls.c
1
__attribute__ ((used))
2
caddr_t _sbrk (int size){
3
   static unsigned char *heap = NULL;
4
   unsigned char *prev_heap;
5
6
   if (heap == NULL) {
7
     heap = (unsigned char *)&__HeapStart;
8
   }
9
   prev_heap = heap;
10
11
   if((heap + size) > (unsigned char *)&__HeapEnd ){
12
      errno = ENOMEM;
13
      return (caddr_t) -1;
14
   }
15
   heap += size;
16
17
   HeapAvailable = (unsigned char *)&__HeapEnd - heap;
18
19
   return (caddr_t) prev_heap;
20
}

das HeapAvailable lasse ich mir dann manchmal ausgeben ..
damit sieht man wieviel heap noch übrig ist

das ENOMEM ist original nicht mit drin ..
wenn malloc also fehlschalgen sollte kracht es einfach ohne 
fehlermeldung
da malloc_r keinen fehler bekommt und munter drauflos schreibt

von Stefan (Gast)


Lesenswert?

Little B. schrieb:
> was steht denn genau in deiner Vector-Tabelle? Mich verwirrt gerade die
> ".co-stack" Section.
1
__attribute__ ((used,section(".isr_vector")))
2
void (* const g_pfnVectors[])(void) =
3
{
4
  /*----------Core Exceptions------------------------------------------------ */
5
  (void *)&pulStack[STACK_SIZE],     /*!< The initial stack pointer         */
6
  Reset_Handler,             /*!< Reset Handler                               */
7
  NMI_Handler,               /*!< NMI Handler                                 */
8
  HardFault_Handler,         /*!< Hard Fault Handler                          */
9
  MemManage_Handler,         /*!< MPU Fault Handler                           */
10
  BusFault_Handler,          /*!< Bus Fault Handler                           */
11
  UsageFault_Handler,        /*!< Usage Fault Handler                         */
12
  0,0,0,0,                   /*!< Reserved                                    */
13
  SVC_Handler,               /*!< SVCall Handler                              */
14
  DebugMon_Handler,          /*!< Debug Monitor Handler                       */
15
  0,                         /*!< Reserved                                    */
16
  PendSV_Handler,            /*!< PendSV Handler                              */
17
  SysTick_Handler,           /*!< SysTick Handler                             */

und das steht davor noch:
1
/*----------Stack Configuration-----------------------------------------------*/
2
#define STACK_SIZE       0x00000400      /*!< The Stack size suggest using even number    */
3
__attribute__ ((section(".co_stack")))
4
unsigned long pulStack[STACK_SIZE];

Wenn man hier die Stacksize ändert wird .bss nach dem kompilieren auch 
größer. Ein Versuch mit einem leeren Projekt hat das jetzt auch nochmal 
bestätigt, dass sich der Stack nicht am Ende befindet.

234897897676878844 schrieb:
> ich hab auch diverse sachen mit CoIDE durch ...
> damals auch anfängliche probleme mit stack und heap gehabt.
>
> ich habe das linker file geändert
>     . = ALIGN(4);
>     __HeapStart = . ;
>     __StackStart = ORIGIN(ram) + LENGTH(ram) - 32 - 16 ;
>     __HeapEnd   = __StackStart - 1024;
1
  .heap (COPY):
2
  {
3
    __end__ = .;
4
    _end = __end__;
5
    end = __end__;
6
    *(.heap*)
7
    __HeapLimit = .;
8
  } > ram 
9
  /* .stack_dummy section doesn't contains any symbols. It is only
10
  *used for linker to calculate size of stack sections, and assign
11
  * values to stack symbols later */
12
  .co_stack (NOLOAD):
13
  {
14
    . = ALIGN(8);
15
    *(.co_stack .co_stack.*)
16
  } > ram 
17
18
  /* Set stack top to end of ram , and stack limit move down by
19
  * size of stack_dummy section */
20
  __StackTop = ORIGIN(ram ) + LENGTH(ram );
21
  __StackLimit = __StackTop - SIZEOF(.co_stack);
22
  PROVIDE(__stack = __StackTop);
23
  
24
  /* Check if data + heap + stack exceeds ram  limit */
25
  ASSERT(__StackLimit >= __HeapLimit, "region ram  overflowed with stack")

Das hier steht in dem Standard Linker File von CoIDE. Was ich hier auch 
nicht verstehe ist das Alignment von 8 Byte. Woher kommt das ? Da die 
meisten Variablen eher <= 4 Byte sind schmeisst man hier doch immer 4 
Byte weg oder ?

Und direkt drunter steht ja eigentlich auch noch: "set stack top to end 
of ram".

von Little B. (lil-b)


Lesenswert?

Ja, ich sehe hier Verbesserungspotential.

Allem voran würde ich den Inital Stack Pointer nicht auf 
&pulStack[STACK_SIZE] setzen, sondern auf &_estack. Damit hast du immer 
den maximal verfügbaren Platz für den Stack, und er ist dort abgelegt, 
wo er hingehört, nämlich ans Ende des RAMs.

Ob die Align(8) Sinn machen, bin ich mir unsicher. Der ARM-Core kann 
sowieso unaligned Speicherzugriffe (lässt sich aber auch abschalten), 
aber ich kenn es, dass Align(4) verwendet wird (wegen 32bit prozessor).

von 234897897676878844 (Gast)


Lesenswert?

Stefan schrieb:
> Wenn man hier die Stacksize ändert wird .bss nach dem kompilieren auch
> größer. Ein Versuch mit einem leeren Projekt hat das jetzt auch nochmal
> bestätigt, dass sich der Stack nicht am Ende befindet.

das pulstack[] array wird dann im bss mit eingerechnet.
da es ja laut linker auch verwendet wird
_attribute_ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];
da co_stack eine gültige marke im ram ist


allerdings hatte ich mit dem co_stack immer den effekt das er am ende 
der variablen lag
>   +--------+----------------+---------+-----------------+
>   | .data  |     .bss       | .stack  |    (free)       |
>   +--------+----------------+---------+-----------------+

als ich dann dynamisch ( malloc )  speicher nutzte krachte es immer

mit der linkervariante ist er immer am ende mit 1024bytes und . = 
ALIGN(4);

von Stefan (Gast)


Lesenswert?

Also vielen Dank nochmal für die Hilfe.
Jetzt klappts :)

Ich habe dann auch gleich mal noch den Stack in den CCM verfrachet.
End of Stack ist dann bei 0x10010000 und ich habe ihn mal auf 32k 
limitiert falls man den CCM an einer anderen Stelle mal noch für was 
braucht.

Dazu hab ich im Linkerskript folgendes geändert:
1
  
2
  /* .stack_dummy section doesn't contains any symbols. It is only
3
  * used for linker to calculate size of stack sections, and assign
4
  * values to stack symbols later */
5
  .co_stack (NOLOAD):
6
  {
7
    . = ALIGN(8);
8
    __StackTop = ORIGIN(ram1) + LENGTH(ram1);
9
    
10
  } > ram 
11
  
12
  /* Set stack top to end of ram , and stack limit move down by
13
  * size of stack_dummy section */
14
  /*__StackTop = ORIGIN(ram ) + LENGTH(ram );*/
15
  __StackLimit = __StackTop - 0x00008000 ;   /* MAX Stack SIZE 32k
16
  PROVIDE(__stack = __StackTop);
17
  
18
  /* Check if data + heap + stack exceeds ram  limit */
19
/*  ASSERT(__StackLimit >= __HeapLimit, "region ram  overflowed with stack")*/

Das Alignment hatte auf den ersten Blick keine Veränderung ergeben bei 4 
statt 8. (Zumindest ist mal nichts abgestürzt :D )


Und im startup_stm32f4xx.c folgendes
1
__attribute__ ((used,section(".isr_vector")))
2
void (* const g_pfnVectors[])(void) =
3
{
4
  /*----------Core Exceptions------------------------------------------------ */
5
  (void *) &__StackTop, //(void *)&pulStack[STACK_SIZE],     /*!< The initial stack pointer         */
6
  // Initial Stack Pointer @ End of CCM ( 0x1000 FFFF)
7
  Reset_Handler,             /*!< Reset Handler                               */
8
  NMI_Handler,               /*!< NMI Handler                                 */
9
  HardFault_Handler,         /*!< Hard Fault Handler                          */
10
  MemManage_Handler,         /*!< MPU Fault Handler                           */
11
  BusFault_Handler,          /*!< Bus Fault Handler                           */
12
  UsageFault_Handler,        /*!< Usage Fault Handler                         */
13
  0,0,0,0,                   /*!< Reserved                                    */
14
  SVC_Handler,               /*!< SVCall Handler                              */
15
  DebugMon_Handler,          /*!< Debug Monitor Handler                       */
16
  0,                         /*!< Reserved                                    */
17
  PendSV_Handler,            /*!< PendSV Handler                              */
18
  SysTick_Handler,           /*!< SysTick Handler                             */

Jetzt darf man nur nich vergessen das richtige Linkerfile und 
Startupfile einzubinden.. :D

von 234897897676878844 (Gast)


Lesenswert?

hi

ich  hasse die getrennten RAM bereiche beim cortex M
bei mir ist es ein LPC1768

32K ram
16k ethernet ram
16k usb ram

ist eben bescheuert

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.