mikrocontroller.net

Forum: Compiler & IDEs Macht GCC 4.2.1 fuer AVR hier einen Fehler?


Autor: Juergen Beisert (jbeisert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mich schon dusselig gesucht, woran es liegen kann, daß bei 
diesem einfachen Ausdruck etwas schiefgeht:

---------
static const prog_uint32_t stimul_rates[] = {
  ((10000000000UL / F_CPU) + 5) / 10,
  (((10000000000UL / F_CPU) << 3) + 5) / 10,
  (((10000000000UL / F_CPU) << 5) + 5) / 10,
  (((10000000000UL / F_CPU) << 6) + 5) / 10,
  (((10000000000UL / F_CPU) << 7) + 5) / 10,
  (((10000000000UL / F_CPU) << 8) + 5) / 10,
  (((10000000000UL / F_CPU) << 10) + 5) / 10
};

int8_t bla(uint32_t *length)
{
uint32_t count;
int i;

[...]
/* Berechnung von i */
[...]
count = (*length + (pgm_read_dword(&stimul_rates[i]) >> 1)) /
      pgm_read_dword(&stimul_rates[i]);
[...]
}
----------------------

Letztenendes versuche ich hier, eine PWM zu programmieren und "count" 
wird dazu benutzt, den Zeitpunkt festzulegen, bei dem das Ausgangssignal 
den Pegel wechseln soll.
Aber: "count" wird immer zu 0, es kommt nie etwas anderes raus. Der 
Zugriff auf die Tabelle funktioniert, weil an anderen Stellen in der 
gleichen Funktion ebenfalls auf die gleiche Art zugegriffen wird und 
dabei korrekte Ergebnisse entstehen.

Ich habe die Funktion testweise auf meinem Host übersetzt, und es kommen 
auch die Ergebnisse dabei raus (abhängig von *length und i), die ich 
erwartet habe.

Eben hatte ich noch die Idee, statt dem GCC 4.2.1, mal den älteren GCC 
3.4.2 zu versuchen. Und siehe da, nun kommen auch brauchbare Werte bei 
der Berechnung raus!

Wie grenzt man so einen Fehler ein, um entweder eine Lösung zu finden 
oder zumindest einen Bug-Report zu erstellen? Oder wie sucht man nach so 
einem Fehler, ob das nicht schon längst gelöst ist? Der erzeugte 
Assembler-Code an der Stelle ruft __udivmodsi4 für die Division auf. 
Kommt das aus dem Compiler oder aus der avr-libc? Denn wenn ich den 
älteren GCC verwende, kommt auch eine ältere avr-libc zum Einsatz. Somit 
kann ich das derzeit nicht eindeutig zuordnen.

Für ein paar Tipps wäre ich dankbar.

Jürgen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Diese Division hier

  (pgm_read_dword(&stimul_rates[i]) >> 1) /
        pgm_read_dword(&stimul_rates[i]);

wird immer 0 ergeben

es hängt als von *length ab, ob da jemals etwas größeres
las 0 entstehen wird. Solange *length nicht größer als
die Hälfte von pgm_read_dword(&stimul_rates[i]) ist, wird
das aber nichts

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist 10'000'000'000  nicht etwas zu gross für "UL"? Wie wärs mit "ULL"

=> 10000000000ULL

static const prog_uint32_t stimul_rates[] =
{
  (( 10000000000ULL / F_CPU) + 5) / 10,
  (((10000000000ULL / F_CPU) << 3) + 5) / 10,
  (((10000000000ULL / F_CPU) << 5) + 5) / 10,
  (((10000000000ULL / F_CPU) << 6) + 5) / 10,
  (((10000000000ULL / F_CPU) << 7) + 5) / 10,
  (((10000000000ULL / F_CPU) << 8) + 5) / 10,
  (((10000000000ULL / F_CPU) << 10) + 5) / 10
};

Autor: Juergen Beisert (jbeisert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Diese Division hier
>
>   (pgm_read_dword(&stimul_rates[i]) >> 1) /
>         pgm_read_dword(&stimul_rates[i]);
>
> wird immer 0 ergeben
>
> es hängt als von *length ab, ob da jemals etwas größeres
> las 0 entstehen wird. Solange *length nicht größer als
> die Hälfte von pgm_read_dword(&stimul_rates[i]) ist, wird
> das aber nichts

So soll es ja auch sein. Die Funktionen, die hier das "*lengt"
durchreichen, stellen sicher, daß diese Randbedingung eingehalten wird.

Allerdings sehen GCC 4.2.1 und GCC 3.4.2 den ganzen Ausdruck 
unterschiedlich. Zumindest sind sie unterschiedlicher Meinung was am 
Ende rauskommt. Bug oder Feature?

Gruß
Jürgen

Autor: Juergen Beisert (jbeisert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter wrote:
> Ist 10'000'000'000  nicht etwas zu gross für "UL"? Wie wärs mit "ULL"
>
> => 10000000000ULL
>
> static const prog_uint32_t stimul_rates[] =
> {
>   (( 10000000000ULL / F_CPU) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 3) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 5) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 6) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 7) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 8) + 5) / 10,
>   (((10000000000ULL / F_CPU) << 10) + 5) / 10
> };

