Hi, Wer die Vorgeschichte nicht lesen mag, überspringt einfach den folgenden Absatz und liest nur die letzte Zeile. Ich programmiere einen Mega32 in C mit avrgcc und habe folgendes Problem: Große structs (16 Byte groß), die ich an Funktionen übergebe, kommen nicht korrekt "an". d.h. in den funktionen unterscheiden sich die Daten von denen, die ich übergeben habe (übergabe by value!) Als Problem konnte ich die Größe des Stacks oder Heaps ausmachen (ich weiss nicht so genau was der Unterschied ist, aber soviel ich weiss werden ja Werte an Funktionen übergeben in dem sie vorher auf den Stack gepushed werden). Kompilierte ich das Program mit IARCC, lief es zunächst auch nicht korrekt. Irgendwo habe ich dann eine Option gefunden, mit der man dem Stack und Heap mehr Platz zuweisen konnte und schon lief das Programm so wie es sollte. Mit dieser Info habe ich einfach das Programm so geändert, daß diese Structs per Referenz übergeben werden und prompt lief es dann wie erwartet auch mit avr-gcc. Die Frage ist jetzt einfach, wie ändere ich die Größe des Stracks und/oder Heaps auch unter avr-gcc? Vielen Dank! Markus
Gar nicht. Beide sind von Haus aus auf Maximum eingestellt, und da der GCC im Gegensatz zu IAR & Co. nur einen Stack benutzt (und nicht zwei), braucht man da nichts einzustellen. (Beim IAR ist meines Wissens einer der beiden Stacks automatisch, der andere muß vorher festgelegt werden. Einer ist dort der Call-Stack, der andere der Parameter-Stack.) Debugge Dein Problem lieber mal, indem Du Dir den Assemblercode ansiehst, den der Compiler generiert.
leider wüsste ich dann nix damit anzufangen bzw würde nicht herausfinden können, was schief läuft...
Hmm, dann sind Microcontroller vermutlich kein richtiges Betätigungsfeld für Dich, sorry. Dir kann gern geholfen werden, wenn Du Fragen hast, aber Deinen Teil an der Arbeit mußt Du schon selbst tun. Auch wenn man MCUs mittlerweile prima in C programmieren kann, so funktioniert das trotzdem nicht, wie auf einem Universalcomputer, einerseits wegen der oft nötigen Hardwarenähe (die bestenfalls vergleichbar mit Betriebssystemprogrammierung auf Universalcomputern ist), andererseits wegen der sehr beschränkten Ressourcen. Wirkliches Debuggen auf einer MCU ist sehr viel aufwendiger als auf einem Universalcomputer.
naja ich wollte damit nicht sagen, daß ich den ASM Code nicht verstehe. Im Prinzip kann es sich ja nur um einen Bug im GCC handeln (denke ich zumindest) denn RAM ist ja genug da. Was soll ich denn tun, wenn ich jetzt feststelle daß da irgendwas im Nirvana aufgrund falschem Code verschwindet? Man kann das Problem auch nicht immer nachvollziehen, denn ändere ich irgendwas an irgendeiner Funktion verhält es sich dann total anders. Was z.B. auch jedesmal bei mir zu einem Fehler führt ist eine for Schleife rückwärts laufen zu lassen. als sowas wie "for (i=10, i>=0, i--)", hingegen "for (i=0, i<10, i++)" funktioniert. Ich kann mir eigentlich nicht vorstellen, daß das noch niemand anderem aufgefallen ist (ich habe aber auch noch für dieses Problem nicht gesucht ob dieser Bug schon existiert). Leider weiss ich nicht, wie ich diese Probleme debuggen kann, denn ich interagiere eigentlich immer mit anderer Hardware und die kann ich nicht simulieren. z.B. ist dieses 15 Byte struct in meiner ersten Message eine komplette CAN Message, die ich einfach nur auf den Bus sende und dann wieder empfange und dann auf dem Display anzeige. Du kannst dir natürlich vorstellen, daß ich immer gedacht habe, daß die Message falsch übertragen wird (also der Fehler bei mir in der Ansteuerung des CAN Controllers liegt). Bis ich darauf gekommen bin das die Nachricht korrekt gesendet und empfangen wird sondern nur aufgrund dieses Parameterübergabebugs falsch angezeigt wird hats ganz schön gedauert (die empfangene Nachricht ins EEPROM zu speichern hat lustigerweise korrekt funktioniert).
> naja ich wollte damit nicht sagen, daß ich den ASM Code nicht > verstehe. Wenn Du ihn verstehst, kannst Du aber auch nachvollziehen, was der Compiler tut. Ist mühselig, aber machbar. > Im Prinzip kann es sich ja nur um einen Bug im GCC handeln Vorsicht, Grundregel #1: rede erst dann über einen Bug in fremder Software, wenn Du Dir durch eine Analyse sicher geworden bist, daß es sich wirklich um einen solchen handelt. 99,9 % aller vermuteten Bugs sitzen vor der Tastatur. ;-) > Man kann das Problem auch nicht immer nachvollziehen, ... Das ist genau die Schwierigkeit beim Debuggen von MCU-Software schlechthin. Du hast eben anschaulich dargelegt, warum Simulation zur Erkennung des Problems ohnehin nur marginal tauglich ist (eigentlich nur für sehr einfache externe Einwirkung oder für das Debuggen von Algorithmen), Du mußt also auf andere Methoden zurückgreifen. Neben der schon erwähnten Codeanalyse kommen noch in Frage: JTAG-Emulation (ist aber natürlich auch nicht völlig echtzeitfähig), ,,printf'' Debugging, LED-Tests, bei vermuteten stack-heap-Kollisionen verbunden mit einem Initialisierungsmuster im gesamten RAM, anhand dessen der ,,Füllstand'' des Stack gelegentlich (z. B. via printf) nachvollzogen wird. Meines Wissens werden structs bei der Übergabe auf dem Stack abgelegt (einfache Variablen werden für gewöhnlich in Registern übergeben). Damit ist es also gut möglich, daß Dein Stack überläuft. Die Details der Übergabe dieser structs sind gut aus dem Assemblercode ersichtlich (s. o.). Meine Vermutung ist, daß Dir aus irgendwelchen Gründen (z. B. zu viele Strings) der RAM alle wird.
> Was z.B. auch jedesmal bei mir zu einem Fehler führt ist eine for > Schleife rückwärts laufen zu lassen. > als sowas wie "for (i=10, i>=0, i--)" Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine Endlosschleife. Ansonsten teste ich Sachen, wo ich mir nicht sicher bin, einfach mal unter Borland-C. Ich nehme da die Version in der DOS-Box, damit man sich nicht mit dem Windows-Schrunz rumplagen muß. Denn dazu ist es ja C, daß es auch auf anderen Maschinen läuft. Und erst, wenn es unter Borland-C läuft, aber unter WINAVR nicht, dann könnte es ein Bug im Compiler sein. Peter
@Jörg: >> naja ich wollte damit nicht sagen, daß ich den ASM Code nicht >> verstehe. >Wenn Du ihn verstehst, kannst Du aber auch nachvollziehen, was der >Compiler tut. Ist mühselig, aber machbar. Wie gesagt, es handelte sich hier um eine CAN Message, die zuvor vom CAN Controller geladen wurde. Ich kann mir ja beim nachvollziehen des ASM Codes nicht sicher sein, ob da schon was falsch gelesen wird (das ändert natürlich den Inhalt der Speicherstellen der Variablen, etc.) oder eben erst später das Problem bei der Übergabe durch den Stack auftritt. Das macht es ja so schwierig für mich, das nachzuvollziehen. Und JTAG habe ich leider nicht zur Verfügung. Desweiteren ist es in der Tat viel Arbeit und da es mit Übergabe als Referenz funktioniert fehlt mir ehrlich gesagt die Motivation mir das genau anzuschauen. Ich hatte ursprünglich ja auch gedacht das mit einem einfachen Kompilerparamter lösen zu können. Ausserdem habe ich ja nicht nach Bug geschrien, sondern das nur in Erwägung gezogen, weil es unter IAR quasi ohne weitere Probleme lief. Von daher schliesse ich auch aus, daß mir der Speicher ausgeht. Denn der müsste unter IAR dann genauso ausgehen (zumindest müsste das Programm IMHO dann auch nicht korrekt laufen, wenn auch warscheinlich mit anderem Fehler). @Peter: >Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine >Endlosschleife. Natürlich, das wirds gewesen sein ;-). Mit normalem gcc für x86 kompiliert habe ich natürlich stets "int" genommen und beim AVR nehme ich eigentlich immer "uint8_t".
> Von daher schliesse ich auch aus, daß mir der Speicher ausgeht. Denn > der müsste unter IAR dann genauso ausgehen Das ist ein Trugschluß. Meines Wissens kann der IAR z. B. alle string literals (also Texte, die in "" stehen) automatisch in den ROM plazieren (was ihn dann nicht mehr standardkonform macht, da man solche Strings nicht an Standard-Funktionen aus <string.h> übergeben kann). Der GCC plaziert die Strings dagegen immer im RAM. Ohne genaue Zahlen Deinerseits gibt's da aber auch keine Hilfe.
>@Peter: >>Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine >>Endlosschleife. > >Natürlich, das wirds gewesen sein ;-). Mit normalem gcc für x86 >kompiliert habe ich natürlich stets "int" genommen und beim AVR nehme >ich eigentlich immer "uint8_t". Dabei erzeugt gcc aber eine Warnung: mycode.c:50: warning: comparison is always true due to limited range of data type Warnungen sollten immer als Hilfe und nicht als lästig betrachtet werden. Eine Warnung sollte höchstens dann akzeptiert werden, wenn genau klar ist, warum sie entsteht und es wirklich keinen Workaround gibt. Dein Problem sieht wirklich sehr nach Stackproblem aus. Lies Dir mal im avr-libc Reference Manual das Kapitel 5.5, "Program Space String Utilities" durch und bau Dein Programm entsprechend um. Zum Vorab-Test, ob daran das Problem liegt: Etliche Strings radikal kürzen. Das Übergeben einer struct als call-by-value würde ich nach Möglichkeit vermeiden: es erzeugt wesentlich mehr Code/Abarbeitungszeit. Stefan
@Stefan&Jörg Wie meint Ihr das mit dem radikal kürzen? Das Problem trat selbst dann auf, wenn ich ein "Minimalprogramm" hatte, was wirklich nichts anderes tut als eine Nachricht zu senden, zu empfangen und diese dann auf dem Display auszugeben. Die Ausgabe besteht einfach darin, jedes Byte der Nachricht in Hex auf dem Display darzustellen. Hab mir dazu extra Funktionen geschrieben, die einen 8Bit Wert in Hex oder Binär aufs Display schreiben. Dieses Programm enthielt keinerlei Strings wie "dies ist jetzt ein Test" , oder sowas.
>Dieses Programm enthielt keinerlei Strings wie "dies ist jetzt ein >Test" , oder sowas. Tja, wenn es das nicht war, dann hilft nur noch raten ... oder mal den Source posten. Stefan
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.