mikrocontroller.net

Forum: Compiler & IDEs AVR-GCC: Compilerfehler?


Autor: Werner Hoch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo erstmal,

ich hab jetzt mit dem AVR-GCC angefangen, aber wenn ich mir so das 
Ergebnis anschaue, dann kommen mir Zweifel.

Ich hab mir 2 Warteschleifen geschrieben, in der .lst-Datei sehen die 
dann so aus:

void
lcd_delay_5ms() {
  uint16_t i;
  /* t = i * loop / UC_CLOCK
     i = t / loop * UC_CLOCK
     the fastest way the compiler can do that loop takes 4 clocks:
     2 clocks for decrementing and 2 clocks to branch
     take care that i does not exceed max(uint16_t) */
  for (i=UC_CLOCK*0.005/4; i; i--)
 1be:  80 e0         ldi  r24, 0x00  ; 0
 1c0:  94 e2         ldi  r25, 0x24  ; 36
 1c2:  42 97         sbiw  r24, 0x12  ; 18
 1c4:  f1 f7         brne  .-4        ; 0x1c2
  ;
}
 1c6:  08 95         ret

UC_CLOCK ist 7372800.
r24 und r25 werden richtig geladen, aber in der nächsten Zeile wird 0x12 
subtrahiert.


inline void
lcd_delay_50us() {
  uint8_t i;
  /* t = i * loop / UC_CLOCK
     i = t / loop * UC_CLOCK
     the fastest way the compiler can do that loop takes 3 clocks:
     1 clocks for decrementing, 2 clocks to branch
     take care that i does not exceed max(uint8_t) */
  for (i=UC_CLOCK*50e-6/3; i; i--)
    ;
}

dieser Block wird so übersetzt:
 1fe:  8a e7         ldi  r24, 0x7A  ; 122
 200:  82 50         subi  r24, 0x02  ; 2
 202:  f1 f7         brne  .-4        ; 0x200

r24 wird wieder richtig geladen, aber dann mit 2 decrementiert.

Mach ich nur einen Denkfehler oder ist tatsächlich was faul?

mfg
werner

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warteschleifen werden gnadenlos wegoptimiert.  Entweder die
Zählvariable "volatile" deklarieren (siehe FAQ, 1. Punkt) oder
in (inline) assembler schreiben -- für letzteres gibt es in
#include <avr/delay.h> schon bißchen was Vorgefertigtes.

Autor: Werner Hoch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke.

Solche "Optimierungen" hätte ich nicht erwartet.

mfg
werner

Autor: Werner Hoch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: Autsch

Das Einfügen von volatile hatte unerwartete Auswirkungen, ich werd mir 
jetzt die vorgefertigten Routinen anschauen.

Der Assembler Code is dadurch "etwas" länger geworden:

lcd_delay_5ms() {
 1be:  cf 93         push  r28
 1c0:  df 93         push  r29
 1c2:  cd b7         in  r28, 0x3d  ; 61
 1c4:  de b7         in  r29, 0x3e  ; 62
 1c6:  22 97         sbiw  r28, 0x02  ; 2
 1c8:  0f b6         in  r0, 0x3f  ; 63
 1ca:  f8 94         cli
 1cc:  de bf         out  0x3e, r29  ; 62
 1ce:  0f be         out  0x3f, r0  ; 63
 1d0:  cd bf         out  0x3d, r28  ; 61
  volatile uint16_t i;
  /* t = i * loop / UC_CLOCK
     i = t / loop * UC_CLOCK
     the fastest way the compiler can do that loop takes 4 clocks:
     2 clocks for decrementing and 2 clocks to branch
     take care that i does not exceed max(uint16_t) */
  for (i=UC_CLOCK*0.005/4; i; i--)
 1d2:  80 e0         ldi  r24, 0x00  ; 0
 1d4:  94 e2         ldi  r25, 0x24  ; 36
 1d6:  89 83         std  Y+1, r24  ; 0x01
 1d8:  9a 83         std  Y+2, r25  ; 0x02
 1da:  89 81         ldd  r24, Y+1  ; 0x01
 1dc:  9a 81         ldd  r25, Y+2  ; 0x02
 1de:  89 2b         or  r24, r25
 1e0:  49 f0         breq  .+18       ; 0x1f4
 1e2:  89 81         ldd  r24, Y+1  ; 0x01
 1e4:  9a 81         ldd  r25, Y+2  ; 0x02
 1e6:  01 97         sbiw  r24, 0x01  ; 1
 1e8:  89 83         std  Y+1, r24  ; 0x01
 1ea:  9a 83         std  Y+2, r25  ; 0x02
 1ec:  89 81         ldd  r24, Y+1  ; 0x01
 1ee:  9a 81         ldd  r25, Y+2  ; 0x02
 1f0:  89 2b         or  r24, r25
 1f2:  b9 f7         brne  .-18       ; 0x1e2
  ;
}
 1f4:  22 96         adiw  r28, 0x02  ; 2
 1f6:  0f b6         in  r0, 0x3f  ; 63
 1f8:  f8 94         cli
 1fa:  de bf         out  0x3e, r29  ; 62
 1fc:  0f be         out  0x3f, r0  ; 63
 1fe:  cd bf         out  0x3d, r28  ; 61
 200:  df 91         pop  r29
 202:  cf 91         pop  r28
 204:  08 95         ret


mfg
werner

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, logisch, volatile verbietet die Optimierung auf der
genannten Variablen, d. h. es ist jedesmal ein Speicherzugriff
durchzuführen.  Ist vor allem gedacht, wenn man eine Variable
als shared memory zwischen einer Interruptroutine und dem
Hauptprogramm benutzen will, oder aber für memory mapped IO,
bei dem eine Adresse nicht auf eine Speicherstelle sondern ein
Peripherie-Steuerregister zeigt (gibt's ja auch beim AVR, und
bei den extended IO registers des ATmega128 muß man das auch
benutzen, die sind nicht mehr über IN oder OUT erreichbar).

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.