Forum: Mikrocontroller und Digitale Elektronik Stack im STM32


von Michael S. (michatroniker)


Lesenswert?

Hallo zusammen =)

Ich verwende einen STM32 mit FreeRTOS. Im linker script wird momentan 
1kB für Stack und ein halbes kB für Heap reserviert. Der FreeRTOS Kernel 
holt sich ja nochmal eigenen Heap, also kann ich ja den Heap im Linker 
Script einfach auf 0Byte setzen, richtig?

Jetzt zu dem 1kB Stack: wozu genau brauche ich den und wie finde ich die 
optimale Größe raus?

Ich dachte, dass Funktionen, die von einem FreeRTOS Task heraus 
aufgerufen werden, für lokale Variablen auch den ihnen zugewiesenen 
Stack innerhalb des FreeRTOS Heaps nutzen. Damit brauche ich den 
globalen Stack doch nur so lange, bis der Scheduler des OS läuft, also 
nur für ein paar Initialisierungen? da würden doch 100Byte locker 
ausreichen? Und wo kommen lokale Variablen hin, die in Interrupts 
genutzt werden?

Danke euch & viele Grüße,

Michael

: Bearbeitet durch User
von C. (Gast)


Lesenswert?

Der Globale Stack wird vom Free-RTOS Kernel benutzt sobald du 
vTaskStartScheduler() aufrufst.

Jeder Task hat seinen eigenen Stack der über die Funktion xTaskCreate() 
vom Heap reserviert wird.

Es gibt nur einen Heap alle Tasks und der Kernel benutzen den gleichen.


mit xTaskCreateStatic() kannst du Task erstellen die ihren Speicher 
nicht vom Heap bekommen.

von Jim M. (turboj)


Lesenswert?

Michael S. schrieb:
> Damit brauche ich den
> globalen Stack doch nur so lange, bis der Scheduler des OS läuft, also
> nur für ein paar Initialisierungen? da würden doch 100Byte locker
> ausreichen?

Da landen auch Interrupts drauf. Und die können bei STM32 verschachtelt 
sein, und bei vorhandener FPU mit recht vielen zu sichernden 
Registern...

von Michael S. (michatroniker)


Lesenswert?

C. schrieb:
> Es gibt nur einen Heap alle Tasks und der Kernel benutzen den gleichen.

mh, alle tasks und der kernel nutzen den FREERTOS Heap, der aber doch 
nicht der gleiche ist, wie der Heap, der im Linker script reserviert 
wird. Wenn ich das richtig verstanden habe, würde ein normales malloc() 
einen Speicher im globalen heap holen, aber FreeRTOS hat ja seinen 
eigenen Speicher (configTOTAL_HEAP_SIZE) von Anfang an, aus dem dann mit 
pvPortMalloc() Speicher für die threads und den KErnel geholt wird. 
Soweit bin ich mir eigentlich ziemlich sicher.

>Der Globale Stack wird vom Free-RTOS Kernel benutzt sobald du
vTaskStartScheduler() aufrufst.

wie meinst du das? bist du dir sicher? der Kernel reserviert sich doch 
seinen eigenen Heap mit der Größe von configTOTAL_HEAP_SIZE, wozu soll 
der noch Speicher aus dem globalen Stack holen?

>Da landen auch Interrupts drauf. Und die können bei STM32 verschachtelt
sein...

die kommen also nicht in den stack vom gerade laufenden thread sondern 
in den globalen? gut zu wissen, dann brauch ich in den 
thread-stack-größen ja kaum Buffer für interrupts einbauen.

von Christopher J. (christopher_j23)


Lesenswert?

Noch was Grundsätzliches zu Stack, Heap und Linkerscripts: Die 
"Reservierung" von Stack bzw. Heap innerhalb des Linkerscripts ist nur 
insofern von Bedeutung, dass der Linker meckert wenn durch globale und 
statische Variablen bereits so viel RAM belegt ist, dass die 
"Reservierung" den Speicher zum überlaufen bringen würde. Ansonsten wird 
da nämlich gar nichts reserviert. Es ist somit eine Garantie, dass wenn 
Stack und Heap innerhalb der angegebenen Grenzen bleiben, es zu keinem 
Überlauf kommt. Der Stack und auch der Heap können (sofern denn noch 
genug freier Speicher verfügbar ist) ohne Probleme größer werden als im 
Linkerscript angegeben.

von Steffen R. (steffen_rose)


