Servus zusammen, ich grüble gerade ein wenig (ohne konkrete Anwendung, mehr so allgemein) ob es einen bequemen Weg gibt volatile-deklarierte Variablen innerhalb von Interrupts normal zu behandeln. Anwendung wären beispielsweise Status-bytes, die für eine Interruptroutine sowieso neu aus dem Speicher geladen und hinterher gespeichert werden müssen. Deren Verwendung im Interrupt könnte dann aber vom Compiler gut optimiert werden. Im Hauptprogramm müssen sie allerdings volatile sein. Damit nicht 2 Versionen der gleichen Variable im Speicher und in einem Register entstehen kann. (Wofür man volatile halt brauchen kann). Kennt da jemand einen Weg? irgend einen trickreichen Cast zu beginn der Interruptroutine oder so etwas? Danke für Antworten, Gruß Willi
Willi S. aus M. schrieb: > Variablen innerhalb > von Interrupts normal zu behandeln. Was ist denn unnormal?
Willi S. aus M. schrieb: > Anwendung wären beispielsweise > Status-bytes, die für eine Interruptroutine sowieso neu aus dem Speicher > geladen und hinterher gespeichert werden müssen. Deren Verwendung im > Interrupt könnte dann aber vom Compiler gut optimiert werden. Im > Hauptprogramm müssen sie allerdings volatile sein. Und wie steht es um nested interrupts?
Willi S. aus M. schrieb: > Kennt da jemand einen Weg? irgend einen trickreichen Cast zu beginn der > Interruptroutine oder so etwas? falscher Ansatz. die ISR ist ja nicht das Problem. Einfach die Variabel nicht als Volatile kennzeichen. Im Hauptprogramm dann auf volatile casten. int i; *(volatile int*)&i = xxx; so in der art.
??? schrieb: > Und wie steht es um nested interrupts? dort gibt es das Optimierungsproblem überhaupt nicht. Dort muss man nur darauf achten das die variabel als Atomic behandelt wird.
Peter II schrieb: > *(volatile int*)&i = xxx; Das ist doch Hack. Lies die Variable in der ISR einfache in eine lokele Kopie ein und fertig.
Peter II schrieb: > Dort muss man nur > darauf achten das die variabel als Atomic behandelt wird. Nö, da kann man volatile nutzen.
??? schrieb: > Peter II schrieb: >> Dort muss man nur darauf achten das die variabel als >> Atomic behandelt wird. > > Nö, da kann man volatile nutzen. Dennoch muß der Zugriff atomar sein. volatile Zugriff hat mit atmoar zunächst nichts zu tun, d.h. volatile Variablen oder SFRs werden vom Compiler nicht atomar behandelt.
??? schrieb: > Nö, da kann man volatile nutzen nein kann man nicht. ein volatile hat nichts mit einen Atomic zugriff zu tun. Den braucht man z.b. bei einen int16 auf einem 8bit System.
Peter II schrieb: > en braucht man > z.b. bei einen int16 auf einem 8bit System. und was hat das mit der Ausgangsfrage zu tun?
??? schrieb: > und was hat das mit der Ausgangsfrage zu tun? nichts es war die Beantwortung von > Peter II schrieb: > > Dort muss man nur > > darauf achten das die variabel als Atomic behandelt wird. > Nö, da kann man volatile nutzen.
Ich gebe zu, nested interrupts sind ein Problem, aber das sind sie so, oder so. da hilft ggf. auch kein volatile. Mir geht es mehr darum, dass volatile ja durchaus manchmal sinnvoll ist, aber häufig eben nur in bestimmten Programmsequenzen. Der Ansatz Peter II schrieb: > Im Hauptprogramm dann auf volatile casten. > > int i; > > *(volatile int*)&i = xxx; könnte durchaus die Ersehnte Lösung sein, ist aber ziemlich unschön zu Programmieren. Angenehmer und vor allem leserlicher wäre es hier bereits mit einem define den "*(volatile int*)&" block abzukürzen. Noch schöner wäre es im entsprechenden Programmabschnitt eine einleitende Anweisung zu geben die besagt: Hier bitte mit oder ohne volatile. Johann L. schrieb: > Lies die Variable in der ISR einfache in eine lokele Kopie ein und > fertig. hier muss ich am ende Manuel die Kopie wieder zurück speichern, was zwar auch schon recht ordentlich ist, aber ein großes Potential für Fehler bietet. Nunja mal sehn vielleicht kommt ja noch DIE LÖSUNG zu tage, auch wenn ich mit den bisherigen definitiv Leben kann... Ich bin halt ein kleiner Perfektionist. Danke euch Gruß Willi
Willi S. aus M. schrieb: > Johann L. schrieb: >> Lies die Variable in der ISR einfache in eine lokele Kopie ein und >> fertig. > > hier muss ich am ende Manuel die Kopie wieder zurück speichern, was zwar > auch schon recht ordentlich ist, aber ein großes Potential für Fehler > bietet. Aha, und der (vergessene) Cast auf volatile in jeder anderen Stelle des Programms ist also kein Problem... Und für das vergessene Rückschreiben gibt's sogar Warnings vom GCC wie "value is set but not used". > Nunja mal sehn vielleicht kommt ja noch DIE LÖSUNG zu tage, auch wenn > ich mit den bisherigen definitiv Leben kann... Ich bin halt ein kleiner > Perfektionist. Perfekter als perfekt geht eben nicht.
#define VOLATILE_ACCESS(x) (*(volatile typeof(x) *) &x)
ein Bisschen Fantasie, bitte! C++ to the Rescue:
1 | #include <iostream> |
2 | |
3 | template <typename T> |
4 | class VolBuffer { |
5 | public:
|
6 | inline VolBuffer (volatile T& var) : m_var (var), m_loaded (false) {} |
7 | ~VolBuffer () { if (m_loaded) m_var = m_buf; } |
8 | |
9 | inline T get () { if (!m_loaded) { m_loaded = true; m_buf = m_var; } return m_buf; } |
10 | inline T set (const T& x) { m_buf = x; m_loaded = true; return x; } |
11 | |
12 | inline operator T () { return get (); } |
13 | inline T operator = (const T& x) { return set (x); } |
14 | private:
|
15 | volatile T& m_var; |
16 | T m_buf; |
17 | bool m_loaded; |
18 | };
|
19 | |
20 | |
21 | volatile int x = 3; |
22 | |
23 | int main () { |
24 | |
25 | {
|
26 | VolBuffer<int> xb (x); |
27 | |
28 | xb = xb * 42; |
29 | xb = xb * 22; |
30 | }
|
31 | |
32 | std::cout << x; |
33 | }
|
Das sieht zwar furchtbar ineffizient aus, aber mit Optimierungen an (-O2 bei GCC) wird daraus genau der Code, den man haben will: Lade den Wert aus x, multipliziere ihn mit 924, schreibe ihn zurück nach x. Die geschweiften Klammern sorgen dafür, dass xb nur innerhalb davon gültig ist, und beim } wird der Destruktor aufgerufen und der Wert automatisch zurückgeschrieben, sofern er geändert wurde. Die Variable x wird innerhalb der Klammern (garantiert) nur genau 1x gelesen und nur 1x geschrieben. Falls der Compiler den Operator-Aufruf nicht automatisch hinbekommt, muss man ggf. explizit über xb.get() bzw. xb.set() nachhelfen.
@ Willi S. aus M. (Gast) >hier muss ich am ende Manuel die Kopie wieder zurück speichern, was zwar >auch schon recht ordentlich ist, aber ein großes Potential für Fehler >bietet. ??? Das muss man auch in Normalfall, mit der lokalen Kopie spart man sich halt einige Takte für das mehrfache Lesen und Schreiben.
1 | volatile int muh; |
2 | |
3 | ISR(melken) { |
4 | |
5 | int mäh= muh; |
6 | |
7 | mäh++; |
8 | if (mäh == VOLL) { |
9 | muh =0; |
10 | }
|
11 | }
|
>Nunja mal sehn vielleicht kommt ja noch DIE LÖSUNG zu tage, auch wenn >ich mit den bisherigen definitiv Leben kann... Ich bin halt ein kleiner >Perfektionist. Ich glaube eher ein Pedant . . . https://de.wikipedia.org/wiki/Pedanterie
Willi S. aus M. schrieb: > könnte durchaus die Ersehnte Lösung sein, ist aber ziemlich unschön zu > Programmieren Seit wann erhebt C den Anspruch, schön zu programmieren zu sein.
Ganz ohne C-Schweinerei geht es wohl nicht. Daher gleich noch eine obendrauf: Man definiere die Variable in einem eigenen Interruptmodul und deklariere die Variable in der Headerdatei als volatile. Die Headerdatei wird nicht vom Interrruptmodul includiert. Kommentare an sinnvollen Stellen machen die Sache relativ eigensicher.
Peter Dannegger, dem hier wohl einige doch Einiges zutrauen, verwendet den oben beschriebenen "Hack", die Variable beim Zugriff im Hauptprogramm auf volatile zu casten. Habe mich vor ein paar Jahren erst auch gewundert, aber das macht Sinn. Und mit einem Macro, ist es im Programmtext auch recht gut zu lesen und zu schreiben. Verwendet wurde es von P.D. z.B in seinem Software-UART (hier im Forum zu finden).
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.