Was passiert dann theoretisch und praktisch? Mir ist aufgefallen, dass Compiler und Debuger (IAR) noch problemlos arbeiten, aber der MC (MSP430) nicht mehr arbeitet; die Hello World - LED blinkt nicht mehr.Ist das normal? Bleibt da nichts außer trial and error und man hat dann einfach Pech, wenn nach einem Jahr plötzlich das RAM nicht mehr reicht?
Was meinst du mit "wenn nach einem Jahr plötzlich das RAM nicht mehr reicht"? Wenn das RAM mit der Zeit immer voller wird dann hat man einen Fehler im Programm, normal ist das nicht.
Compiler und Debugger laufen natürlich problemlos, sie sind ja auch nicht vom RAM des µC abhängig. Wenn deine Software im µC läuft, dann kann sie wg. eines Programmfehlers (z.B. Stack läuft voll) abstürzen. Ich vermute aber du meinst, daß du nicht weisst wieviel RAM du für deine Applikation benötigst bzw. der Compiler verbraucht. Wie man das mit dem IAR-Compiler feststellt kann ich dir nicht sagen. GCC/make gibt mit "make size" oder "avr-size" Auskunft über den verwendeten Speicherplatz RAM/ROM. Schmittchen "mehr konnte ich aus deiner vagen Fragestellung nicht herauslesen".
Aha, kann der gcc denn das maximal belegte RAM bestimmen?
Das ist warscheinlich die schwierigste Frage bei der Softwareentwicklung überhaupt. Wie sonst sind die vielen Blue-Screens und Exceptions bei kommerziellen Programmen und Betriebssystemen zu erklären. Es hängt sehr stark von der Architektur und dem Compiler ab. Beim 8051 und dem Keil ist das z.B. sehr einfach, da dort direkte Zugriffe auf den RAM am komfortabelsten sind. D.h. der Kompiler stellt eine Calling-Tree auf und weist dann jeder Funktion direkt Speicher zu. Im *.map-File kann man dann schön sehen, wieviel Speicher insgesamt belegt wird und wieviel noch frei ist. Man erkennt auch sofort die Kandidaten, die am meisten RAM verschlingen, d.h. wo eine Optimierung am meisten bringen würde. Falls der Linker es nicht schafft, alle Variablen unterzubringen, meckert er sofort. Der Stack dient fast nur zum Speichern der Returnadressen, bzw. der Register in Interrupts. Je nach Programmgröße reichen etwa 16 Byte für den Stack aus. Bei Architekturen, die dagegen wenig Register haben und fast alles auf dem Stack machen müssen, ist das wesentlich schwieriger, da der Stack ja erst zur Laufzeit benutzt wird. Nur static und globale Variablen sind sichtbar. Da hilft eigentlich nur, den Stack zur Laufzeit z.B. in einem Timerinterrupt permanent zu überwachen und eine Alarmmeldung auszugeben, wenn eine kritische Größe unterschritten wird. Peter
Funktioniert das denn auch immer richtig? Mit sowas wie einer rekursiven Funktion oder malloc kann man ja schnell die Limits erreichen. Welche Einschränkungen brauchen gcc und Keil denn?
Malloc und Rekursionen sind Teufelszeug und haben auf einem µC nichts zu suchen, wenn man auf Stabilität und Zuverlässigkeit Wert legt ! Malloc braucht man nicht, da ja auf einem µC fest steht, welche Funktionen laufen müssen und wieviel Speicher sie benötigen. Und nur dann, wenn man die Variablen schon zur Compilezeit in der richtigen Größe angibt, ist der Linker auch in der Lage, den benötigten Speicher zu berechnen und zu meckern, falls es nicht reicht. Natürlich sollte man zur effektiven Speicherverwaltung auch Variablenfelder lokal zu einer Funktion anlegen, wenn sie nur benötigt werden, solange diese Funktion auch ausgeführt wird. Rekursionen sind nur ein Programmierstil um Funktionen möglichst unlesbar zu gestalten. Oftmals braucht es lange, um die Abbruchbedingung zu erkennen. Auch beim Debuggen sind Rekursionen nur schwer zu handhaben, da man dann von sämtlichen Variablen mehrere verschiedene Instanzen hat und der Debugger aber immer nur die letzte Instanz anzeigt. Die Hauptgefahr, besteht jedoch darin, daß Rekursionen dazu verleiten, eine Notabbruchbedingung zu vergessen ! D.h. wenn durch ungünstige Eingangswerte die geplante Abbruchbedingung nie erreicht wird, spielt es keine Rolle, ob ich 128 Byte oder 128MByte RAM habe. Es dauert nur unterschiedlich lange, bis die Endlosrekursion den Speicher aufgebraucht hat und die CPU sich ins Nirwana verabschiedet. Beliebte Absturzbeispiele sind float Vergleich auf 0 oder Reihenentwicklung mit ständig schwankendem Endergebnis. Bei einer besser lesbaren Schleifenprogramierung bietet sich der Schleifenzähler quasi von selbst an, bei Überschreitung eine Fehlerbehandlung durchzuführen, ohne daß die CPU komplett abschmiert. Der Debugger kann durch den Schleifenindex auch bequem die Zwischenergebnisse jedes Durchlaufs darstellen, da ja alle Variablen während des gesamten Durchlaufs sichtbar sind. Auch sind Schleifen wesentlich effektiver im Speicherverbrauch und auch schneller, da unnötige CALLs und RETURNs entfallen. Rekursionen müssen für jede Variable bei jedem Durchlauf umständlich Duplikate auf dem Stack anlegen. Schleifen können dagegen Variablen die nur einmal benötigt werden auch nur einmal anlegen bzw. alle Variablenfelder auf einen Ruck anlegen. Es gibt ja immer mal Konteste, wer den unleserlichsten C-Code schreiben kann, Rekursionen sind da immer mit dabei. Peter
Ja, den obfuscated C code contest kenne ich: http://www.ioccc.org/ Mir geht es aber darum zu erfahren unter welchen Bedingungen man zumindest verifizieren kann, dass das RAM immer ausreicht.
Wie gesagt, ich kenne nur den Keil C51 und da reicht ein Blick ins *.map-File um zu sehen obs klemmt und wenn ja, wo. Vorausgesetzt, man macht nicht diese Schweinereien (malloc, recursiv). Peter
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.