Variablen und der Optimierer - WINAVR

Prost Neujahr erst einmal an Alle!

---

Muß jetzt mal mein erstes Leid in 2011 klagen ;-)

Seit zwei Tagen bin ich daran den Grund für ein sporadisches Byte auslassen der UART zu begründen.

Gerade vor 5min habe ich den Fehler bei mir im Code entdeckt.

Ich fahre derzeit mit 250k Baud zwischen einem ATMega168 / FTD232R und dem PC.

Sporadisch wenn ich etwas an den uC sende, "verlegt" dieser plötzlich ein Byte des Streams und der Befehl kann somit nicht aufgelöst werden - Der uC sendet dann ein NAK zurück.

Nachdem ich etliche Zeilen Code aus der ISR verbannt hatte (die eigentlich nicht zeitkritisch waren) ist mir dann aufgefallen, das ohne Optimierung auf Speed die UART wie gewünscht funktioniert.

Ich habe in der UART ISR zwei Variablen die die empfangenen Bytes händeln (uart_stream & uart_data).

Keine ist global, sondern nur in der ISR benutzbar.

Leider habe ich es verpennt das uart_stream Array als static zu deklarieren. Somit ist bei jedem neuen Byte das Array wieder leer :) ABER NUR wenn man den Optimizer auf Speed stellt! Ohne Optimizer funktioniert das Array wie vorgesehen...

Kann mir das bitte einmal jemand erklären?

Björn

Reply to
"Björn G."
Loading thread data ...

Ebenso.

Kann Zufall sein. Wenn die Variablen nicht static sind, dann werden die auf dem Stack angelegt. Da kann dann je nach Optimierung anderer Müll stehen, oder auch die Werte vom letzen mal.

Oder greifst du auf das Array auch außerhalb der Interruptroutine zu, also als FIFO? Dann musst du die als volatile deklarieren.

--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
Reply to
Frank Buss

Hi Frank.

Die Zugriffe sind nur intern in der ISR.

Bin nun voll froh, das ich es endlich gefixt habe :) Unfassbar wie sporadisch das immer aufgetreten ist...

Björn

Am 01.01.2011 18:17, schrieb Frank Buss:

Reply to
"Björn G."

Du greifst auf nichtinitialisierte Variablen zu. Das Verhalten ist dann undefiniert und kann sich z.B. auch mit anderen Compilerflags ändern.

Automatische Variablen (also ohne static) werden typisch auf dem Stack angelegt. Wenn es nur wenige solche Variablen gibt, wird der Compiler versuchen, sie in Registern zu halten. Das ist eine Optimierung. Auf dem Stack gibt es eine gewisse Chance, daß die alten Werte noch da sind. Für Register ist die Chance deutlich geringer.

XL

Reply to
Axel Schwenke

Björn G.schrieb: "

Schau dir doch einfach den Unterschied im List-File an. Vermutlich liegt das Array ohne Optimierung zufällig immer an der selben Stelle auf dem Stack. Eigendlich sollte der Compiler aber eine Warnung ausspucken, wenn du auf lokale Variablen lesend zugreifst, die vorher nicht initialisert wurden. Oder hast du Warnungen abgeschaltet. Naja und Arrays auf dem Stack ablegen ist auch nicht die feine englische ..

Dirk

Reply to
Dirk Ruth

Am 01.01.2011 18:12, schrieb "Björn G.": global, sondern nur in der ISR benutzbar.

Du hast es doch im Prinzip schon selbst herausgefunden... Wenn Du das Array nicht static deklariert hast dann sind dessen Speicherzellen nach verlassen der ISR wieder zur allgemeinen Verwendung freigegeben. So gesehen ist es reiner Zufall dass es überhaupt ohne static funktioniert...

-> Empfangen Daten in einer ISR immer in static-Variblen speichern wenn sie nicht sofort verarbeitet werden

Gerald

Reply to
Gerald Oppen

Hallo Axel.

Sorry das ich mich jetzt erst melden kann.

Ich greife ja nicht wirklich auf nicht initialisierte Varieblen zu. Diese wurden ja am Anfang der Funktion deklariert (mit = {0}).

Interessanter Tip mit der Variablenverwaltung! Ich wußte bisher nicht genau wie es gehandhabt wird.

Gruß, Björn

Am Sat, 1 Jan 2011 19:53:11 +0100 schrieb Axel Schwenke:

Reply to
Björn G.

Am Sun, 02 Jan 2011 02:57:03 +0100 schrieb Gerald Oppen:

Hi Gerald.

Warum der Fehler aufgetreten ist habe ich ja rausgefunden. Mit dem Static ist mir auch bekannt.

Ich hatte mich nur gewundert warum es ab und an funktionierte wenn ich static nicht verwendete.

Björn

Reply to
Björn G.

Am Sat, 01 Jan 2011 20:04:37 +0100 schrieb Dirk Ruth:

Stimmt, das wäre eine Möglichkeit gewesen.

Björn

Reply to
Björn G.

"Björn G." :