Lesenswert?

Christopher J. schrieb:
> Noch was Grundsätzliches zu Stack, Heap und Linkerscripts:

Das hängt sehr von deiner Umgebung ab.

: Bearbeitet durch User
von Christopher J. (christopher_j23)


Lesenswert?

Von welcher Umgebung denn? Ich denke wir reden hier vom "normalen" 
ST-Linkerscript, was bei CubeMX und Co dabei ist und im Grunde dem 
08/15-Linkerscript aus dem GCC(-ARM) entspricht. Das Verhalten sollte 
aber für andere Cortex-M exakt gleich sein und es hängt auch nicht von 
irgendeiner IDE oder dergleichen ab.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Christopher J. schrieb:
> Von welcher Umgebung denn? Ich denke wir reden hier vom "normalen"
> ST-Linkerscript, was bei CubeMX und Co dabei ist und im Grunde dem
> 08/15-Linkerscript aus dem GCC(-ARM) entspricht. Das Verhalten sollte
> aber für andere Cortex-M exakt gleich sein und es hängt auch nicht von
> irgendeiner IDE oder dergleichen ab.

Generiere mal für MDK-ARM V5.
Technisch hängt es natürlich vom Linkerscript und vom startup file ab. 
Doch davon gibt es verschiedenen. Daher ist es leichter durch die 
Benennung der Umgebung zu beschreiben.

Auszug aus dem Mapping file für einen STM32L476
1
Component: ARM Compiler 5.06 update 6 (build 750) Tool: armlink [4d35ed]
2
...
3
4
    0x200004ac        -       0x00000060   Zero   RW         3014    .bss                c_w.l(libspace.o)
5
    0x2000050c   0x080047b0   0x00000004   PAD
6
    0x20000510        -       0x00000200   Zero   RW          131    HEAP                startup_stm32l476xx.o
7
    0x20000710        -       0x00000400   Zero   RW          130    STACK               startup_stm32l476xx.o

Man sieht, der Stack wird hier direkt hinter die Variablen (und Heap) 
gelegt und überschriebt beim Überlauf sofort relevante Daten.

Da man das Ganze allerdings durch verändern des Linker- und startup 
files beeinflussen kann, ist es auch noch von den eigenen Settings 
abhängig.

von Christopher J. (christopher_j23)


Lesenswert?

Das ist ja genau das was ich dem TO versucht hatte zu erklären, weil ich 
das Gefühl hatte, dass er da einem Missverständnis aufsitzt. Der Stack 
liegt nicht da, wo der Linker ihn hin packt bzw. wo das Map-File sagt, 
sondern er wächst vom initialen Stackpointer aus nach unten. Im 
Linker-Script und dementsprechend auch im Map-File findest du nur eine 
Dummy-Section, welche den bereits oben erwähnten Zweck hat. Deshalb ist 
es auch egal wohin genau der Linker den Stack "platziert", weil den 
Stack das ohnehin nicht interessiert.

von Steffen R. (steffen_rose)


Lesenswert?

Wieder kommt es auf dein startup file an.

Der Cortex-M legt den MSP auf den Wert im ersten Vector.
Im startup file wird dies ggf. umdefiniert.

gcc
1
Reset_Handler:
2
  ldr   sp, =_estack

Im Linkerfile ist dann fest codiert:
_estack = 0x20020000;    /* end of RAM */

Und dort liegt beim gcc dann auch der Stack.
Da gebe ich dir auch recht, dass es nicht der Bereich ist, den man im 
Mapfile sieht. Der hat aber auch einen anderen Namen.

Bei den anderen Umgebungen ist es anders.


Für den TO ist es aber auch nur teilweise interessant, da hier auch noch 
der PSP genutzt wird, der durch FreeRTOS vergeben wird. Aber darauf ist 
C. bereits in der ersten Antwort eingegangen.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Steffen R. schrieb:
> Bei den anderen Umgebungen ist es anders.

Sicherheitshalber nochmal beim RealARM gecheckt. Der Stackpointer liegt 
auch nach der Initialisierung noch direkt hinter den Variablen.

von Christopher J. (christopher_j23)


Lesenswert?

Steffen R. schrieb:
> Wieder kommt es auf dein startup file an.

