www.mikrocontroller.net

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


Autor: Henning (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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.
unsigned char tmp;
//Schreibzeiger einen weiter
tmp = (UART_TX_BufferWrite + 1) % UART_TX_BufferSize;
//warten bis Buffer nicht mehr voll ist
while (tmp == UART_TX_BufferRead) ;
//einschreiben der daten in den Buffer array
foo()
In einem Interrupt wird dann irgendwann eine Zelle freigegeben.
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

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
volatile

Autor: Henning (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
unsigned char tmp2;
...
tmp2 = UART_TX_BufferRead;
while (tmp == tmp2)
  tmp2 = UART_TX_BufferRead;
...

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

Autor: Henning (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey Danke!!! Genau das wars!

Autor: Nasenmann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nasenmann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Nasenmann:

Hast du davor in asm oder bascom programmiert?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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:
if (tmp == UART_TX_BufferRead)
    while(1);

  

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.