Hallo Leute, Ich bin am verzweifeln, da mein WINAVR 20090313 mit Studio 4.16 SP1 völlig falschen Code für einen AT90CAN32 produziert. Selbst eine einfache For-Schleife, die nur wartet, wird falsch codiert mit Optimierungsstufe Os und dann nur einmal durchlaufen. Stelle ich keine Optimierung ein, läuft sie richtig. Das komplette Programm aber geht mal so oder so, aber nie völlig richtig. Jedenfalls ändert sich das Verhalten je nach Optimierung. Auch Zeilen, die in C nacheinander abgearbeitet werden, sich aber nicht beeinflussen, ändern das verhalten des Programmes, wenn man sie vertauscht?! Man kann das Fehlverhalten am Assembler nachvollziehen. Der Code wird falsch übersetzt. Hat einer von Euch sowas schon erlebt? Ich habe auch einen anderen Rechner versucht, andere Einstellungen, etc. Es hat keinen Zweck, die ausgespuckten Programme funktionieren nicht, oder nur mangelhaft. Ist WINAVR nichts für den AT90CAN? hhoopi
:
Verschoben durch User
Es ist wahrscheinlicher, dass das Problem nicht in Form von WinAVR auf der Festplatte hockt, sondern vorm PC sitzt :). Irgendwas ist falsch. Makefile, Code?
> Es ist wahrscheinlicher, dass das Problem nicht in Form von WinAVR auf > der Festplatte hockt, sondern vorm PC sitzt :). !!! Alle Jahre wieder meint man, einen Fehler im Compiler oder im AVR gefunden zu haben, und immer ist es dann doch ein Fehler im eigenen Programm. Am besten kommentierst du mal alles aus, und baust das Programm dann Stück für Stück wieder zusammen, bis die Fehler auftreten. Dann kann es sich oft lohnen, nach Zufall ein paar Änderungen einzubauen und das Verhalten zu beobachten.
>Selbst eine >einfache For-Schleife, die nur wartet, wird falsch codiert mit >Optimierungsstufe Os und dann nur einmal durchlaufen. Eigentlich sollte der Compiler die komplett rauswerfen - das Konzept "warten" kennt der gar nicht, der sieht nur unnützen Code. Nicht umsonst gibt es in der avrlibc für diesen Zweck _delay-Funktionen. Warten ist nämlich gar nicht so einfach. Oliver
Danke für die aufmunternden Worte, Das mit dem Wegoptimieren von nichts tuenden Schleifen habe ich tatsächlich nicht gewusst. Wenn ein Compiler so eigenwillig ist, muss ich ihn wohl überlisten. Ich bin jetzt den raikalen Weg gegangen und habe alle Funktionen auf die Portebene heruntergebrochen, dabei Strukturen und enums entfernt und das doch relativ kleine Programm in einer Datei zusammengefasst, um einen Überblick zu bekommen. Jetzt fuktioniert die Sache etwas besser, allerdings zickt der Can-Controller noch etwas herum. Die Daten werden richtig angezeigt, doch zwischendurch bleiben sie einfach weg, kommen dann aber wieder, als wenn der Controller sich "verschluckt". Ich habe zur Info den Code angehängt. hhoopi.
ich glaube den kannst da noch ne menge optimieren ich glaube es sind viel zu viele variablen die volatile sind. Und was soll das hier volatile unsigned int weekunit_low; // Lowbyte volatile unsigned int weekunit_high; // Highbyte ein lowbyte ist nun mal kein int
if (waittimer > 0) waittimer--; Da wird der optimierer wohl einfach waittimer = 0; draus machen. Wie lange es dauert kannst du eh nicht wissen.
Teilweise alter Code, den ich noch rausschmeissen muss. Ich bin dabei, gründlich aufzuräumen und zu dokumentieren. Aber dass ist halt nur Arbeit, die Spass macht, wenn es grundsätzlich läuft. Der Can-Controller hat übrigens rumgezickt, weil meine Uhr (Timer-Int.) reingeschlagen hat. Uhr weg - Controller ruhig. Jetzt läuft es gut. Danke für die Tipps. Ich stelle den Code nochmal ein, wenn er überarbeitet ist.
So, der Code ist ziemlich überarbeitet worden. Eine seltsame Sache geht hier immer noch vor: Das Programm läuft nur mit Optimierungsstufe O3 und Os, auf den anderen Stufen bekomme ich keine richtige Can-Antwort. Außerdem ist (im laufenden Programm) bei Drehschalter-Stellung 0 (Codierschalter PORTA - erstes Datenbyte=0x40) die Anwort sofort da, bei Stellung 8 (erstes Datenbyte=0x48) springt die Antwort von Verögerung 0 bis 3ms hin und her. Der einzige Unterschied in den Daten ist wie gesagt das erste Datenbyte und der errechnete Identifier von 0x201 auf 0x241. Ich muss mir wohl die Mühe machen, den Assemblercode unter die Lupe zu nehmen. hhoopi.
warum hast du immer noch so viele variabeln als volatile gekennzeichnet? z.b. volatile unsigned int idf1 (sollte aber nicht zu dem problem führen)
Habe ich mir so angewöhnt, weil ich eigentlich viel mit Interrupts arbeite, die wiederum mit den globalen Variablen rumspielen. Wenn volatile, dann wird die Variable nach Änderung sofort wieder auf den Speicherplatz geschrieben und es passiert nicht, dass ein zuschlagender Int. diese unbemerkt ändert. hhoopi
du hast hier aber nicht ein aktuellen High-end Prozessor vor die wo man genügend Rechenleistung hat sondern ein µC, da sollte man sich schon angewöhnen sparsmam mit Resourcen umzugehen - und das volatile kostet sehr viel Zeit. Vergleiche mal dem ASM-Code von mit volatile und ohne. Auch sollte variablen die nicht wirkich Global sein müssen auch nicht global sein - das liest sich dann für Fremde wesentlich besser.
Harald H. schrieb: > Das mit dem Wegoptimieren von nichts tuenden Schleifen habe ich > tatsächlich nicht gewusst. Wenn ein Compiler so eigenwillig ist, muss > ich ihn wohl überlisten. Das ist kein eigenwilliger Compiler, das ist schlicht und einfach C. Un des bringt nix, nach dem Gieskannenprinzip Zeug volatile zu deklarieren... das hülft zB nicht gegen Raise-Conditions durch nicht-atomaren Zugriff. Aber auch das liegt nicht am "eigenwilligen" Compiler, sondern dann an der eigenwilligen Interpretation der C-Spezifikation durch C-Programmierer ;-) Johann
Johann L. schrieb:
> das hülft zB nicht gegen Raise-Conditions durch nicht-atomaren Zugriff.
Nicht, dass ich kleinlich wäre (aber vielleicht ja doch ;-)),
aber falls er danach googlen will, sollte er dafür schon den richtigen
Begriff haben:
race condition
Ich versuche noch zu optimieren und Eure Ratschläge anzunehmen, trotzdem ist das Verhalten, was ich weiter oben beschrieben habe, doch seltsam, oder? Der Can-Controller kann sich in anderen Optimierungsstufen doch nicht einfach anders verhalten.
diese sieht mir auch nicht sehr sinnvoll aus idf1 = (((id_hb<<8) | 0x37)>>5); warum machst du ein oder 0x37 und danach ein >> 5 - da bleibt von der 0x37 recht wenig übrig (genau 1bit)
idf1 ist ein int, be dem in das High-Byte der id_hb geschrieben wird. In das untere Byte kommt fest 0x37. id_hb benötige ich noch in dem Datenstrom, also nicht kaputtmachen. Der Identifier wird jetzt aus der Mischung berechnet, indem man idf1 5mal rechts schiebt und damit die 11 Bit für Standard-Can gewinnt. Dieses Verfahren hängt mit der alten Schaltung zusammen, die ich jetzt modernisiere. Der alte Controller war ein Siemens SAE81C91. Der feste Wert 0x37 und die Schalterstellung (id_hb) sollen nach Bedarf schnell geändert werden können, daher wird die alte Berechnung beibehalten. Im alten Controller konnte man High- und Lowbyte so in die Descriptor-Register einschreiben, beim AT90CAN muss ich halt anders verfahren. hhoopi
>Der Can-Controller kann sich in anderen Optimierungsstufen doch >nicht einfach anders verhalten. Das Zeitverhalten des Codes ändert sich in den verschiedenen Optimierungsstufen. Wenn du also irgendwo zeitkritische IO's hast, funktionieren die mal so und mal so. Oliver
Peter schrieb: > if (waittimer > 0) waittimer--; > > Da wird der optimierer wohl einfach > > waittimer = 0; draus machen. > > Wie lange es dauert kannst du eh nicht wissen. warum? Ist ja ein if und kein while. VG, /th.
> warum? > Ist ja ein if und kein while. oh, stimmt nehme es zurück - keine ahnung wie ich auch eine while gekommen bein
Wollt schon sagen **shocked** So setze ich meist meine prüfungen auf im SRC :-) if(geht noch) mach; else mach überlaufbehandlung; funzt Erfahrungsgemäss besser als: mach; if(geht doch nicht) mach zurück oder überlauf; **grins** VG, /th.
Harald H. schrieb: > So, der Code ist ziemlich überarbeitet worden. Eine seltsame Sache geht > hier immer noch vor: Das Programm läuft nur mit Optimierungsstufe O3 und > Os, auf den anderen Stufen bekomme ich keine richtige Can-Antwort. Du beachtest immer noch nicht, daß atomar auf Variablen zugegriffen werden muss, die sowohl ISRs als auch das Hauptprogramm verwenden. Johann
Falk Brunner schrieb:
> Siehe Interrupt
In dem Artikel steht das leider im Kleingedruckten und m.E. viel zu weit
unten. Es wird leicht überlesen.
Vor den zentnerweise Code-Listings in dem Artikel wäre ein Hinweis auf
diesen sehr wichtige Punkt, der ganz oft in Programmen nicht beachtet
wird, besser aufgehoben. Am besten am Artikelanfang, weil bis an der
Stelle, wo's jetzt steht, geht bestimmt vielen die Lese-Puste aus...
Johann
@Johann L. (gjlayde) Benutzerseite
>Stelle, wo's jetzt steht, geht bestimmt vielen die Lese-Puste aus...
Separates the boys from the men . . .
MfG
Falk
Hallo Leute, Vielen Dank für den Hinweis, ich habe mir den Interrupt-Artikel mit atomarem Zugriff angeschaut und habe einiges verstanden, bin daher ziemlich geschockt, weil ich bis jetzt darüber nie richtig nachgedacht hatte. Das Problem ist da, aber wenn ich mir jedesmal den kompletten Assembler-Code anschauen muss, um sicher zu gehen, dass kein Code ein Opfer des Int. werden kann, sollte ich gleich in Assembler programmieren. Ich denke, es ist besser, das Problem im Interrupt zu behandeln, denn Interrupts abschalten beendet auch Ihren gewollten Zweck. Die Sicherung aller wichtigen Daten (Steuerregister, im Interrupt genutzte Variablen) am Anfang des Int. und Rücksicherung am Ende des Int. ist doch eine effektive Lösung des Problems? hhoopi
Harald H. schrieb: > denn Interrupts abschalten beendet auch Ihren gewollten > Zweck. Nein, du schaltest sie ja nur für sehr kurze Zeit ab. Die Interrupt- Latenz vergrößert sich dadurch etwas, aber die ist ohnehin nicht so klein, wie man sich das zuweilen wünschen würde.
> werden kann, sollte ich gleich in Assembler programmieren
Und wie willst du es in assembler besser machen als der compiler? Sobald
du 16bit Zahlen hast, hast du das gleiche Problem das du dafür 2befehle
braucht.
>Das Problem ist da, aber wenn ich mir jedesmal den kompletten >Assembler-Code anschauen muss, um sicher zu gehen, dass kein Code ein >Opfer des Int. werden kann, sollte ich gleich in Assembler >programmieren. Brauchst du gar nicht. ALLE Zugriffe auf Variablen größer 8 Bit müssen atomar geschützt werden. ALLE globalen Variablen, die im Interrupt und im Hauptprogramm gelesen oder geschrieben werden, müssen volatile sein (zumindest im Moment des Zugriffs) Einfach. Immer. Oliver
> Brauchst du gar nicht. ALLE Zugriffe auf Variablen größer 8 Bit müssen > atomar geschützt werden. Das bedeutet aber im Umkehrschluss nicht, dass man sich bei 8-Bit keine Gedanken machen müsste. Read-Modify-Write-Zugriffe müssen auch bei 8-Bit geschützt werden. Ein "var++;" beispielsweise muss auch dann geschützt werden, wenn var nur 8-Bit hat.
nicht immer, wenn du im Interrup auf eine 8bit variabel zugreifst ist sie immer vollständig da, etweder ist schon aufaddiert oder noch nicht. Probleme kommen erst wenn du im interupt und im hauptprogramm die variable änderst - das kommt aber recht selten vor.
Ja ja, ich war mal wieder zu faul und nicht ausführlich genug. Die eigentliche Kernaussage meines Posts steht aber: > Das bedeutet aber im Umkehrschluss nicht, dass man sich bei 8-Bit keine > Gedanken machen müsste. Peter schrieb: > Probleme kommen erst wenn du im interupt und im hauptprogramm die > variable änderst - das kommt aber recht selten vor. Das "recht selten" würde ich aber nicht unterschreiben. Es kommt z.B. häufiger vor, dass Main und Interrupt unterschiedliche Pins am selben Port benutzen.
> Das "recht selten" würde ich aber nicht unterschreiben. > Es kommt z.B. häufiger vor, dass Main und Interrupt unterschiedliche > Pins am selben Port benutzen. naja ein Port ist bei mir keine Variable. Bei einem Port gibt es ja extra SetPortBit und ClearPortBit dafür muss man ja den Port nicht erst lesen und dann zurückschreiben. (auch wenn der C Code das vermuten lässt)
Peter schrieb: >> Das "recht selten" würde ich aber nicht unterschreiben. >> Es kommt z.B. häufiger vor, dass Main und Interrupt unterschiedliche >> Pins am selben Port benutzen. > naja ein Port ist bei mir keine Variable. Sorry, aber was es bei dir ist, spielt keine Rolle. Aus Sicht des Compilers ist ein SFR eine Variable. > Bei einem Port gibt es ja extra SetPortBit und ClearPortBit dafür muss > man ja den Port nicht erst lesen und dann zurückschreiben. (auch wenn > der C Code das vermuten lässt) Und wenn der Port nicht im von SBI/CBI erreichbaren Bereich liegt? Oder wenn es nicht nur ein einzelnes Bit ist?
> Und wenn der Port nicht im von SBI/CBI erreichbaren Bereich liegt? > Oder wenn es nicht nur ein einzelnes Bit ist? ja das gleiche Problem habe ich auch mit C und µC. Ich fand den alten syntax besser wo man explizit SBI/CBI aufrufen konnte, da wusste man das es atomar ist. Wenn der port es nicht unterstützt gibt es einen Fehler. Jetzt schreibt man nur noch normalen C Syntax und weiss nicht was der compiler draus macht.
Peter schrieb: > Ich fand den alten > syntax besser wo man explizit SBI/CBI aufrufen konnte, da wusste man das > es atomar ist. Das ist eben der Trugschluss (und einer der Gründe, warum ich dann auch dafür war, dass diese Makros verschwinden): sbi und cbi haben nichts anderes gemacht als das, was wir jetzt auch machen. Die eigentliche Umsetzung in SBI- und CBI-Befehle blieb dem Optimierer überlassen. Das von dir beschriebene Verhalten gab es nur ca. 1 Jahr lang in den Anfangszeiten von AVR-GCC/avr-libc, noch lange vor der Version 1.0 der avr-libc.
Jörg Wunsch schrieb: > Das ist eben der Trugschluss (und einer der Gründe, warum ich dann auch > dafür war, dass diese Makros verschwinden): sbi und cbi haben nichts > anderes gemacht als das, was wir jetzt auch machen. Die eigentliche > Umsetzung in SBI- und CBI-Befehle blieb dem Optimierer überlassen. Da gibt es aber böse Fallen wie http://www.rn-wissen.de/index.php/Avr-gcc#Bit_7_bei_SFR-Zugriff Das ist zwar in einer älteren avr-gcc-Version gesehen worden (und zudem kein Compilerfehler), ich würd aber kein Deut darauf wetten, daß sowas nicht auch in aktuellen GCC-Versionen passieren kann. Allein die Erklärung zu dem Fehler und wann er u.U. auftreten kann zeigt, daß sowas schlicht und einefach nicht sicher an der Quelle festzumachen ist, d.h. anhand der C-Quelle ist nicht zu beurteilen wie der Code aussehen wird. Die einzige Möglichkeit dazu ds auf Compiler-Ebene zu machen sind Builtins -- jedenfalls fällt mit nix anderes ein. Asm-Makros auf SBI/CBI/SBRS/SBRC haben den großen Nachteil, daß sie nicht innerhalb von SBRC/S, SBIC/S oder CPSE stehen können, weil der Compiler nix über deren Instruktionslängen wissen kann. Johann
Johann L. schrieb: > Da gibt es aber böse Fallen wie > http://www.rn-wissen.de/index.php/Avr-gcc#Bit_7_bei_SFR-Zugriff Der sieht natürlich wirklich interessant aus. Mit aktuellen Versionen des GCC gelingt es mir aber nicht, das irgendwie zu reproduzieren. Im Prinzip müsste man die Optimierung nach SBI/CBI vor der CSE machen, damit sowas nicht passiert, aber das wird vermutlich von GCCs Architektur nicht passen, oder?
Harald H. schrieb: > Hallo Leute, > Ich bin am verzweifeln, da mein WINAVR 20090313 mit Studio 4.16 SP1 > völlig falschen Code für einen AT90CAN32 produziert. Selbst eine > einfache For-Schleife, die nur wartet, wird falsch codiert mit > Optimierungsstufe Os und dann nur einmal durchlaufen. Warum glaube ich das nicht... mal abgesehen dass Du nicht einmal versucht hast, einen Beweis dafuer zu liefern.
Jörg Wunsch schrieb: > Johann L. schrieb: > >> Da gibt es aber böse Fallen wie >> http://www.rn-wissen.de/index.php/Avr-gcc#Bit_7_bei_SFR-Zugriff > > Der sieht natürlich wirklich interessant aus. > > Mit aktuellen Versionen des GCC gelingt es mir aber nicht, das > irgendwie zu reproduzieren. Wie gesagt, wirde gesehen in einer älteren Version, aber daß sowas bei neueren Versionen nicht auch passier bei komplexen oder brain-dead Quellen (zB aus Codegenerator) kann nicht garantiert werden. > Im Prinzip müsste man die Optimierung nach SBI/CBI vor der CSE > machen, damit sowas nicht passiert, aber das wird vermutlich von > GCCs Architektur nicht passen, oder? CSE ist eine der ersten RTL-Optimizer. Die einzige Möglichkeit, sowas definitiv auszuschliessen, ist dedizierte RTL-Konstrukte dafür zu verwenden. So ziemlich das einzige, wo GCC keine algebraische Vorstellung von hat sind UNSPEC und UNSPEC_VOLATILE. Das würde solchen Optimierungen verhindern. Es müsste aber jemand geben, der solche Konstrukte erst erzeugt, und das kann nur in Expand oder per RTL-Builtin passieren. In Expand geht es nicht, weil man nicht die Insns bekommt, wie sie in Final aussehen (sollen), also kann man an der Stelle keine andere Darstellung ausgeben, weil man den algebraischen Zusammenhang nicht hat. Builtins für UNSPEC müsste jeman schreiben und testen wie das auf die Performance wirkt. Combine tut sich naturgemäß schwer mit UNSPEC, aber wahrscheinlich braucht man Combine garnicht für guten Code wenn man schon adäquates RTL ausgibt. Momentan verlässt sich avr-Backend ja auf CSE, Combine, Peep2 und RTX_COSTS. Per Design liefert das also keine Sicherheit vor dem geschilderten Problem. Johann
Hallo Michael G., Es ist schon so, dass der Compiler in höheren Optimierungsstufen einfache "Warteschleifen" wegoptimiert, wenn die nichts anderes tun, als eine lokale Variable hoch zu zählen. Man muss nur einen globalen Arbeitsschritt in die Schleife einbauen, dann bleibt der Code erhalten. Habe ich übrigens hier im Forum gelernt und auf meiner Schaltung nachvollzogen. Danke nochmal für die Hinweise. An Alle, Scheint ja ein interessantes Problem zu sein, wenn ich mir die Reaktionen anschaue. Ich habe es jedenfalls bis jetzt nicht sonderlich zur Kenntnis genommen, bis ich es am eigenen Leib... äh Code zu spüren bekommen habe. Ich werde jedenfalls versuchen, im Interrupt all das zu retten, was gefährdet sein könnte. So etwas muss doch funktionieren, oder? Finde ich jedenfalls einfacher, als im Allgemein-Code alles abzusichern. Innerhalb des Int. hat man doch eine übersichtlichere Auswahl der Variablen/Register, die verändert werden könnten? hhoopi
Harald H. schrieb: > Ich werde jedenfalls versuchen, im Interrupt all das zu > retten, was gefährdet sein könnte. Das ist Quatsch. Der Interrupt kann nicht unterbrochen werden, d.h. ihm kann keiner die Variablen unterm Hintern wegändern. Dem Main dagegen schon. > So etwas muss doch funktionieren, > oder? Natürlich nicht. Aber es gibt ne Möglichkeit, das sauber zu machen: Man nimmt keine globalen Variablen. Wenn das Main auf Interruptvariablen zugreifen muß, geschieht das nur über Zugriffsfunktionen. Die Variablen sind dann nicht mehr global, sondern statisch in dem Objekt, wo der Interrupthandler und die Zugriffsfunktionen sind. Dann müssen Variablen auch nichtmal mehr volatile sein, da ja die Zugriffsfunktionen sie nur einmal einlesen bzw. schreiben. Am besten auch dem Compiler sagen, daß er die Zugriffsfunktionen nicht inlinen darf: _attribute_ ((noinline)); Falls man die Optimierung "-fwhole-program" verwenden will. Ein Beispiel dafür ist meine Entprellroutine: http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29 Peter
Peter Dannegger schrieb: > Wenn das Main auf Interruptvariablen zugreifen muß, geschieht das nur > über Zugriffsfunktionen. Die Variablen sind dann nicht mehr global, > sondern statisch in dem Objekt, wo der Interrupthandler und die > Zugriffsfunktionen sind. Das ändert aber nichts bezüglich der Atomar-Thematik. Mir ist klar, dass du das weißt, aber dein Post könnte vom OP dahingehend missverstanden werden, dass er mit dieser Vorgehensweise alle hier besprochenen Probleme los ist.
Mir ist nicht so recht klar, was das für einen Vorteil haben soll. Durch den zusätzlichen Funktionsaufruf wird etwas mehr Rechenzeit verbraucht, und wirklich gewonnen hat man gegenüber einer volatile-Variable doch eigentlich nichts.
Rolf Magnus schrieb: > Mir ist nicht so recht klar, was das für einen Vorteil haben soll. Durch > den zusätzlichen Funktionsaufruf wird etwas mehr Rechenzeit verbraucht, > und wirklich gewonnen hat man gegenüber einer volatile-Variable doch > eigentlich nichts. Es geht nur um das Atomic. Die Zugriffsfunktion macht die nötige atomare Klammerung und dann muß sich das Main nicht mehr drum kümmern (der Softwareschreiber nicht mehr dran denken). Das mit dem volatile ist nur ein Nebeneffekt. Hier noch ein Beispiel einer Zugriffsfunktion, um immmer einen gültigen Zeitstempel zu erhalten: Beitrag "AVR Timer mit 32 Bit" Die Problematik des Atomic wird selbst von Profis oft nicht verstanden. Z.B. hatte mein erstes Notebook (468SX/25MHz) eine Treiber, um nach einem Sleep den Timerinterrupt mit der CMOS-Uhr zu synchronisieren. Hatte ich dann die Windows-Zeigeruhr laufen, fror der PC immer um 0:00Uhr ein. Ich hab dann mal die Timer-Funktion geloggt und folgende Zeiten erhalten: 23:59 23:60 24:60 24:00 00:00 Es haben also 2 Programmierer gepennt. Der von dem Treiber und der von der Windows-Uhr. Die Atomic-Funktionen sind auch erst seit neuestem (2008) in dem WINAVR drin. Peter
Rolf Magnus schrieb: > Mir ist nicht so recht klar, was das für einen Vorteil haben soll. Durch > den zusätzlichen Funktionsaufruf wird etwas mehr Rechenzeit verbraucht, > und wirklich gewonnen hat man gegenüber einer volatile-Variable doch > eigentlich nichts. Im Gegentum: man verliert mächtig, da der Compiler dann alle Register in der ISR retten muss, die die Funktion zerstören dürfte (sofern er sie nicht inlinen kann).
Jörg Wunsch schrieb: > Im Gegentum: man verliert mächtig, da der Compiler dann alle Register > in der ISR retten muss, die die Funktion zerstören dürfte (sofern > er sie nicht inlinen kann). Ja, das ist ein Schwachpunkt des AVR-GCC, er analysiert nicht die Registerbelegung und verschenkt dadurch viel Optimierungspotential. Ob man durch ne Zugriffsfunktion was verschenkt, hängt von der Anwendung ab. Wenn ich in nem Zählerinterrupt durch das nicht volatile spare und dieser aber 1000-mal häufiger aufgerufen wird als die Zugriffsfunktion, gewinnt die Zugriffsfunktion in jedem Fall CPU-Zeit. Aber wie gesagt, daß ist nicht das hüpfende Komma. Volatile Fehler fallen sehr schnell auf, da dann garnichts passiert. Sie sind einfach nur lästig. Das Gefährliche sind die Atomic-Fehler, da sie einen Interrupt zum ungünstigen Zeitpunkt benötigen, um aufzufallen. Sie fallen daher typisch wärend der Entwicklung nicht auf, sondern erst später in der Praxis unter Vollast. Peter
Ganz so schlimm ist es dann doch nicht. Die Variablen sind static für das ISR-Modul, die ISR greift direkt zu. Das Hauptprogramm hat über Zugriffsfunktionen zugriff, die dann alles regeln. Dieses Kapselung ist durchaus guter Programmierstil. Oliver
> Es geht nur um das Atomic. Die Zugriffsfunktion macht die nötige > atomare Klammerung und dann muß sich das Main nicht mehr drum kümmern > (der Softwareschreiber nicht mehr dran denken). Ach so. Du kapselst einfach das cli/sei hinter der Funktion weg. Da muß man dann nur darauf achten, die Funktion nicht versehentlich in der ISR zu verwenden, sonst schaltet man dabei mittendrin die Interrupts ein.
Rolf Magnus schrieb: > Ach so. Du kapselst einfach das cli/sei hinter der Funktion weg. Da muß > man dann nur darauf achten, die Funktion nicht versehentlich in der ISR > zu verwenden, sonst schaltet man dabei mittendrin die Interrupts ein. Dafür gibt auch ne Lösung:
1 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |
2 | {
|
3 | |
4 | }
|
Allerdings würde ich Interrupts, die die selbe Variable bearbeiten, auch ins selbe Objekt schreiben und dann brauchen sie die Zugriffsfunktion nicht. Generell mag es der AVR-GCC ja nicht, wenn man Unterfunktionen in Interrupts aufruft (PUSH/POP-Orgie). 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.