Gibt es einen Trick um "volatile"-Variablen zu "normalisieren"

Gast #3229649
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
Gast #3229656
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?
Gast #3229658
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.
Gast #3229691
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
Persönliche Seite #3229699
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.
Gast #3229845
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.
#3229922
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
#3230806
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.
Gast #3230834
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).

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren