Hi! Hab diesen Code in einem älteren Beitrag gefunden: struct test { byte b0:1; byte b1:1; byte b2:1; byte b3:1; byte b4:1; byte b5:1; byte b6:1; byte b7:1; } __attribute__((packed)); #define LED_rot (*(volatile struct test*)&PORTD).b3 #define LED_gruen (*(volatile struct test*)&PORTD).b2 Könnt ihr mir erklären warum ich bei dem cast der struct das schlüsselwort volatile zufüge? macht das sinn obwohl meine struct nicht volatile ist? oder ist das weil der portd volatile ist? das versteh ich nicht ganz? Danke im Voraus, lg Hubert
Hubert schrieb: > Könnt ihr mir erklären warum ich bei dem cast der struct das > schlüsselwort volatile zufüge? Weil der Port volatile ist. Du willst das "Datenlayout" von der Speicherstelle "PORTD" von "uint8_t" in "stuct test" Ändern, aber das "volatile" dabei nicht verlieren. Also muss das im Cast mit dabei stehen.
Ich denke schon, aber vll kannst du mir ja da noch nachhilfe geben? Bin um jede Hilfe und Erklärung dankbar!
Karl Heinz Buchegger schrieb: >>>> FAQ: Was hat es mit volatile auf sich <<< > > Kapitel 9: Was hat es mit volatile auf sich? Ein wirklich sehr schöner Artikel, Hut ab! Ich persönlich mag ja "const volatile" am liebsten (für Hardwareregister, die read-only sind)...
Hubert schrieb: > Könnt ihr mir erklären warum ich bei dem cast der struct das > schlüsselwort volatile zufüge? macht das sinn obwohl meine struct nicht > volatile ist? oder ist das weil der portd volatile ist? das versteh ich > nicht ganz? Der Struct "test" ist der Datentyp. "Volatile" ist ein Qualifier. Ein Qualifier gibt Eigenschaften an. Das sind zwei Paar Schuhe. In Deinem Beispiel bedeutet dies: 1. Greife auf den Port als Datentyp "struct test" zu. 2. Beachte dabei die Eigenschaft "volatile" des Ports.
Dosmo schrieb: > Ein wirklich sehr schöner Artikel, Hut ab! Allerdings hat er einen beliebten Schwachpunkt (IMO), nämlich eine einseitige Konzentration (oder gar Beschränkung) auf nur "eine Richtung". Wie viele der volatile-Erklärungen erweckt auch diese den Eindruck, dass es nur ein Problem gäbe, wenn sich etwas außerhalb des direkten Programmflusses ändern kann. In Wahrheit geht es aber darum, ob es benutzt wird. Ob dieses Benutzen nun ein Schreiben oder Lesen ist, spielt keine Rolle, auch beim "nur" Lesen gibt es die selben Probleme. Ich habe mal den Artikel um einen kleinen Absatz ergänzt. Vielleicht kann ja mal der originale Autor (Karl-Heinz?) drüber schauen und es ggf. den eigenen Vorstellungen (oder Stil) entsprechend umformulieren/ergänzen.
Dosmo schrieb: > 2. Beachte dabei die Eigenschaft "volatile" des Ports. Nicht direkt. Der mit & auf PORTD erzeugte Pointer wird in einen (volatile struct test*) -Pointer gecastet. Das PORTD selber volatile ist, wird da nicht "beachtet", sondern sinnvollerweise auch dem neuen Pointer hinzugefügt. Oliver
Stefan Ernst schrieb: > Ich habe mal den Artikel um einen kleinen Absatz ergänzt. Du meinst AVR-GCC-Tutorial: Interrupt-Routinen und Registerzugriffe? Oder Interrupt: Interruptfeste Programmierung? Das Thema "Interruptfeste Programmierung" ist unabhängig von AVR und GCC, m.E. würde sich der Abschnitt besser in letzterem Artikel machen; dafür dann dort gut ausgearbeitet und vom Tutorial aus verlinkt. Ein Tutorial sollte zwar nicht eine Linksammlung darstellen, aber bei entsprechend wichtigen Themen wie hier, und solchen, die wie gesagt nicht avr-gcc spezifisch sind, finde ich eine eigenständige Besprechung vorteilhafter. Das vermeidet zudem sich widersprechende Erklärungen und ist i.d.R vollständiger und konsistenter als Hier-Ein-Bisschen-Und-Da-Ein-Bisschen-Aber-Nirgends-Richtig-Erklärungen. Und nochwas: Code wie PORTD |= 1 ist auch nicht IRQ-fest per Design, wird aber in mindestens 99.9% aller Tutorials und Forenbeiträge als solches verkauft...
Johann L. schrieb: > Du meinst AVR-GCC-Tutorial: Interrupt-Routinen und Registerzugriffe? > Oder Interrupt: Interruptfeste Programmierung? Nein, ich meinte den FAQ-Abschnitt, auf den Karl-Heinz oben verwiesen hat. Allerdings hat auch in "Interrupt: Interruptfeste Programmierung" gerade heute jemand einen Absatz "Volatile Variablen" eingefügt, den ich ebenfalls etwas umformuliert habe, damit beide Richtungen berücksichtigt werden.
Stefan Ernst schrieb: > Johann L. schrieb: >> Du meinst AVR-GCC-Tutorial: Interrupt-Routinen und Registerzugriffe? >> Oder Interrupt: Interruptfeste Programmierung? > > Nein, ich meinte den FAQ-Abschnitt, auf den Karl-Heinz oben verwiesen > hat. Ah, also gibt es mindestens noch eine dritte Stelle, die das gleiche Faß aufmacht... > Allerdings hat auch in "Interrupt: Interruptfeste Programmierung" gerade > heute jemand einen Absatz "Volatile Variablen" eingefügt, den ich > ebenfalls etwas umformuliert habe, damit beide Richtungen berücksichtigt > werden. ...was aber sehr missverständlich ist. Unter "Verwendung einer Variable" kann nämlich leicht verstanden werden, daß sie nicht verändert wird. Ich verwende zB ein Programm wie avr-gcc, was aber nicht bedeutet, daß ich es verändere oder erweitere.
Johann L. schrieb: > Ah, also gibt es mindestens noch eine dritte Stelle, die das gleiche Faß > aufmacht... Nicht nur das. Ich habe gerade gesehen, dass es jetzt sogar innerhalb eines Artikels (Interrupt: Interruptfeste Programmierung) an zwei Stellen thematisiert wird, einmal unter "Wichtige Eigenschaften von ISRs", und in dem neuen Abschnitt. Johann L. schrieb: > ...was aber sehr missverständlich ist. Unter "Verwendung einer Variable" > kann nämlich leicht verstanden werden, daß sie nicht verändert wird. Aber darum geht es doch, dass das volatile auch dann nötig ist, wenn die Variable außerhalb des Programmflusses nicht verändert (sondern nur gelesen) wird. PS: Oder meinst du das im Sinne von "nirgendwo verändert wird"? In meinem Sprachgebrauch ist das dann keine Variable mehr, sondern eine Konstante. ;-)
Stefan Ernst schrieb: > Johann L. schrieb: >> ...was aber sehr missverständlich ist. Unter "Verwendung einer Variable" >> kann nämlich leicht verstanden werden, daß sie nicht verändert wird. > > Aber darum geht es doch, dass das volatile auch dann nötig ist, wenn die > Variable außerhalb des Programmflusses nicht verändert (sondern nur > gelesen) wird. Ja, eben auch. Aber die Erwähnung von Veränderung ist um Zuge der Änderung rausgeflogen, so daß die entsprechenden Stelle(n) jetzt überaus missverständlich sind, weil sie nur von "Verwenden" reden. Aber letzteres bedeutet im üblichen Sprachgebrauch eben "nicht Verändern, sondern nur Nutzen".
Johann L. schrieb: > Aber letzteres bedeutet im üblichen Sprachgebrauch eben "nicht > Verändern, sondern nur Nutzen". Und genau hier würde ich widersprechen. Was die Termini "verwenden" und "nutzen" alles einschließen, hängt vom Objekt ab. Johann L. schrieb: > Ich verwende zB ein Programm wie avr-gcc, was aber nicht bedeutet, daß > ich es verändere oder erweitere. Klar, "verändern" ist da ja auch nicht Teil des eigentlichen Verwendungszwecks, also ist es auch nicht bei "verwenden" mit eingeschlossen. Bei einer Variablen sieht das ganz anders aus, da ist das Verändern integraler Bestandteil ihres Verwendungszwecks. Ich würde bei einer Variablen jedenfalls nicht auf die Idee kommen, dass "verwenden" und "nutzen" gleichbedeutend wäre mit "read only". Aber diese Diskussion ist natürlich müßig, denn wenn es für dich missverständlich ist, dann ist es das auch für andere, und bedarf einer "Änderung". ;-)
Stefan Ernst schrieb: > Dosmo schrieb: >> Ein wirklich sehr schöner Artikel, Hut ab! > > Allerdings hat er einen beliebten Schwachpunkt (IMO), nämlich eine > (...) Hallo Stefan, mich überrascht Deine Ergänzung ein wenig, jedenfalls habe ich so etwas noch nie gesehen (was ja nix heißen soll). Ich kann mir gar keinen Anwendungsfall dafür vorstellen. Hast Du schon mal eine solche Anwendung gehabt, wo Du volatile in diese Richtung benutzt mußtest (also von der Hauptschleife zur ISR hin)?
Dosmo schrieb: > mich überrascht Deine Ergänzung ein wenig, jedenfalls habe ich so etwas > noch nie gesehen (was ja nix heißen soll). Ich kann mir gar keinen > Anwendungsfall dafür vorstellen. Du hast also noch nie Daten interrupt-gesteuert per UART versendet? Gut, in dem Fall wird ein fehlendes volatile für den Sende-Puffer vermutlich keine Auswirkungen haben. Ein konkretes Beispiel, bei dem es sehr wahrscheinlich ohne volatile in die Hose gehen wird: Software-PWM per Timer-Interrupts und eine Fading-Schleife in main in der Form:
1 | for (PWM_duty = 255; PWM_duty; PWM_duty--) |
2 | _delay_ms(4); |
Stefan Ernst schrieb: > for (PWM_duty = 255; PWM_duty; PWM_duty--) > _delay_ms(4); Das geht doch kürzer:
1 | _delay_ms(1024); |
2 | PWM_duty = 0; |
;) MfG Klaus
Stefan Ernst schrieb: > Du hast also noch nie Daten interrupt-gesteuert per UART versendet? > Gut, in dem Fall wird ein fehlendes volatile für den Sende-Puffer > vermutlich keine Auswirkungen haben. Hä? Ein UART-Tx-Interrupt läuft doch nicht periodisch die ganze Zeit, auch wenn er nichts zu senden hat. D.h. es gibt in der ISR keine Abfrage, ob neue Daten anliegen und zu versenden sind. Aber das mit dem Timer leuchtet mir ein. Da wär ich echt nicht auf die Idee gekommen, daß der Compiler in der ISR eine Abfrage optimiert. Aber jetzt wo Du sagst... Tatsächlich sind bei mir alle Variablen, die zwischen Hauptschleife und ISRs ausgetauscht werden, als volatile deklariert, nach dem Motto "lieber zu viel als zu wenig".
Dosmo schrieb: > Hä? Ein UART-Tx-Interrupt läuft doch nicht periodisch die ganze Zeit, > auch wenn er nichts zu senden hat. D.h. es gibt in der ISR keine > Abfrage, ob neue Daten anliegen und zu versenden sind. Es geht um die Daten selber, die werden in main geschrieben und in der ISR gelesen. Dosmo schrieb: > Aber das mit dem Timer leuchtet mir ein. Da wär ich echt nicht auf die > Idee gekommen, daß der Compiler in der ISR eine Abfrage optimiert. Nicht die Abfrage in der ISR, das Schreiben in main (siehe dazu auch den Kommentar von Klaus).
Stefan Ernst schrieb: > Nicht die Abfrage in der ISR, das Schreiben in main (siehe dazu auch den > Kommentar von Klaus). Oh ja, um die falsche Ecke gedacht. Ich benutz für sowas immer Methoden/Funktionen, wegen der Lesbarkeit, aber Du hast natürlich Recht!
Stefan Ernst schrieb: > for (PWM_duty = 255; PWM_duty; PWM_duty--) > _delay_ms(4); Dosmo schrieb: > Ich benutz für sowas immer > Methoden/Funktionen, wegen der Lesbarkeit und der Wartbarkeit, insbesondere wenn mehrere an dem Projekt arbeiten. Ich zitiere mal Kernighan and Plauger: > Write clearly -- dont't sacrifice clarity for "efficency" In einem Stück Code, daß ich irgendwie zu verantworten habe, will ich so etwas nicht sehen MfG Klaus
Klaus schrieb: > Stefan Ernst schrieb: >> for (PWM_duty = 255; PWM_duty; PWM_duty--) >> _delay_ms(4); > > Dosmo schrieb: >> Ich benutz für sowas immer >> Methoden/Funktionen, wegen der Lesbarkeit > > und der Wartbarkeit, insbesondere wenn mehrere an dem Projekt arbeiten. > Ich zitiere mal Kernighan and Plauger: > >> Write clearly -- dont't sacrifice clarity for "efficency" > > In einem Stück Code, daß ich irgendwie zu verantworten habe, will ich so > etwas nicht sehen Ich weiß gar nicht, was das Ganze jetzt überhaupt soll. Es ging nicht darum, irgendwas zu präsentieren, was irgendwie "empfehlenswert" wäre, sondern lediglich um ein Beispiel zur Demonstration obigen volatile-Sachverhalts.
Stefan Ernst schrieb: > Ich weiß gar nicht, was das Ganze jetzt überhaupt soll. > Es ging nicht darum, irgendwas zu präsentieren, was irgendwie > "empfehlenswert" wäre, sondern lediglich um ein Beispiel zur > Demonstration obigen volatile-Sachverhalts. Richtig. Ich wollte auch auf was anderes raus, aber mich aber doof ausgedrückt: Wenn ich mit Interrupts arbeite, dann kommen alle Daten, die zwischen ISR und main() ausgetauscht werden, in einen struct. Diesen struct deklariere ich volatile. Damit sind automatisch beide Flußrichtungen abgedeckt, obwohl mir bisher noch gar nicht bewußt war, daß ich überhaupt an die Flußrichtung main()->ISR denken muß. Insofern danke für Deinen Input.
Dosmo schrieb: > obwohl mir bisher noch gar nicht bewußt war, daß ich > überhaupt an die Flußrichtung main()->ISR denken muß. Dosmo schrieb: > Ist Dir wirklich klar, was "volatile" bedeutet? So schliesst sich der Kreis... Oliver
Dosmo schrieb: > Damit sind automatisch beide Flußrichtungen > abgedeckt, obwohl mir bisher noch gar nicht bewußt war, daß ich > überhaupt an die Flußrichtung main()->ISR denken muß. Diese Flußrichtung gibt es auch nicht, das Main kann keine Variable ändern, während die ISR läuft. Es reicht also völlig, wenn die ISR die Variable einmal einliest. Die ISR kann allerdings genau dann zuschlagen, wenn das Main eine Variable ändert und das nicht atomar macht. Also z.B. von 2 Bytes (int) nur eines geändert hat. Dann liest die ISR Unsinn. Für die ISR hat das volatile daher keine Bedeutung, es vergrößert nur oft den Code. Für das Main ist bei Interruptvariablen das volatile Pflicht und bei Bedarf auch noch das atomic. Elegant läßt sich das volatile mit einem Macro auf das Main beschränken:
1 | #define IVAR(x) (*(volatile typeof(x)*)&(x))
|
2 | |
3 | main() |
4 | {
|
5 | a = IVAR(b); |
6 | IVAR(c) = d; |
7 | }
|
Damit erhöht sich zugleich die Lesbarkeit. Jeder sieht sofort, daß diese Variable zu einem Interrupt gehört. In der ISR hat das volatile nur bei Hardwarezugriffen Bedeutung, die müssen natürlich auch immer ausgeführt werden. Peter
Peter Dannegger schrieb: > > Diese Flußrichtung gibt es auch nicht, das Main kann keine Variable > ändern, während die ISR läuft. > Es reicht also völlig, wenn die ISR die Variable einmal einliest. Steht irgendwo, daß die ISR atomar ist? > Die ISR kann allerdings genau dann zuschlagen, wenn das Main eine > Variable ändert und das nicht atomar macht. Also z.B. von > 2 Bytes (int) nur eines geändert hat. Dann liest die ISR Unsinn. Da hilft auch kein volatile. > Für die ISR hat das volatile daher keine Bedeutung, es vergrößert nur > oft den Code. Siehe oben. Eine ISR ist nicht norwendig atomar. Die meisten AVR-Anwendungen/ISRs sind zwar so geschrieben, auf größeren, echtzeitfähigen Systemen ist es aber als Kunstfehler anzusehen, Interrupts global über einen so langen Zeitraum zu sperren. > Elegant läßt sich das volatile mit einem Macro auf das Main beschränken:
1 | #define IVAR(x) (*(volatile typeof(x)*)&(x))
|
2 | |
3 | main() |
4 | {
|
5 | a = IVAR(b); |
6 | IVAR(c) = d; |
7 | }
|
Nein, das ist nicht elegant, es ist Hack.
> Damit erhöht sich zugleich die Lesbarkeit.
Wer Quellcode les- und verstehbar haben will, der kommentiert und
dokumentiert ihn.
Oliver schrieb: > Dosmo schrieb: >> obwohl mir bisher noch gar nicht bewußt war, daß ich >> überhaupt an die Flußrichtung main()->ISR denken muß. > > Dosmo schrieb: >> Ist Dir wirklich klar, was "volatile" bedeutet? > > So schliesst sich der Kreis... > > Oliver Das kommt halt davon, wenn man soviele Endlosschleifen in den ISRs hat...
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.