ich bekomme einen Compilerfehler: mem-check.c:28: internal compiler error: in start_function, at c-decl.c:6035 weiß jemand Rat? #include <avr/io.h> // RAMEND #include "mem-check.h" // Mask to init SRAM and check against #define MASK 0xaa // From linker script extern unsigned char __heap_start; unsigned short get_mem_unused (void) { unsigned short unused = 0; unsigned char *p = &__heap_start; do { if (*p++ != MASK) break; unused++; } while (p <= (unsigned char*) RAMEND); return unused; } /* !!! never call this function !!! */ void _attribute_ ((naked, section (".init8")))__init8_mem (void) { !!!hier ist der Compilerfehler!!! __asm volatile ( "ldi r30, lo8 (__heap_start)" "\n\t" "ldi r31, hi8 (__heap_start)" "\n\t" "ldi r24, %0" "\n\t" "ldi r25, hi8 (%1)" "\n" "0:" "\n\t" "st Z+, r24" "\n\t" "cpi r30, lo8 (%1)" "\n\t" "cpc r31, r25" "\n\t" "brlo 0b" : : "i" (MASK), "i" (RAMEND+1) ); }
Known issue, tritt seltsamerweise nur beim WinAVR-Build des Compilers auf. Workaround: entkopple die Deklaration und die Definition der Funktion.
1 | void __attribute__ ((naked, section (".init8")))__init8_mem (void); |
2 | void __init8_mem (void) |
3 | {
|
4 | /* code goes here */
|
5 | }
|
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:
1 | void __attribute__((naked, section(".init3"))) init_mem(void); |
2 | void init_mem(void) |
3 | {
|
4 | extern uint8_t __heap_start; |
5 | uint8_t *cp; |
6 | |
7 | for (cp = &__heap_start; cp < (uint8_t *)RAMEND; cp++) |
8 | *cp = 0x42; |
9 | }
|
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.
Ich kenne deine Implementierung für get_mem_unused() nicht, aber es hört sich so an, als sollte das ungefähr so benutzt werden, ja.
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
Hallo Gast, richtig da kommt immer 0 zurück, kannst Du die geänderte Suchfunktion einstellen?
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.
Hi, so habe ich es geändert, als einfache Version ohne Prüfung auf 0xAFFE. Jetzt erhalte ich Werte zwischen 30 und 600. #include <avr/io.h> // RAMEND #include "mem-check.h" // Mask to init SRAM and check against #define MASK 0xaa // From linker script extern unsigned char __heap_start; unsigned short get_mem_unused (void) { unsigned short unused = 0; unsigned char *p = (unsigned char*) RAMEND; do { if (*p-- == MASK) break; unused++; } while (p >= &__heap_start); return unused; } void __attribute__((naked, section(".init3"))) init_mem(void); void init_mem(void) { extern uint8_t __heap_start; uint8_t *cp; for (cp = &__heap_start; cp < (uint8_t *)RAMEND; cp++) *cp = 0x42; }
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.
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.