Hmm, gute Frage. Bei meinen Tests stehen in der Tabelle aber die 
richtigen Werte (hier für 16MHz Grundtakt):

Entry 0: 0000003F (63)
Entry 1: 000001F4 (500)
Entry 2: 000007D0 (2000)
Entry 3: 00000FA0 (4000)
Entry 4: 00001F40 (8000)
Entry 5: 00003E80 (16000)
Entry 6: 0000FA00 (64000)

Das Gleiche entsteht, wenn ich stattdessen "ULL" verwende.

Gruß
Jürgen

Autor: Luther Blissett (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__udivmodsi4 kommt vom compiler, steht in libgcc.

Revisions-Log siehe hier:
http://gcc.gnu.org/viewcvs/trunk/gcc/config/avr/libgcc.S

Autor: Juergen Beisert (jbeisert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Juergen Beisert wrote:
>[...]
> Eben hatte ich noch die Idee, statt dem GCC 4.2.1, mal den älteren GCC
> 3.4.2 zu versuchen. Und siehe da, nun kommen auch brauchbare Werte bei
> der Berechnung raus!
>
> Wie grenzt man so einen Fehler ein, um entweder eine Lösung zu finden
> oder zumindest einen Bug-Report zu erstellen? Oder wie sucht man nach
> so einem Fehler, ob das nicht schon längst gelöst ist? Der erzeugte
> Assembler-Code an der Stelle ruft __udivmodsi4 für die Division auf.
> Kommt das aus dem Compiler oder aus der avr-libc? Denn wenn ich den
> älteren GCC verwende, kommt auch eine ältere avr-libc zum Einsatz.
> Somit kann ich das derzeit nicht eindeutig zuordnen.

Wenn ich die Funktion in ein eigenständiges Programm auslagere, liefert 
auch der GCC 4.2.1 ein richtiges Ergebnis auf dem AVR. Die Funktion 
fällt also nur im Verbund der gesamten Applikation und GCC 4.2.1 auf die 
Nase.
Was kann denn sowas sein? Problem mit dem Stack? Zu viel Optimierung von 
Seiten GCC?

Gruß
Jürgen

Autor: Luther Blissett (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Was kann denn sowas sein? Problem mit dem Stack? Zu viel Optimierung von
Seiten GCC?

gcc 4.2's Verhalten bei undefined behavior (UB) ist anders als bei der 
3er Serie. So werden signed int operation jetzt defaultmässig so 
optimiert als ob es keinen Überlauf gäbe. Falls dein code dann irgendwo 
davon ausgeht, daß 2er Komplement Überläufe stattfinden, dann läuft er 
idR. nicht mehr.

Schau mal ob -Wall etwas sagt. Probier mal mit -fwrapv zu kompilieren.

Autor: Juergen Beisert (jbeisert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arrrrghhh, war gestern eine besondere Mondstellung? Heute kommt die 
gleiche Routine auf dem AVR auch mit dem GCC 4.2.1 zum richtigen 
Ergebnis. Aber Subversion sagt mir, ich hätte an den Rahmenbedingungen 
und den Quellen nichts verändert (nicht mal den Entwicklungshost neu 
gestartet!). Gna, gna, gna, ich geh' am Stock. Offenbar einen ganzen Tag 
Phantome gesucht.

Danke aber erst mal für die Tipps und Korrekturen. Die baue ich jetzt 
dauerhaft ein. Mal sehen ob dieser komische Fehler wieder auftritt.

Jürgen

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vergessenes make clean => rebuild all..?

Möglicherweise wurden Object-Dateien der verschidene GCC Versionen 
gelinkt.

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.