Hallo! Ich habe ein sehr seltsames Phänomen: Ich habe einen Mikrocontroller ATMega8535 programmiert. Der Speicher von 8k ist zu ca. 90% belegt. Zur Schaltung: Ich habe ein LCD und ein paar Schalter und Messpunkte (ADC) verbunden. Die Schaltung läuft soweit. Jetzt habe ich das Problem, das der Code, der ganz unten im Programm steht nicht richtig ausgeführt wird. Kopiere ich den Teil nach oben, so funktioniert dieser dann - jedoch der nach unten gerutschte Teil nicht mehr. Ich habe alle Variablen mit volatile deklariert... von daher sollte doch keine Variable überlaufen können, weil der Compiler den Platz dann vorsieht, oder? Ich weiß nicht mehr weiter. Ich bin fertig mit dem Programm und die letzten 10 Zeilen werden nicht richtig ausgeführt. Auch wenn es nur ein lcd_put("blabla"); ist. Da werden dann komische Zeichen ausgegeben. Vielen Dank für eure Antworten! Alex
Wie hoch ist denn der RAM Verbrauch durch statische Variablen? Hast du viele Aufrufe ala "lcd_put("XYZ")", wo Strings in doppelten Anführungszeichen stehen? Diese konstanten Strings werden beim Start des Mikrocontrollers in den RAM kopiert, was eigentlich sinnlos ist. Ich glaube hier liegt dein Problem...
Wie groß der RAM-Verbrauch ist kann ich Dir nicht genau sagen, weil ich mich zuwenig damit auskenne. Beschäftige mich noch nicht lange mit MCs. Ich kann aber sagen, welche Arten von Variablen ich deklariert habe: volatile float Spannungs=0; volatile float Spannung=0; volatile uint16_t Messwert=0; volatile uint32_t Widerstand=0; volatile uint8_t gef=0; volatile uint8_t l=0; volatile uint8_t m=1; volatile uint8_t k=0 und ja - ich habe viele Aufrufe wie lcd_puts("xyz"); Gibt es hierfür eine bessere Alternative?
Du bekommst doch sicher eine Ausgabe von den Größenstatistiken nach dem Kompiliervorgang, oder nicht? Woher beziehst du sonst deine Angabe mit dem belegten Flash(Programm)-Speicher? Ein guter Ersatz für die "lcd_puts("xyz")" sachen ist, die Strings im Flash zu belassen. Hierfür hat der Compiler allerdings keine nativ eingebauten Funktionen, da die Compiler für Systeme gemacht sind, wo Programmspeicher und Datenspeicher beide im RAM liegen. Um diese Möglichkeit trotzdem zu benutzen, gibts aber ein paar Hilfsmakros und "Ersatz"-Funktionen. Ein Beispiel ist zum Beispiel der Funktionsaufruf ala "printf_P(PSTR("%u"), MyVal);" Zu beachten ist hier das PSTR() Makro, was den String per Sections vom Linker in den Flash-Bereich legt. Weiterhin das Suffix _P was für "Progmem" (denke ich mal) steht. Dieser Funktion ist es also möglich, Strings aus dem Flash auszugeben. Am besten schaust du dafür mal in die avr-libc Dokumentation. Da ist das ganze sehr gut erklärt.
Hallo! Ich konnte mein Problem lösen. Es gibt eine Funktion lcd_puts_P(). Mit dieser werden konstante Strings im Flash abgelegt. Ja, ich bekomme eine Übersicht. Kann jedoch nicht viel damit anfangen. Welcher Bereich ist der Flash und welcher der RAM? Ich denke mal Program: ist Flash und Data wird RAM sein, oder? Aber genau deswegen verstehe ich nicht, wieso es vorher nicht funktionierte... wenn Data der RAM ist, dann hatte ich nur 89% davon belegt. Jetzt, wo die ganzen Strings im Flash liegen bin ich bei 25,8%. AVR Memory Usage ---------------- Device: atmega8535 Program: 7350 bytes (89.7% Full) (.text + .data + .bootloader) Data: 132 bytes (25.8% Full) (.data + .bss + .noinit) Build succeeded with 0 Warnings...
.text ist der reine Programmcode Der initilisierte Teil der Daten liegt für die Initialisierung auch erst einmal im Flash (.data) und wird beim Programmstart in das Ram (.data) kopiert. Beispiel static int a_number = 4711; oder auch die "strings" ohne PROGMEM. .bss sind die nicht initialisierten Daten (bzw. mit 0 initialisierte daten) und werden beim Start mit 0 initialisiert. z.B. static int another_integer; ==> Im flash liegen .text + .data Im Ram liegen (nach programmstart) .data + .bss + stack
Hehe, ja du hast schon richtig geraten. Program ist der Flash (steht
auch drunter). Data sind die Variablen.
Und jetzt zu deiner Aussage:
> nur 89% davon belegt
Wie ich schon gesagt habe: Die Ausgabe nach der Kompilierung gibt die
Belegung des Arbeitsspeichers durch statische Variablen an. Wenn du
dich aber schonmal mit dem C-Compilersystem und seiner
Speicherverwaltung auseinandergesetzt hast, wirst du sicher auch den
Stack kennen. Lokale Funktionsvariablen werden auf einer Art Stack
erzeugt und dort gespeichert. Verlässt man die Funktion, schrumpft der
Stack wieder (Die Variablen werden wieder "freigegeben").
So, das Programm, was dir nach dem Kompiliervorgang die Speicherbelegung
anzeigt kann aber eben nur die statische Belegung anzeigen, da sich die
Größe des Stacks zur Laufzeit verändern kann. Und deshalb musst du
etwas Reserve neben den statischen Variablen lassen.
Ergo: 89% sind schon zuviel Speicher, der durch statische Variablen
belegt wird.
Edit: Mist, zu spät :D
PS: Deine _P trifft das Problem genau ins Schwarze. Hast du auch das
PSTR() Makro nicht vergessen? Oder hast du die Variablem lokal erzeugt
und per Schlüsselwort "PROGMEM" ins Flash verlagert?
hmm... erst mal Danke für Deine Hinweise - wenn ich auch nicht alle verstehe. Eigentlich bin ich auf dem Gebiet C neu. Ich kenne Pascal, Object Pascal, PHP und MySQL fast aus dem FF... jedoch was C anbelangt wage ich mich auf Neuland... aber ohne Probieren kann man nichts lernen. Soviel dazu;) >PS: Deine _P trifft das Problem genau ins Schwarze. Hast du auch das >PSTR() Makro nicht vergessen? Oder hast du die Variablem lokal erzeugt >und per Schlüsselwort "PROGMEM" ins Flash verlagert? Weder noch eingebaut. PROGMEM weiß ich inzwischen was es bedeutet, da ich in Google was gefunden habe. Damit schreibt man Variablen in den Flash-Speicher um den RAM zu schonen (oder ganze Strukturen). Was PSTR() ist weiß ich (noch) nicht. Wahrscheinlich eine Möglichkeit einen String im RAM abzulegen (zumindest der Name deutet darauf hin). Ich nutze die fertige Funktion von Peter Fleurys LCD Ansteuerung um die Daten im Flash abzulegen. Diese Funktion heißt lcd_puts_P Link zum LCD-Modul: http://jump.to/fleury Dort steht in der Manual: void lcd_puts_p ( const char * progmem_s ) Display string from program memory without auto linefeed. Parameters: s string from program memory be be displayed Returns: none Da ich diese lcd_puts_P Befehle nicht für Variablen sondern nur für konstante Strings nutze sollte es funktionieren... zumindest konnte ich noch keine Programmfehler beim Testen entdecken... natürlich wäre es auch einen Versuch Wert sämtliche Variablen im Flash zu speichern, um das Programm noch ein wenig ausbauen zu können.
> natürlich wäre es > auch einen Versuch Wert sämtliche Variablen im Flash zu speichern, Nein, ist es nicht (den Versuch wert). Denn Flash ist nicht für Variablen geeignet, nur für Konstanten. In Harvard-Architektur gibt es physikalisch getrennte Speicher für Programm und Daten. Dabei gehören Daten ins RAM (rechnen wir die Register des AVRS der Einfachheit mal mit zum RAM) und Programm ins ROM. ROM ist im Laufe der Entwicklung (über PROM, EPROM, OTP) zu Flash mutiert, was ein mehrmaliges Beschreiben des Programmspeichers ermöglicht. Der Programmspeicher bleibt aber trotzdem ein Speicher für Werte, die sich während der Laufzeit NICHT verändern, also für Programmcode und Konstanten. Ihn für Variablen (Veränderliche!) nutzen zu wollen, wäre sinnfrei. Du solltest also (zumindest beim AVR) immer korrekt zwischen Konstante (deren Inhalt schon zur Entwurfszeit bekannt ist und die sich während der Laufzeit nie ändert) und Variable (Speicherzelle mit veränderbarem Inhalt) unterscheiden und alle Konstanten möglichst in den Programmspeicher legen. Das Anlegen einer Variablen mit Zuweisung eines Startwertes entspricht übrigens einer Variable (RAM) und einer Konstante (Bereitstellen des Startwertes im Flash). Wie man's nun dem Compiler sagt, kann ich Dir nicht sahgen, ich programmiere AVRs in Assembler mithilfe des Datenbletts des AVRs. ...
Alexander L. wrote: > Weder noch eingebaut. PROGMEM weiß ich inzwischen was es bedeutet, da > ich in Google was gefunden habe. Damit schreibt man Variablen in den > Flash-Speicher um den RAM zu schonen (oder ganze Strukturen). Was PSTR() > ist weiß ich (noch) nicht. Wahrscheinlich eine Möglichkeit einen String > im RAM abzulegen (zumindest der Name deutet darauf hin). > > Ich nutze die fertige Funktion von Peter Fleurys LCD Ansteuerung um die > Daten im Flash abzulegen. Diese Funktion heißt lcd_puts_P > > Display string from program memory without auto linefeed. > Parameters: > s string from program memory be be displayed > Returns: > none Hmpf, wie sieht denn dein Funktionsaufruf auf? etwa
1 | lcd_puts_P("Test"); |
Das dürfte rein theoretisch eigentlich nicht funktionieren. Denn "Test" liegt nach dem Prozessorstart im RAM, und lcd_puts_P versucht dann an der Stelle, wo der String im RAM liegt, im Flash zu lesen. Deswegen benutzt man in der Regel das PSTR() Makro. Der String wandert dann automatisch ins ROM und kann der Funktion lcd_puts_P() ohne Probleme übergeben werden. PS: Variablen, die im ROM landen sind automatisch mit "const" modifiziert. Die könntest du zur Laufzeit nicht mehr ändern. Bloß nicht alle Variablen in den Flash. Lies hierzu nochmal Hannes Post... PPS: >von daher >sollte doch keine Variable überlaufen können, weil der Compiler den >Platz dann vorsieht, oder? Dafür ist Volatile übrigens nicht da. Du brauchst Volatile nur dann zu verwenden, wenn du jegliche Optimierung verhindern willst auf dieser Variable. Nötig ist das zB, wenn du eine statische Variable einmal in einem Interrupt und einmal in einer anderen Funktion beschreiben/lesen willst. Ansonsten macht es den Code wahrscheinlich nur langsamer ;)
Hallo! Vielen Dank für die Hinweise. Bedeutet der Aufruf für konstante Strings müsste dann lauten: lcd_puts_P(PSTR("Mein String")); Aber wenn mein lcd_puts_P("xyz"); nicht funktioniert wie du sagst, wieso ist dann Data: 132 bytes (25.8% Full) (.data + .bss + .noinit) von ca. 89% auf 25,8% geschrumpft? Hat der Compiler evtl. den Fehler entdeckt und selbstständig optimiert? Ich nutze -Os. Gruß, Alex
Nunja, bin jetzt auch kein C-Compiler-Freak, da müsste Karl Heinz, Jörg Wunsch oder wie sie nicht alle heißen ran :-)) > lcd_puts_P(PSTR("Mein String")); Ja, so mache ich es immer, und so steht es in den Doc's. Das sollte so richtig sein. > Aber wenn mein lcd_puts_P("xyz"); nicht funktioniert wie du sagst, wieso > ist dann > Data: 132 bytes (25.8% Full) > (.data + .bss + .noinit) Hm, die Frage ist berechtigt. Ehrlichgesagt: Keine Ahnung.
Ich verwende zwar die fleury rouinen nicht, erinnere mich aber "dunkel" dass die _P's dort makros sind explizit ein PSTR() um die strings bauen. Am beseten in den zugehörigen headerfiles nachsehen bevor weiter spekuliert wird. Werner
Du hast vollkommen recht:
1 | /**
|
2 | @brief macros for automatically storing string constant in program memory
|
3 | */
|
4 | #define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))
|
Joup, alles klar. Dann wäre in diesem Fall sogar die Verwendung von PSTR() falsch. Das wusste ich nicht. Dachte der Fleury hält sich da an die allgemeine (inoffizielle) Konvention.
Hm? Er hält sich doch nicht dran, also gibts in diesem Falle auch keine! Aber alle anderen PROGMEM Funktionen, die zum Beispiel in der avr-libc enthalten sind, erwarten, dass man das PSTR() Makro benutzt. Dass man dem Herrn Fleury das nicht vorwerfen kann, sollte klar sein. Schließlich gibts dafür keine Norm o.ä.. Jeder kann das mit einem weiteren Makro definieren (wie in diesem Falle), kann es aber auch sein lassen. Es stiftet halt nur etwas Verwirrung. Deshalb sprach ich von "inoffiziell".
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.