Zusätzliche Bemerkungen: benenne die Funktion bitte init_mem, nicht
__init8_mem. Solche Namen sind für Compiler und Systembibliothek
reserviert. Außerdem kannst du das gut und gern bereits in .init3
abfackeln und es gibt keinen Grund, unlesbaren inline asm Code
dafür zu schreiben. Das geht auch prima in C:
OK besten Dank so läufts.
ich habe sporadisch abstürze und möchte mit dieser Funktion prüfen ob es
einen Stacküberlauf gibt.
get_mem_unused ();
sollte jetzt den freien RAM im whorst case anzeigen, ist das richtig?
Momentan kommt 0 zurück.
Hi,
@Jörg: Die Implementierung von get_mem_unused steht im ersten Post :)
Dürfte allerdings so nicht funktionieren und immer 0 zurückliefern. Mann
muß vom aktuellen Stackpointer ausgehend "nach unten" suchen um den
Abstand zum "heap end" zu ermittteln. Bei "heap start" anzufangen und
"nach oben" zu suchen ist normalerweise ziemlich für die Katz ...
CU
Du wirst doch wohl noch die Schleife umdrehen können :-)
Fang bei RAMEND an zu immer kleineren Werten hin.
Solange du im Speicher kein 0xaa vorfindest, bist
du sicher noch im Stack. Leider gilt das umgekehrte nicht :-)
Wenn du ein 0xaa vorfindest, heist das nicht, dass du den
Stack durch hast, denn am Stack kann ja auch zufällig ein
0xaa liegen. Ist sogar recht wahrscheinlich, dass du auf eines
stossen wirst. Von daher ist es sicherlich besser, wenn du
das Muster auf eine etwas längere Sequenz ausdehnen würdest.
Der berühmte 0xAFFE bietet sich an. Nun kann zwar auch zufällig
am Stack ein 0xAFFE liegen, das ist aber deutlich unwahrscheinlicher
als ein einzenles 0xaa.
Hast du dann den ersten 0xAFFE gefunden, geht es in der nächsten
Schleife weiter, bis der 0xAFFE wieder nicht mehr gefunden werden
kann. Das bedeutet dann, dass du durch den 'freien' Speicher durch
bist und den Bereich der Heap Allokierungen erreicht hast.
Du weist jetzt also wo der Stack endet und wo der Heap anfängt.
Die Differenz davon ist der noch freie Speicher zwischen Heap
und Stack.
Man könnte auch bei __brkval anfangen und von dort nach oben gucken.
In dieser Variablen steht die Adresse, bis zu der malloc() den
Speicher bereits in Beschlag genommen hat. Darüber kommt dann
freier Platz im Stack.
Man muss allerdings dann den Sonderfall behandeln, dass __brkval
noch NULL ist, dann wurde noch kein einziges malloc() aufgerufen und
man müsste bei __heap_start starten.
Michael wrote:
> so habe ich es geändert, als einfache Version ohne Prüfung auf> 0xAFFE. Jetzt erhalte ich Werte zwischen 30 und 600.
Naja...
> #define MASK 0xaa> if (*p-- == MASK)> *cp = 0x42;
Du solltest die Werte wohl schon anpassen. :-/
Außerdem: wenn du von RAMEND nach unten guckst, erfasst du zuerst den
Stack. Der sollte immer ein wenig benutzten RAM haben... Wie Karl
Heinz schon andeutete, ist die Erkennung dort nicht ganz trivial, da
deine MASK (oder deine 0x42, je nachdem, wofür du dich entscheidest)
ja auch normaler Inhalt des Stacks sein könnte.
Erst, nachdem du die Stackbelegung bewertet hast, sollte dann der
freie RAM folgen, der mit MASK gefüllt ist. Wenn du dann noch weiter
nach unten läufst, kommt entweder der Heap oder die statischen
Variablen (falls kein malloc() benutzt wird).
Daher war ja mein Vorschlag, dass du vom Ende des Heap nach oben
gehst.
wenn ich jetzt einfach den Stackpointer von __brkval abziehe und dieser
>0 ist? Passt das?
extern unsigned char __brkval;
uint16_t momentan_frei = SP - (uint16_t) &__brkval;
Michael wrote:
> wenn ich jetzt einfach den Stackpointer von __brkval abziehe und dieser> >0 ist? Passt das?
Damit hast du den aktuell freien RAM. Das Ziel der Mustersuche dagegen
ist es, den über die bisherige Laufzeit minimal vorhandenen freien
RAM zu ermitteln.
Hi, die urspüngliche Implementierung findet sich in
http://www.roboternetz.de/wissen/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc#Dynamischer_RAM-Verbrauch
-- Ich hatte Inline Assembler gewählt, weil der Code ansonsten bei -O0
nicht lauffähig ist (weiß jetzt nicht mehr genau, warum).
-- Gedacht war der Code, wenn ohne malloc() etc gearbeitet wird, weil
man das auf AVR möglichst vermeiden sollte, zumindest bei den kleineren
Derivaten -- und idR auch vermeiden kann.
== Edit ==
Ah ja. Der Grund ist, daß man nicht garantieren kann, daß GCC alle
Variablen in Registern hält und evtl. auto-Variablen im Frame anlegt,
die dann von der init-Routine überschreiben würden. Man darf dann also
maximal bis SP initialisieren und nicht bis RAMEND.
>get_mem_unused ();>sollte jetzt den freien RAM im whorst case anzeigen, ist das richtig?>Momentan kommt 0 zurück.
Wenn man printf() aus der avr-libc benutzt kommt tatsächlich
immer 0 zurück. printf() benutzt malloc(). Damit wird der
Heap verändert und get_mem_unused (); funktioniert nicht mehr.
holger wrote:
> printf() benutzt malloc().
Schon lange nicht mehr. fdevopen() benutzt malloc(), aber es gibt ja
mittlerweile fdev_setup_stream() und FDEV_SETUP_STREAM() als
Alternativen.