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
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
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 };
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
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
__udivmodsi4 kommt vom compiler, steht in libgcc. Revisions-Log siehe hier: http://gcc.gnu.org/viewcvs/trunk/gcc/config/avr/libgcc.S
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
> 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.
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
Vergessenes make clean => rebuild all..? Möglicherweise wurden Object-Dateien der verschidene GCC Versionen gelinkt.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.