Forum: Compiler & IDEs AVR GCC: Ungewünschte optimierung


von Henning (Gast)


Lesenswert?

Hi,

ich bin grad relativ erfolgreich am Debuggen, denn ich habe den Fehler 
zwar gefunden, weis aber leider nicht, wie ich ihn beheben kann.

ich habe eine globale Variable in meiner uart.c
1
unsigned char UART_TX_BufferRead;
wenn ich die static deklariere macht das ganze zwar einen kleinen 
unterschied.
Mit hilfe der While-Schleife will ich auf eine freie Zelle in meinem 
Buffer warten.
1
unsigned char tmp;
2
//Schreibzeiger einen weiter
3
tmp = (UART_TX_BufferWrite + 1) % UART_TX_BufferSize;
4
//warten bis Buffer nicht mehr voll ist
5
while (tmp == UART_TX_BufferRead) ;
6
//einschreiben der daten in den Buffer array
7
foo()
In einem Interrupt wird dann irgendwann eine Zelle freigegeben.
1
UART_TX_BufferRead = (UART_TX_BufferRead + 1) % UART_TX_BufferSize;
Nun das Problem:
Der Compiler macht daraus den folgenden Assembler-Code. Da das BREQ 
jedoch nur eine und nicht zwei befehle zurückspringt bekommt die 
While-Schleife nicht mit, das sich UART_TX_BufferRead geändert hat (R18 
wird nicht aktuallisiert).

87:         while (tmp == UART_TX_BufferRead) ;
+000018BB:   91200417    LDS     R18,0x0417       Load direct from data 
space
+000018BD:   1782        CP      R24,R18          Compare
+000018BE:   F3F1        BREQ    PC-0x01          Branch if equal

Wie bringe ich dem Compiler bei, das er in der while schleife immer den 
aktuellen UART_TX_BufferRead neu holen soll?
Reicht eine andere deklaration der Variable, oder muss am Aufruf etwas 
geändert werden?

Vielen dank im Voraus!
Henning

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

volatile

von Henning (Gast)


Lesenswert?

ich habe noch herausgefunden, das das Problem bei der Optimierung mit 
-Os entsteht. Wenn ich -O0 (Ohh Null) nehme, dann klappt das ganze bei 
folgendem Code.
1
unsigned char tmp2;
2
...
3
tmp2 = UART_TX_BufferRead;
4
while (tmp == tmp2)
5
  tmp2 = UART_TX_BufferRead;
6
...

Das ist aber ja nicht sinn der Sache... also was tun?

von Henning (Gast)


Lesenswert?

Hey Danke!!! Genau das wars!

von Nasenmann (Gast)


Lesenswert?

Ist so eine Optimierung nicht ein Bug vom Compiler ?
Kann ja eigentlich nicht sein das er eine Funktion "wegoptimiert" ?

Würde mich brennend interessieren, da ich auch mittlerweile in C 
programmiere

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Nein, die Verwendung von Variablen in Interruptroutinen und 
Hauptprogramm ist ein Spezialfall. C hat keine Ahnung davon dass es 
sowas wie Interrupts gibt, die den Programmfluss an beliebiger Stelle 
unterbrechen und Variablen im Speicher ändern können. Siehe das 
entsprechende Kapitel im AVR-GCC-Tutorial.

von Nasenmann (Gast)


Lesenswert?

Ahh. Danke.

Habe es mir im Tut. durchgelesen und direkt im Hinterkopf gespeichert.
Da sind ja soviele Sachen , die man als Anfänger beim Programmieren in C 
beachten muß, damit man sich nicht den Wolf sucht beim debuggen.

Trotzdem finde ich C zum Programmieren echt 1A. Hatte es lange Zeit vor 
mir hergeschoben, aber jetzt wo ich damit arbeite bin ich echt 
begeistert.

von Ulrich (Gast)


Lesenswert?

@Nasenmann:

Hast du davor in asm oder bascom programmiert?

von Rolf Magnus (Gast)


Lesenswert?

> Ist so eine Optimierung nicht ein Bug vom Compiler ?

Nein, denn Interrupt-Routinen werden nicht als Teil des normalen 
Programmflusses ausgeführt. Sie werden ja nirgends explizit aufgerufen. 
Der Compiler weiß nicht, daß sie irgendwann mitten im Programm auf 
einmal ausgeführt werden. Der Löwenanteil des existierenden C-Codes muß 
sich auch mit sowas nicht beschäftigen. Deshalb darf der Compiler solche 
Optimierungen durchführen. volatile ist nun genau für solche Fälle wie 
Interrupt-Routinen gedacht. Du sagst dem Compiler damit, daß die 
Variable auch außerhalb des normalen Programmflusses gelesen und/oder 
geschrieben wird und daher Zugriffe darauf nicht wegoptimiert werden 
dürfen. Ein anderes Beispiel für den Einsatz von volatile sind 
Hardware-Register, die in den Speicher-Adressraum gemapt sind.

> Kann ja eigentlich nicht sein das er eine Funktion "wegoptimiert" ?

Nicht die Funktion, sondern der Variablenzugriff wird wegoptimiert.
Der Compiler sieht, daß ein
1
while (tmp == UART_TX_BufferRead) ;

tmp und UART_TX_BufferRead nicht ändert und geht deshalb davon aus, daß 
beide in der Schleife konstant sind. Er wird sie deshalb ersetzen z.B. 
durch sowas wie:
1
if (tmp == UART_TX_BufferRead)
2
    while(1);

  

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.