Forum: Mikrocontroller und Digitale Elektronik GPIO-Pin nur richtig, wenn volatile verwendet


von knickknack (Gast)


Lesenswert?

Hallo,

ich verwende den STM32L151 von STmicroelectronics (wobei ich nicht 
glaube, dass es ein CPU-abhängiges Problem ist) und lese meine 
GPIO-Eingänge bisher immer ganz normal so aus:
1
// is Pin3 an PortC high?
2
if ((GPIOC->IDR & GPIO_Pin_3) != 0)
3
{
4
...}

Bisher hatte ich damit nie Probleme. Bei einem Pin ist mir jedoch 
aufgefallen, dass er den richtigen Wert nur dann liest, wenn ich ihn so 
auslese:
1
// is Pin3 an PortC high?
2
if ((volatile)(GPIOC->IDR & GPIO_Pin_3) != 0)
3
{
4
...}

Meistens hatte ich bisher nur 8-Bit'er verwendet und noch nie war es 
nötig ein CPU-Register per "volatile" auszulesen, wenn kein ISR im Spiel 
war.
Habe ich das "fehlende volatile" bisher immer falsch gemacht? Könnte ich 
bei meiner jetzigen CPU eine falsche Einstellung für den Compiler haben?

von Oliver (Gast)


Lesenswert?

knickknack schrieb:
> Meistens hatte ich bisher nur 8-Bit'er verwendet und noch nie war es
> nötig ein CPU-Register per "volatile" auszulesen, wenn kein ISR im Spiel
> war.

Was wohl daran lag, daß die Register im entsprechenden Header-files als 
volatile deklariert waren.

Schau halt mal in die header zum STM32L151, wie das da gelöst ist. 
Vielleicht fehlt da ein volatile.

Oliver

von knickknack (Gast)


Lesenswert?

Danke für deine Antwort.

Nur um sicher zu gehen, ob ich es richtig verstanden habe:
Es ist also so, dass (egal ob es bisher immer im Header-file deklariert 
wurde oder nicht) ich die GPIO-Eingänge/Register IMMER als volatile 
verwenden muss?

von troll (Gast)


Lesenswert?

knickknack schrieb:
> Nur um sicher zu gehen, ob ich es richtig verstanden habe:
Nein. Der Cast auf volatile ist nicht nötig, eben weil er bereits in den 
Headerfiles ist.

von Der Rächer der Transistormorde (Gast)


Lesenswert?

knickknack schrieb:
> Es ist also so, dass ...  ich die GPIO-Eingänge/Register IMMER als volatile
> verwenden muss?

Nein, meist macht das ein header file für dich.

Der Status von I/O Pins kann sich unabhängig vom Programm ändern. Genau 
das muss ein C-Compiler wissen. Das sagt man ihm dann auf englisch mit 
volatile (flüchtig). Eine volatile Variable wird immer aus der 
Speicherzelle wo sie steht gelesen. Optimierungen wie "da wurde nie was 
geschrieben also nehme ich den Anfangswert" unterbleiben.

von knickknack (Gast)


Lesenswert?

Wenn ich mich jetzt mal durch die librarys hangel, kann ich sehen, dass 
das Register bereits "volatile" ist. Aufgedröselt schaut das dann so 
aus:
1
if ((GPIOC->IDR & GPIO_Pin_3) != 0)
2
{
3
...}
=
1
if ((GPIOC->((__IO uint16_t)IDR) & GPIO_Pin_3) != 0)
2
{
3
...}
=
1
if ((GPIOC->((volatile uint16_t)IDR) & GPIO_Pin_3) != 0)
2
{
3
...}
So weit hätte es dann doch eigentlich passen müssen. (oder?)
Den richtigen Wert erhalte ich allerdings nur, wenn ich das Ergebnis vor 
der "ver-undung" erneut auf volatile setze:
1
if ( (volatile)(GPIOC->((volatile uint16_t)IDR) & GPIO_Pin_3) != 0)
2
{
3
...}

Ist es meinem Fall etwa so, dass die CPU das IO-Register zwar sehr wohl 
neu auslesen würde, aber erst gar nicht so weit kommt, da er bereits 
glaubt das Ergebnis nach der Berechnung zu kennen?

von Bronco (Gast)


Lesenswert?

knickknack schrieb:
> Ist es meinem Fall etwa so, dass die CPU das IO-Register zwar sehr wohl
> neu auslesen würde, aber erst gar nicht so weit kommt, da er bereits
> glaubt das Ergebnis nach der Berechnung zu kennen?

Nicht die CPU, sondern der C-Compiler.
Der denkt sich: "Warum soll ich etwas zyklisch abfragen, was nie 
beschrieben wird? Das optimier ich weg!"
Er weiß nämlich nicht, daß sich ein SpecialFunctionRegister auch ändern 
kann, ohne daß er (der C-Compiler) jemals eine Schreibaktion ausgeführt 
hat.
Volatile sagt dem C-Compiler: "Bitte nicht optimieren, dies könnte sich 
auch ändern, ohne daß Du es erwartest"
Genau das ist beim einem SpecialFunctionRegister der Fall.

von Karl H. (kbuchegg)


Lesenswert?

Bronco schrieb:
> knickknack schrieb:
>> Ist es meinem Fall etwa so, dass die CPU das IO-Register zwar sehr wohl
>> neu auslesen würde, aber erst gar nicht so weit kommt, da er bereits
>> glaubt das Ergebnis nach der Berechnung zu kennen?
>
> Nicht die CPU, sondern der C-Compiler.
> Der denkt sich: "Warum soll ich etwas zyklisch abfragen, was nie
> beschrieben wird? Das optimier ich weg!"

Damit das nicht missverständlich wird:

Nicht in diesem Fall!
In den Header Files ist das schon richtig gemacht. Das Problem muss 
woanders sitzen.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Ein (oder mehrere) Blicke mit dem Disassembler könnten helfen

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.