Die Frage ist, ob man so eine komplexe Struktur wie einen Ringpuffer
wirklich komplett "volatile" machen möchte. Das könnte ziemlich
ineffizienten Code bewirken. Dass der Compiler die Schreib-und
Lesezugriffe nicht wegoptimiert hilft dir bei gleichzeitigen Zugriffen
aus ISR und mainloop sowieso nicht, weil die Variablen zwischendurch in
inkonsistenten Zuständen sein können - das bringt nur was bei einzelnen
Variablen, sofern die Plattform sie "atomic" behandelt (bei ARM:
1/2/4-Byte-Variablen).
Vielleicht wäre es da sinnvoller, die Interrupts während der Zugriffe
auf die Pointer/Zähler komplett zu sperren, und dann vor der Freigabe
mit einer Optimization Barrier den Compiler dazu zwingen, sie
herauszuschreiben:
1 | __disable_irq ();
|
2 | ... Zeiger/Zähler bearbeiten ...
|
3 | __asm__ volatile ("": : :"memory");
|
4 | __enable_irq ();
|
Durch clevere Zugriffsalgorithmen kann man das Lesen/Schreiben der
eigentlichen Daten außerhalb dieser Sperre vornehmen, und die
geschriebenen/frei gewordenen Bereiche danach mittels Anpassung der
Zähler/Zeiger (unter Interruptsperre) herausgeben:
1 | __disable_irq ();
|
2 | ... Bereich zum Schreiben reservieren ...
|
3 | __asm__ volatile ("": : :"memory");
|
4 | __enable_irq ();
|
5 |
|
6 | ... Daten in Puffer schreiben ...
|
7 |
|
8 | __disable_irq ();
|
9 | ... Soeben beschriebenen Bereich zum Lesen freigeben ...
|
10 | __asm__ volatile ("": : :"memory");
|
11 | __enable_irq ();
|
Das funktioniert so natürlich nur auf Single-Core-Controllern zur
Synchronisation zwischen mainloop und ISR (oder verschachtelten ISR).
Ansonsten wären noch Cache-Maintenance und/oder Mutexe oder Atomics
nötig, was man dann das (RT)OS machen lässt.
Wenn die mainloop sowieso leer ist und der ganze Programmcode sich in
ISRs befindet, welche nicht verschachtelbar sind (bzw. die
verschachtelten Interrupts nicht auf den Ringpuffer zugreifen), ist das
sowieso egal und man kann das volatile ganz weglassen; der Compiler
sorgt dafür dass vor der Rückkehr aus der ISR alles zurückgeschrieben
wird.