Natürlich, ich war lediglich davon ausgegangen, dass der TO die 
Standard-Startupfiles von ST nutzt und da ist zumindest beim GCC der 
initiale Stackpointer fix und hängt damit nicht vom Linkerscript ab. 
Auch meine Aussage bezüglich der Unabhängigkeit der IDE war auf den GCC 
bezogen, weil ich davon ausgegangen bin, dass der TO den benutzt, da er 
eben nichts anderes dazu geschrieben hatte.


Noch ein letzter Nachtrag:
Steffen R. schrieb:
> Für den TO ist es aber auch nur teilweise interessant, da hier auch noch
> der PSP genutzt wird, der durch FreeRTOS vergeben wird. Aber darauf ist
> C. bereits in der ersten Antwort eingegangen.

Alles was ich dem TO sagen wollte war (unter der Annahme, dass er den 
GCC mit "Standard"-Linkerscript und -Startupfile verwendet):
Mach dir keine Gedanken um die Angaben zur Größe von Stack und Heap im 
Linkerscript, da diese Größenangaben sowieso Makulatur sind.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Christopher J. schrieb:
> Standard-Startupfiles von ST

Ich gehe auch von den Standard-Startupfiles von ST aus, aber eben nicht 
für den gcc. Ich bin eigentlich nur so penetrant, weil du suggerierst, 
der gcc sei Standard.

Naja, und weil du nebenbei auch schwer zu findende sporadische Fehler 
als tolerabel suggerierst.

Christopher J. schrieb:
> Die
> "Reservierung" von Stack bzw. Heap innerhalb des Linkerscripts ist nur
> insofern von Bedeutung, dass der Linker meckert wenn

Das ist eigentlich der wichtigste Punkt am ganzen. Der Linker soll 
meckern, wenn der Speicher zur Neige geht. Daher ist es wichtig, die 
benötigte Stackgröße (oder mehr) anzugeben. Nicht immer ist der RAM so 
reichlich, dass dir die Hilfe des gcc dir Arbeit abnimmt.

Insofern ist die Frage des TO sehr berechtigt und er sollte sich darüber 
Gedanken machen. Mit OS wird ein Fehler an der Stelle noch schwieriger 
zu finden.

von Christopher J. (christopher_j23)


Lesenswert?

Steffen R. schrieb:
> Ich gehe auch von den Standard-Startupfiles von ST aus, aber eben nicht
> für den gcc. Ich bin eigentlich nur so penetrant, weil du suggerierst,
> der gcc sei Standard.

Ich gehe mal davon aus, dass du so penetrant bist, weil du es selber 
nicht wusstest. Sonst hättest du nicht das Beispiel mit Keil gebracht, 
für den eben genau das gleiche gilt wie für den GCC...

Steffen R. schrieb:
> Generiere mal für MDK-ARM V5.
> [...]
> Man sieht, der Stack wird hier direkt hinter die Variablen (und Heap)
> gelegt und überschriebt beim Überlauf sofort relevante Daten.

... weil genau das ist eben nämlich nicht der Fall.



Steffen R. schrieb:
> Naja, und weil du nebenbei auch schwer zu findende sporadische Fehler
> als tolerabel suggerierst.
>
> Christopher J. schrieb:
>> Die
>> "Reservierung" von Stack bzw. Heap innerhalb des Linkerscripts ist nur
>> insofern von Bedeutung, dass der Linker meckert wenn
>
> Das ist eigentlich der wichtigste Punkt am ganzen. Der Linker soll
> meckern, wenn der Speicher zur Neige geht. Daher ist es wichtig, die
> benötigte Stackgröße (oder mehr) anzugeben. Nicht immer ist der RAM so
> reichlich, dass dir die Hilfe des gcc dir Arbeit abnimmt.
>
> Insofern ist die Frage des TO sehr berechtigt und er sollte sich darüber
> Gedanken machen. Mit OS wird ein Fehler an der Stelle noch schwieriger
> zu finden.

Ach komm, jetzt erzähl hier nicht so einen Käse. Ich habe nie behauptet, 
dass man sich keine Gedanken um den Speicherverbrauch machen muss. 
Natürlich muss man das und man muss es umso mehr, wenn man ein RTOS 
einsetzt. Ich habe lediglich gesagt, dass durch die Angaben im 
Linkerscript kein Speicher "reserviert" wird und sowohl Stack, als auch 
Heap sowohl größer, als auch kleiner sein können als im Linkerscript 
angegeben. Der "Verbrauch" richtet sich nicht nach dem Linkerscript, 
sondern nach der tatsächlichen Nutzung. Um diese tatsächliche Nutzung 
muss man sich natürlich unbedingt Gedanken machen.

