Forum: Compiler & IDEs Gibt es einen Trick um "volatile"-Variablen zu "normalisieren"


von Willi S. aus M. (Gast)


Lesenswert?

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

von Ralf G. (ralg)


Lesenswert?

Willi S. aus M. schrieb:
> Variablen innerhalb
> von Interrupts normal zu behandeln.

Was ist denn unnormal?

von ??? (Gast)


Lesenswert?

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?

von Peter II (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

??? 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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von ??? (Gast)


Lesenswert?

Peter II schrieb:
> Dort muss man nur
> darauf achten das die variabel als Atomic behandelt wird.

Nö, da kann man volatile nutzen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

??? 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.

von Peter II (Gast)


Lesenswert?

??? 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.

von ??? (Gast)


Lesenswert?

Peter II schrieb:
> en braucht man
> z.b. bei einen int16 auf einem 8bit System.

und was hat das mit der Ausgangsfrage zu tun?

von Peter II (Gast)


Lesenswert?

??? 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.

von Willi S. aus M. (Gast)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Karl (Gast)


Lesenswert?

#define VOLATILE_ACCESS(x) (*(volatile typeof(x) *) &x)

von Dr. Sommer (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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

von C-Nachfolger? (Gast)


Lesenswert?

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.

von Eddy C. (chrisi)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.