Hi, ich habe hier gerade ein merkwürdiges Problem mit einem ATmega8. Es geht um PWM und die Ausgabe von Sinus-Schwingungen. Ich weiß, daß man die Werte "offline" ausrechnen und im Flash versenken kann, aber ich will im Moment das Problem verstehen. Ich habe ca. 450 Byte RAM mit globalen Variablen voll ('n dickes Array, int8_t[435], und etwas Kleinzeug). Nun scheint der Gebrauch von double-Variablen und der sin-Funktion einen Teil des Arrays zu überschreiben, jedenfalls steht da gegen Ende kranker Kram drin, den ich nicht reingeschrieben habe. Wenn ich das Array kleiner mache, geht's. Wenn ich den double-Kram rausnehme, geht's. Ich habe mir nix dazu ergoogeln können, wie der avr-gcc das mit den Doubles auf dem AVR hinbekommt. Daß da ein fetter Batzen Code dranhängt sehe ich (das Programm hat 4 KB, ohne double-Kram was um 400 Byte). Aber braucht der auch RAM von der Größenordnung eines halben Ks? Und wieso (falls das der Grund ist) zerballert er dabei meine Variablen? Das ist nicht nett! ;-) Code kann ich im Moment nicht liefern, der sieht noch etwas chaotisch aus, aber ich habe etliche Stunden mit dem Vieh verbracht, und bin mir ziemlich sicher, daß in dem verbliebenen Code nix mehr begraben liegt (zeilenweise mit #ifdef durchgekaut...), kann ihn aber in den nächsten Tagen nachliefern, falls nötig. Nur um nochmal sicher zu gehen: von dem 1 KB SRAM des Mega8 steht mir doch auch 1 KB zu, abzüglich Stack latürnich, oder? Gruß, Felix
Aloha, hier gibts eine kleine Routine, mit der Du das prüfen kannst: http://www.roboternetz.de/wissen/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc
Ich habe die Routine mal ausprobiert, in einem frischen Projekt. Und siehe da, von 1 KB SRAM lässt sich nur die Hälfte verwenden. Das erklärt natürlich alles. Allerdings frage ich mich, warum das so ist. Hier die Ausgabe: $ avr-size -x -A mem_demo.elf mem_demo.elf : section size addr .text 0x10e 0x0 .data 0x0 0x800060 .bss 0x1 0x800060 .noinit 0x0 0x800061 .eeprom 0x0 0x810000 .stab 0x36c 0x0 .stabstr 0x54 0x0 Total 0x4cf und in meinem Programm steht -------------------------------- free = get_mem_unused(); if (free < 500) zappel(); -------------------------------- wobei zappel() mit PB0 wackelt, was ich am Oszi sehen kann. Wenn ich jetzt noch ein paar Variablen definiere, schlägt's zu. Wenn man also großzügig auf die nächste 2er-Potenz aufrundet, ergibt sich daß nur 512 Byte RAM nutzbar sind, obwohl 1024 Byte vorhanden wären. Wozu ist das gut? Gruß, Felix
Na ja. Der Stack braucht ein paar Bytes. Und für dynamische Speicherallokierung (malloc, free) muss auch noch etwas reserviert werden. Insgesamt hast du ja im SRAM 3 Bereiche +------------+---------------+--------+ | statische | dynamische | Stack | | Variablen | Allokierungen | | +------------+---------------+--------+ Irgendwann krachts da halt.
Wobei 500 Byte Stackverbrauch schon auf eine, sagen wir mal großzügige Nutzung lokaler Variablen hin deuten.
Zotteljedi wrote: > großzügig auf die nächste 2er-Potenz aufrundet, ergibt sich daß nur 512 > Byte RAM nutzbar sind, obwohl 1024 Byte vorhanden wären. Wozu ist das > gut? Riecht verdächtig stark nach dem bekannten "Konstanten sind per default im SRAM"-Problem. Der AVR-GCC will leider für Konstanten ne extra Syntax haben, damit sie im Flash und nicht im SRAM landen. Das macht auch konstante Strukturen besonders haarig (d.h. geht garnicht). Bei kleineren Prohjekten lasse ich ihm daher seinen Willen und versuche nicht zu überschwenglich lange Texte zu schreiben. Peter
Peter Dannegger wrote: > Riecht verdächtig stark nach dem bekannten "Konstanten sind per default > im SRAM"-Problem. Nein. Guck dir mal die Ausgabe von avr-size an: .data ist leer.
@Jörg: beim ursprünglichen Programm liegt in der Tat viel auf dem Stack, aber bei dem, zu dem die avr-size-Ausgabe gehört, liegt quasi nichts drauf, trotzdem habe ich nur ca. 500 Byte Platz. Quellen hängen an. In dem Zustand wird zappel() aufgerufen, wenn ich eine Variable wegnehme nicht mehr, das ist genau die Grenze, also ca. 500 Byte modulo etwas Kleinkram durch die Funktionen. Von 1 KB kann da nicht die Rede sein... @Karl Heinz: ich weiß, aber wenn kein malloc stattfindet, und der Stack "frisch" ist, können Variablen im Wert von 10 Byte auf Stack und Heap nicht alles bis auf 500 Byte aufmampfen. Ich fände es auch leicht beknackt, wenn Platz für mallocs reserviert werden würde, wenn im ganzen Programm kein malloc drin ist, und der Compiler das ja auch weiß. Es ist ja nicht so, daß ich nicht einsehen wollte, daß man mit RAM sparsam umgehen sollte (inzwischen kommt das Zeug eh alles offline berechnet ins Flash rein). Nur wundere ich mich, daß ich an die Hälfte des ohnehin knappen RAMs nicht dran darf. Gruß, Felix
Umm, der war wirklich fies! Das kostet 'n Bier, Felix. Ich wollte das Ganze debuggen und hab's daher auf einem Controller ausführen wollen, der debugWire kann. Da ich gerade nur einen ATmega48 (keinen 88) hatte, OK, dafür genügt der ja auch. Irgendwie wollte aber das AVaRICE bzw. der AVR Dragon nicht recht glücklich werden. Alles funktionierte normal bis zu diesem Hack, der da den RAM zumüllen soll. Danach wollte der Dragon irgendwie mit dem AVaRICE nicht mehr reden. Da habe ich mir das __init8_mem() mal angeguckt, auf Anhieb auch nichts gefunden, bis ich dann irgendwie über die RAM-Adressen gestutzt habe. Der Stackpointer wurde auf 0x25f initialisiert, aber der RAM bis < 0x300 beschrieben... Ja, der ATmega48 hat wirklich seinen RAM von 0x100 bis 0x2ff, aber warum dann 0x25f? Da ging mir der Seifensieder auf: du hast das -mmcu beim Linken weggelassen! Schade, sonst habe ich sowas nicht erst nach 'ner Stunde Arbeit gemerkt wie hier. Übrigens gibt's keinen Grund für diesen schrägen inline-asm-Hack, das geht in C genauso gut:
1 | void __attribute__ ((naked, section (".init8"))) |
2 | __init8_mem (void) |
3 | {
|
4 | uint8_t *cp = &__heap_start; |
5 | do
|
6 | {
|
7 | *cp++ = MASK; |
8 | }
|
9 | while (cp < (uint8_t *)RAMEND); |
10 | }
|
Der resultierende Code ist ähnlich kompakt wie das unverständliche inline-Kauderwelsch. ;-) p.s.: Es sind natürlich nur 3 Byte RAM in Benutzung: eins für die Variable a am unteren Ende und zwei für die eine Ebene an Rückkehradressen am oberen Ende des RAMs.
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.