von Pascal (Gast)


Lesenswert?

Treffen Sich Heap und Stack. Fragt der eine den anderen "Hi schon lange 
nicht mehr gesehen, was machst Du hier" und der antwortet 
"Hard_Fault_Handler"
Wer ist jetzt wer?

von P.Loetmichel (Gast)


Lesenswert?

Das juckt den Hardfault ueberhaupt nicht du Laie.

Hoechstens dabei verbogene Pointer im weiteren Ablauf...

von Pascal (Gast)


Lesenswert?

Pass mal auf das der Wach-Hund Dich nicht beisst Du oberlaie

von Steffen R. (steffen_rose)


Lesenswert?

Jemand hier im Forum legt den Stack an den Anfang des RAM Bereichs. Dann 
klappt es auch sofort beim Stackoverflow mit dem Hardfault ohne das 
Daten überschrieben werden.

von Michael S. (michatroniker)


Lesenswert?

Christopher J. schrieb:
> Noch was Grundsätzliches zu Stack, Heap und Linkerscripts: Die
> "Reservierung" von Stack bzw. Heap innerhalb des Linkerscripts ist nur
> insofern von Bedeutung, dass der Linker meckert wenn durch globale und
> statische Variablen bereits so viel RAM belegt ist, dass die
> "Reservierung" den Speicher zum überlaufen bringen würde. Ansonsten wird
> da nämlich gar nichts reserviert. Es ist somit eine Garantie, dass wenn
> Stack und Heap innerhalb der angegebenen Grenzen bleiben, es zu keinem
> Überlauf kommt. Der Stack und auch der Heap können (sofern denn noch
> genug freier Speicher verfügbar ist) ohne Probleme größer werden als im
> Linkerscript angegeben.

Jap, das hatte ich schon so verstanden. Ich möchte trotzdem einen immer 
ausreichend großen Stack schon im Linker reservieren, sodass ich den 
freien Platz danach komplett für FreeRtos verwenden kann, ohne mir 
sorgen machen zu müssen, dass der Stack da reinwächst.

Also zusammenfassend (korrigiert mich wenn ich was falsch formuliere):
-der Heap im linkerscript kann ruhig 0 sein, weil der eh nie genutzt 
wird, solange ich kein malloc() verwende
-die einzelnen Tasks bekommen ihren Stack innerhalb des von FreeRTOS 
reservierten Speichers und verwenden nicht den globalen Stack, der im 
Linker script reserviert wird
- der globale Stack im Linker script wird nur für ISRs verwendet (die 
auch verschachtelt sein können) und für alle Variablen, die vor dem 
start des FreeRTOS-schedulers angelegt werden. Daher muss er nicht 
sonderlich groß sein, 128Byte sollten in meinem Fall ausreichen

: Bearbeitet durch User
von Christopher J. (christopher_j23)


Lesenswert?

Michael S. schrieb:
> Jap, das hatte ich schon so verstanden.

Offensichtlich nicht, weil sich das ganz böse mit

Michael S. schrieb:
> Ich möchte trotzdem einen immer
> ausreichend großen Stack schon im Linker reservieren, sodass ich den
> freien Platz danach komplett für FreeRtos verwenden kann, ohne mir
> sorgen machen zu müssen, dass der Stack da reinwächst.

widerspricht.

Ich versuche es nochmal. Im Linkerscript wird abgesehen von Platz für 
globale (.bss) und statische Variablen (.data) nichts reserviert. Die 
Angaben zu der Größe von Stack und Heap führen lediglich zu einem 
Compiletime-Check (bzw. Linktime-Check), ob .bss+.data+heap+stack > 
RAM-Größe. Ist das der Fall, dann spuckt der Linker einen Fehler aus.

Zur Laufzeit (i.e. "runtime") hat die "Reservierung" von Stack bzw. Heap 
absolut keine Bedeutung mehr. Du kannst beides auf Null setzen und es 
wird trotzdem problemlos funktionieren, so lange der Gesamtverbrauch 
(.bss+.data+heap+stack) zur Laufzeit kleiner ist als die Größe des RAMs.


Michael S. schrieb:
> -der Heap im linkerscript kann ruhig 0 sein
Ja

> , weil der eh nie genutzt
> wird, solange ich kein malloc() verwende
Nein, das ist nicht der Grund. FreeRTOS kann z.B. den Heap verwenden und 
wird dies auch sehr wahrscheinlich tun.