Mhh, ich leg solche Variablen immer global an (statt lokal in der Routine und static deklariert) - praktisch sieht im Speicher beides gleich aus, es vermeidet aber Irritationen mit den Compilern; manche machten da (static - volatile etc.) ganz schönen Mist - global deklariert hingegen funktioniert immer! Um das ein wenig zu kapseln braucht man die Deklaration ja nicht in die .h zu schreiben ;-).

M.

Reply to
Matthias Weingart

Matthias Weingart schrieb:

Ich mache sowas normal nie wenn fest steht das ich die Variablen nirgendwo anders gebrauche. Das erhöht, so finde ich, enorm die Übersichtlichkeit - Vor allem bei großen Projekten.

Björn

Reply to
Björn G

Am Fri, 7 Jan 2011 15:19:21 +0100 schrieb Björn G:

Ich liebe da eigentlich auch die Ordnung, habe deshalb aber neulich mal eine gute Weile gesucht:

Ein Beispiel aus einer API-Dokumentation nahezu 1:1 übernommen, trotzdem stürzte das Programm reproduzierbar schon bei simplen Aufrufen der DLL ab.

Am Ende stellten sich zwei lokale Variablen als Ursache heraus die als Parameter an die DLL übergeben wurden. Wurden die ausserhalb der Prozedur (Delphi, aber für das Problem wahrscheinlich egal) definiert passte es. Hart codierte Parameter taten es auch, es war also auch keine Referenz auf eine Variable erforderlich.

Merkwürdig.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Messwerte nachträgliche Wärmedämmung http://www.messpc.de/waermedaemmung.php
Reply to
Lutz Schulze

Lutz Schulze :

Ja ebend. Dann lieber global ;-(. Wirkliche Nachteile hat das ja nicht. Gebranntes Kind scheut das Feuer ;-). C ist ja sowieso nur ne Krücke und kann nicht richtig kapseln. Bei kleineren Projekten und uC's gehören da noch dazu; stört das aber nicht gross.

Vermutlich war der aus der DLL bereits zurückgekehrt, aber die DLL benutzte die Daten intern - in einem 2. Thread - trotzdem noch? Nach dem Return war dann nur noch irgendwas zufälliges auf dem Stack und in den Variablen ;-(. Sowas passiert schnell mal.

M.

Reply to
Matthias Weingart

In C kann man eigentlich recht gut Dinge kapseln, siehe z.B. mein Projekt hier und unten die C-Dateien:

formatting link

main.c, wo die Anwendungslogik drin steht, kennt nichts von der konkreten Hardware und kann problemlos auf andere Microcontroller portiert werden, da die gesamte Hardwareansteuerung, inklusiv Interrupts, gekapselt ist und rein per Funktionsinterface angesprochen wird. Und wenn man die globalen Variablen in einer C-Datei auch noch als static deklariert, dann sind die nicht in anderen C-Dateien sichtbar, sodaß man also theoretisch dieselben Variablennamen verwenden könnte (Vermeidung von global namespace cluttering, keine Ahnung ob es da auch einen üblichen deutschen Begriff für gibt).

Auch wenn man nicht nur solche Schichten braucht, sondern mehrere Objekte gleichen Typs und kein C++ verwenden kann oder will, geht das mit Strukturen in C auch noch leidlich gut und 100% gekapselt.

--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
Reply to
Frank Buss

Frank Buss :

Ja, die Objekte sind ja ne logische Weiterentwicklung der struct; manchmal hab ich es schon gewünscht - das jetzt in C++ realisieren - und es wäre viel einfacher; (stattdessen mit nem Array mit Funktionspointern gearbeitet, was es letzlich recht kompliziert werden liess). Das was C aber wirklich fehlt, ist die volle Unterstützung der Schiebeoperationen (mit Carryflag), die vermisse ich da am meisten.

M.

Reply to
Matthias Weingart

Du meinst sowas, wie man es von 8-Bitter gewohnt ist, daß man ein Byte schiebt und das letzte Bit ins Carry-Register wandert und beim schieben des nächsten Bytes dann verodert wird? Das vermisst du wirklich am meisten in C? Ich könnte mir da nicht viele Anwendungsfälle für vorstellen, und die meisten davon werden durch die Wahl eines breiteren Datentypen vom C-Compiler automatisch abgedeckt.

--
Frank Buss, http://www.frank-buss.de
piano and more: http://www.youtube.com/user/frankbuss
Reply to
Frank Buss

Frank Buss :

des

Also wenn Du Integerarithmetik machen willst und es kommen Divisionen vor und das soll halbwegs vernünftig in Code umgesetzt werden, dann bleibt da nur die Wahl von inline assembler (was z.B. crossworks leider nicht gut kann) und auch ist das dann nicht portierbar. Irgendwie stolpere ich da oefters mal drüber. Klar kann man da was mit dem normalen Shift oder Divisionen und if- Konstrukten basteln; da wird der Code aber unnötig kompliziert. Oder man packt das in ne Assemblerroutine - das kostet aber durch die calls/push/pop/ret Befehle auch Zeit und Code. C bietet ja leider keine Möglichkeit, Inline-Code (der auch nur mit Registern ablaufen könnte) so wie Subroutinen definieren zu können. Naja, es ist aber Meckern auf hohem Niveau. :-)

M.

Reply to
Matthias Weingart

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.