> -die einzelnen Tasks bekommen ihren Stack innerhalb des von FreeRTOS
> reservierten Speichers
FreeRTOS reserviert für die Tasks nur dann Speicher, wenn man den Task 
mit xTaskCreateStatic erstellt, ansonsten nimmt sich FreeRTOS für den 
Task-Stack RAM aus dem Heap. Siehe auch 
https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html

> verwenden nicht den globalen Stack, der im
> Linker script reserviert wird
Ja, den "globalen Stack" verwenden sie nicht aber der wird auch nicht im 
Linkerscript reserviert.

> - der globale Stack im Linker script wird nur für ISRs verwendet (die
> auch verschachtelt sein können) und für alle Variablen, die vor dem
> start des FreeRTOS-schedulers angelegt werden
korrekt

> Daher muss er nicht
> sonderlich groß sein, 128Byte sollten in meinem Fall ausreichen
Das kommt natürlich auf deine ISR drauf an und wie verschachtelt die 
gegebenenfalls ist. Bei jeder Verschachtelung landen automatisch 8*4 
Byte auf dem Stack und da sind 128 Byte schnell weg. Wie oben schon 
gesagt musst du dir aber nicht direkt Gedanken machen ob dein 
Exception-Stack jetzt 128 Byte oder doch eher 256 Byte haben wird. Der 
Stack wächst nach unten in Richtung Heap und solange da noch Platz ist 
kann er weiter wachsen, ohne dass das zu irgendwelchen Problemen führen 
würde. Wie viel Platz da jetzt noch genau zwischen Heap und Stack ist, 
dass musst du genau beobachten und alles mit einbeziehen, z.B. auch 
deine Task-Stacks die auf dem Heap landen und somit zur Linkzeit im 
RAM-Verbrauch noch nicht auftauchen.

von Michael S. (michatroniker)


Angehängte Dateien:

Lesenswert?

Danke dir für die ausführliche Erklärung.

> Ich versuche es nochmal. Im Linkerscript wird abgesehen von Platz für
> globale (.bss) und statische Variablen (.data) nichts reserviert. Die
> Angaben zu der Größe von Stack und Heap führen lediglich zu einem
> Compiletime-Check (bzw. Linktime-Check), ob .bss+.data+heap+stack >
> RAM-Größe. Ist das der Fall, dann spuckt der Linker einen Fehler aus.
>
> Zur Laufzeit (i.e. "runtime") hat die "Reservierung" von Stack bzw. Heap
> absolut keine Bedeutung mehr. Du kannst beides auf Null setzen und es
> wird trotzdem problemlos funktionieren, so lange der Gesamtverbrauch
> (.bss+.data+heap+stack) zur Laufzeit kleiner ist als die Größe des RAMs.

doch, das hatte ich tatsächlich richtig verstnden. Ich will nur bereits 
beim linken sicher sein, dass mir der Stack hinterher ausreicht, also 
will ich einen Speicher reservieren, der sicher groß genug ist, also 
dass der Stack zur Laufzeit sicher nie größer wird, als der Stack, der 
beim linken angegeben wird.




> Michael S. schrieb:
>> -der Heap im linkerscript kann ruhig 0 sein
> Ja
>
>> , weil der eh nie genutzt
>> wird, solange ich kein malloc() verwende
> Nein, das ist nicht der Grund. FreeRTOS kann z.B. den Heap verwenden und
> wird dies auch sehr wahrscheinlich tun.

aber FreeROTS hat doch seinen eigenen Heap im .bss Bereich von Anfang an 
reserviert, das sind bei mir 14kB (bei einem insgesamt-Ram von 20kB), 
aus denen sich FreeRTOS seinen Speicher holt... siehe angehängten 
Screenshot. Damit ist der globale heap doch komplett überflüssig, 
solange ich kein malloc verwende.




> FreeRTOS reserviert für die Tasks nur dann Speicher, wenn man den Task
> mit xTaskCreateStatic erstellt, ansonsten nimmt sich FreeRTOS für den
> Task-Stack RAM aus dem Heap.
aber aus dem eigenen Heap, der wie gesagt im .bss Bereich liegt

> Bei jeder Verschachtelung landen automatisch 8*4
> Byte auf dem Stack und da sind 128 Byte schnell weg.
oha, warum so viel bzw für was? In den ISRs verwende ich kaum 
stack-Speicher

> Wie oben schon
> gesagt musst du dir aber nicht direkt Gedanken machen ob dein
> Exception-Stack jetzt 128 Byte oder doch eher 256 Byte haben wird.
Naja, wenn globaler heap (0Byte) + globaler stack zusammen nur 128Byte 
zugewiesen bekommen, weil der FreeRTOS Stack im .bss Bereich maximal 
groß gemacht wird, dann kann der Stack auch nirgends mehr raus wachsen. 
Oder mache ich etwas grob falsch?

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Wie ich oben schonmal schrieb, vieles ist von deiner speziellen Umgebung 
und deiner speziellen Konfiguration abhängig. Diese hast du bisher nie 
angegeben.

Christopher J. bezieht sich auf gcc und einer bestimmten FreeRTOS 
Konfiguration.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Eine FreeRTOS Anpassung, welche heap3.c nutzt, würde wohl malloc() 
nutzen. Die Anpassungen, welche ich bisher für den STM32 (welcher Core?) 
gehabt habe, nutzen wie bei dir heap4.c.

Michael S. schrieb:
>> Wie oben schon
>> gesagt musst du dir aber nicht direkt Gedanken machen ob dein
>> Exception-Stack jetzt 128 Byte oder doch eher 256 Byte haben wird.
> Naja, wenn globaler heap (0Byte) + globaler stack zusammen nur 128Byte
> zugewiesen bekommen, weil der FreeRTOS Stack im .bss Bereich maximal
> groß gemacht wird, dann kann der Stack auch nirgends mehr raus wachsen.
> Oder mache ich etwas grob falsch?

Da du lt. Bild scheinbar den gcc verwendest:

Dein main()-Funktion usw. welche du außerhalb von FreeRTOS nutzt, nutzen 
auch diesen Stack.

Beim gcc reservierst du nicht, sondern prüfst, ob der freie Bereich 
entsprechend deiner Angaben groß genug ist. Der Stack beginnt hier im 
Normalfall immer am Ende des RAM Bereichs.

Wenn du dich verschätzt hast, wächst er aus diesem Bereich heraus (Stack 
Overflow). Da Du diesen gesamten übrigen freien RAM FreeRTOS zur 
Verfügung stellen willst, wächst er somit dort hinein.

Wie sehr deine Interrupte verschachteln können, hängt davon ab, wieviele 
Prioritätsgruppen du hast. Und dann noch die Exceptions.

Die Cortex-M CPUs sichern automatisch alle Register bei einem Interrupt.

von Christopher J. (christopher_j23)


Lesenswert?

Michael S. schrieb:
> doch, das hatte ich tatsächlich richtig verstnden.

Da habe ich meine Zweifel...

> Ich will nur bereits
> beim linken sicher sein, dass mir der Stack hinterher ausreicht, also
> will ich einen Speicher reservieren, der sicher groß genug ist, also
> dass der Stack zur Laufzeit sicher nie größer wird, als der Stack, der
> beim linken angegeben wird.

Genau das geht nämlich nicht. Es ist ausgeschlossen durch eine Angabe im 
Linkerscript sicherzustellen, dass der Stack zur Laufzeit nicht größer 
wird als zur Compiletime angegeben. Der Stack schert sich nicht um die 
Grenzen des Linkerscripts. Er wächst einfach (ohne Ankündigung oder 
Nachfrage !!!) darüber hinaus.

Michael S. schrieb:
>> FreeRTOS reserviert für die Tasks nur dann Speicher, wenn man den Task
>> mit xTaskCreateStatic erstellt, ansonsten nimmt sich FreeRTOS für den
>> Task-Stack RAM aus dem Heap.
> aber aus dem eigenen Heap, der wie gesagt im .bss Bereich liegt

Ja, wenn du das so konfiguriert hast, dann ist das so.


Michael S. schrieb:
>> Wie oben schon
>> gesagt musst du dir aber nicht direkt Gedanken machen ob dein
>> Exception-Stack jetzt 128 Byte oder doch eher 256 Byte haben wird.
> Naja, wenn globaler heap (0Byte) + globaler stack zusammen nur 128Byte
> zugewiesen bekommen, weil der FreeRTOS Stack im .bss Bereich maximal
> groß gemacht wird, dann kann der Stack auch nirgends mehr raus wachsen.
> Oder mache ich etwas grob falsch?

Nein, für den Fall hast du recht und es kommt bei einem Stack-Overflow 
direkt zum Überschreiben von relevanten Daten in .data oder was auch 
immer unterhalb des Stacks liegt.

von Michael S. (michatroniker)


Lesenswert?

>> Naja, wenn globaler heap (0Byte) + globaler stack zusammen nur 128Byte
>> zugewiesen bekommen, weil der FreeRTOS Stack im .bss Bereich maximal
>> groß gemacht wird, dann kann der Stack auch nirgends mehr raus wachsen.
>> Oder mache ich etwas grob falsch?
>
> Nein, für den Fall hast du recht und es kommt bei einem Stack-Overflow
> direkt zum Überschreiben von relevanten Daten in .data oder was auch
> immer unterhalb des Stacks liegt.

und genau deshalb will ich den Stack im Linker Script auf jedenfall groß 
genug für den worst case haben, damit ich den freeRTOS Heap maximieren 
kann.

Ich verwende einen Stm32L0 mit einem M0+ core, da habe ich nur drei 
interrupt prio level. d.h. es müssen nur drei Interrupts gleichzeitig in 
den Stack passen. 3*8*4 = 96Bytes für die gesicherten Register plus das 
was ich in der ISR brauche (max 3*5*32bit = 60Bytes), damit reichen mir 
also 200Byte Stack locker aus.

Gut, dann lege ich meine minimum stack size auf 200Byte und mach dann 
den FreeRtos Heap im .bss so groß wie möglich bis der Linker meckert.

Danke für die Infos =)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael S. schrieb:
> und genau deshalb will ich den Stack im Linker Script auf jedenfall groß
> genug für den worst case haben,

Wie willst Du denn den worst case ermitteln? Es reicht doch schon der 
(versehentliche) rekursive Aufruf einer Funktion, bei der die 
Abbruchbedingung falsch formuliert ist, um Deinen "worst case" ad 
absurdum zu führen.

von Steffen R. (steffen_rose)


Lesenswert?

"Irgendeinen" Wert muss er nunmal ansetzen. Und er setzt hier den worst 
case im Gutfall an. Was auch sonst.

Ob der Wert in seinem Fall knapp oder reichlich ist möchte ich hier 
garnicht bewerten.

Frank M. schrieb:
> (versehentliche) rekursive Aufruf einer Funktion,

In dem Falle kann er angeben was er will. Alles führt zu einem Problem.

Du machst zwar auf ein Problem aufmerksam. Der TO steht jetzt aber 
weiterhin vor dem Problem, wieviel Speicher er nun seinem RTOS gönnen 
darf.

von Nop (Gast)


Lesenswert?

Frank M. schrieb:
> Es reicht doch schon der
> (versehentliche) rekursive Aufruf einer Funktion, bei der die
> Abbruchbedingung falsch formuliert ist, um Deinen "worst case" ad
> absurdum zu führen.

Deswegen sagt MISRA "keine Rekursion". Das wiederum bedeutet, wenn man 
doch Rekursion verwendet, dann muß man eine entsprechende Analyse 
vorlegen mit Stackverbrauch pro Ebene und Nachweis der maximalen Tiefe. 
Das ist Aufwand, aber kein Hexenwerk.

von Michael S. (michatroniker)


Lesenswert?

Frank M. schrieb:
> Michael S. schrieb:
>> und genau deshalb will ich den Stack im Linker Script auf jedenfall groß
>> genug für den worst case haben,
>
> Wie willst Du denn den worst case ermitteln? Es reicht doch schon der
> (versehentliche) rekursive Aufruf einer Funktion, bei der die
> Abbruchbedingung falsch formuliert ist, um Deinen "worst case" ad
> absurdum zu führen.

na das hab ich doch geschrieben.

> Ich verwende einen Stm32L0 mit einem M0+ core, da habe ich nur drei
> interrupt prio level. d.h. es müssen nur drei Interrupts gleichzeitig in
> den Stack passen. 3*8*4 = 96Bytes für die gesicherten Register plus das
> was ich in der ISR brauche (max 3*5*32bit = 60Bytes), damit reichen mir
> also 200Byte Stack locker aus.

dass ich in den ISRs keine rekursion verwende ist ja wohl sonnenklar. 
Wenn ich "versehentlich" einen Bug einbaue, ist natürlich einer drin, 
aber dagegen hilft ein großer Stack nur für Bugs auch nicht weiter.

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.