Forum: Mikrocontroller und Digitale Elektronik GCC, Cortex-M3 (LPC1768) und Fließkommazahlen


von Eduard S. (rfk)


Lesenswert?

Hallo,

bei meinem LPC1768 Cortex-M3 in Kombination mit meiner GCC 4.4.1 
Toolchain (Linux) habe ich heute ein komisches Verhalten entdeckt, wenn 
Fließkommazahlen in Modulen auftauchen. Es geht dabei um folgende 
Beispielfunktion:
1
void demo_fail(unsigned long p1, unsigned long p2) {
2
  log("STEP 1");
3
  double f = 0.0, d = 1.0;
4
5
  log("STEP 2");
6
  f = (double)p1/(16.0*(double)p2*d);
7
8
  log("STEP 3");
9
  if (f <= 1.1 || f >= 1.9) {
10
11
    log("STEP 4");
12
    for (f = 1.1; f <= 1.9; f += 0.1)
13
      d++;
14
  }
15
16
  log("STEP 5");
17
}

Ist diese Funktion innerhalb meiner main.c, funktioniert deren Aufruf 
"demo_fail(1,1)" komplett. Ist sie hingegen in ein Modul ausgelagert, 
ist "STEP 2" die letzte Ausgabe, die ich sehe (also hängt die 
double-Berechnung).

Übersetzt wird das Ganze fehlerfrei mit:
1
arm-none-eabi-gcc -marm -mcpu=cortex-m3 -mthumb -msoft-float 
2
   -ffreestanding -Wall -std=gnu99 -Wno-parentheses
3
   -fomit-frame-pointer -fshort-wchar -O3 -g -c -o mod.o mod.c
4
arm-none-eabi-gcc -marm -mcpu=cortex-m3 -mthumb -msoft-float 
5
   -ffreestanding -Wall -std=gnu99 -Wno-parentheses
6
   -fomit-frame-pointer -fshort-wchar -O3 -g -c -o main.o main.c
7
arm-none-eabi-ld --no-wchar-size-warning -T lpc1768.x -o main.elf
8
   main.o mod.o

Die folgenden beiden Varianten der Funktion (1 ohne Funktionsparameter, 
2 ohne Fließkommazahlen) funktionieren auch in einem Modul einwandfrei:
1
void demo_ok1() {
2
  log("STEP 1");
3
  unsigned long p1 = 1, p2 = 1;
4
  double f = 0.0, d = 1.0;
5
6
  log("STEP 2");
7
  f = (double)p1/(16.0*(double)p2*d);
8
9
  log("STEP 3");
10
  if (f <= 1.1 || f >= 1.9) {
11
12
    log("STEP 4");
13
    for (f = 1.1; f <= 1.9; f += 0.1)
14
      d++;
15
  }
16
17
  log("STEP 5");
18
}
19
20
void demo_ok2(unsigned long p1, unsigned long p2) {
21
  log("STEP 1");
22
  int f = 0, d = 1;
23
24
  log("STEP 2");
25
  f = p1/(16*p2*d);
26
27
  log("STEP 3");
28
  if (f <= 1 || f >= 2) {
29
30
    log("STEP 4");
31
    for (f = 1; f <= 2; f += 1)
32
      d++;
33
  }
34
35
  log("STEP 5");
36
}

Hat jemand eine Idee, woran das liegen könnte?! Danke vorab.

von arm-gast (Gast)


Lesenswert?

eine Funktion log zu benennen halte ich nicht für gut, denn in math.h 
gibt es ja: double log(double x)  natürlicher Logarithmus ln(x), x > 0
vielleicht liegt da der Fehler.!?

von Eduard S. (rfk)


Lesenswert?

Da habe ich beim Vereinfachen des Codes nicht nachgedacht. Ich habe die 
Funktion nur der Einfachheit halber hier log() genannt (auch wenn ich 
nicht gegen die libmath linke). Das ist also nicht das Problem. :)

von Eduard S. (rfk)


Lesenswert?

Keine weiteren Ideen?

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Probiere mal -lc und -lm beim Linker mit an zu geben, unmittelbar vor 
dem -o Parameter

von Eduard S. (rfk)


Lesenswert?

Ich habe weder die libc noch die libm zur Verfügung.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

das glaub ich nicht.

Schaue hier:
.... \CodeSourcery\arm-none-eabi\lib

Da gibt es die Datei libc.a und libm.a

von Eduard S. (rfk)


Lesenswert?

Das kannst du mir ruhig glauben, ich habe eine eigens übersetzte 
Toolchain und absichtlich keine libc und libmath... wieso glaubst du, 
dass es damit funktioniert? Das sieht mir irgendwie eher nach einem Bug 
aus.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ich meine vor laaanger zeit hatte ich mal ein ähnliches Problem. Kann 
mich nur noch dunkel daran erinnern. Erst mit dem Einbinden ging es 
dann.

Im Setup von Codesourcery werden die Libs mit installiert.

von Eduard S. (rfk)


Lesenswert?

Das kommt mir bekannt vor, ich kann mich ebenso dunkel an einen Fall 
erinnern, bei dem das Funktionieren von der Position der libgcc in der 
Parameterliste abhing.

Leider scheint das hier nicht der Fall zu sein, ich habe es gerade mit 
der Codesourcery Toolchain gemäß deinem Vorschlag versucht, das Ergebnis 
ist aber leider dasselbe. Trotzdem danke für die Idee.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Kannst Du das nicht mit s32 rechnen und einen Multiplikator von z.B. 
1000 verweden?

Ich habe auch mal eine recht komplexe Formel auf s32 umgestellt:
Beitrag "Re: SHT11, Abweichung bei Temperatur"

Hier wäre die Float-Formel:
Beitrag "Re: SHT11, Abweichung bei Temperatur"

von Eduard S. (rfk)


Lesenswert?

Bisher habe ich das auch immer so gemacht. Bei manchen Berechnungen wäre 
es aber halt viel einfacher und schöner, Fließkommazahlen zu haben.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ich habe meine Formel wegen der Geschwindigkeit umgebaut. Du könntest 
vielleicht eine Float-Zahl wandeln in eine s32, dann berechnen, dann 
wiederzurück in Float. Ich weiß ja nicht wie komplex Deine Formeln sind, 
bzw. ob Du cos/sin Funktionen brauchst.

PS: Versuche es doch mal mit dem Datentyp float un nicht mit double.

von Eduard S. (rfk)


Lesenswert?

Versteh mich bitte nicht falsch, aber mir geht's da eher ums Prinzip. 
Falls es tatsächlich ein Bug ist, ist er in den aktuellen Versionen auch 
noch vorhanden. Habe mittlerweile folgende Kombinationen durch:

gcc 4.4.1 / binutils 2.19.1
gcc 4.4.1 / binutils 2.19.51.20090709 (Sourcery)
gcc 4.5.0 / binutils 2.20

Mit "float" kommt er immerhin zu "STEP 3".

von Mars (Gast)


Lesenswert?

Dann schau dir doch mal den generierten Assembler-Code an, bzw. poste 
diesen hier.

von Eduard S. (rfk)


Angehängte Dateien:

Lesenswert?

Disassembly des Funktionsaufrufs in main() und von demo_fail() (mit 
Source) siehe Anhang.

von Eduard S. (rfk)


Lesenswert?

Push.

von Uwe H. (uwehermann) Benutzerseite


Lesenswert?

Halte ich zwar für unwahrscheinlich dass es daran liegt, aber trotzdem: 
Prober mal statt -O3 lieber -O2 oder -O0 (zumindest testweise), evtl. 
ist das schlicht ein Compilerbug oder sowas in der Richtung.

Außerdem könnten die Optionen die du beim bauen der Toolchain verwendet 
hast eine Rolle spielen (also nicht nur die Optionen mit denen du den 
Compiler aufrufst), z.B. --with-float=soft u.ä.

Und/oder probier auch mal eine andere toolchain-Version um festzustellen 
ob es evtl. ein Compilerbug in dieser Version ist.

HTH, Uwe.

von Eduard S. (rfk)


Lesenswert?

Unterschiedliche Optimierungsstufen habe ich schon hinter mir und 
unterschiedliche Toolchains auch, siehe oben. Die Toolchains sind wie 
folgt konfiguriert:
1
Target: arm-none-eabi
2
Configured with: ../gcc-4.4.1/configure --target=arm-none-eabi --prefix=/usr/local/toolchain/arm-none-eabi-4.4.1 --enable-interwork --enable-multilib --enable-languages=c --disable-fpu --disable-nls --disable-shared --disable-libssp --without-headers
3
Thread model: single
4
gcc version 4.4.1 (GCC)
5
6
Target: arm-none-eabi
7
Configured with: ../gcc-4.5.0/configure --target=arm-none-eabi --prefix=/usr/local/toolchain/arm-none-eabi-4.5.0 --enable-interwork --enable-multilib --enable-languages=c --with-newlib --with-headers=../newlib-1.18.0/newlib/libc/include --with-float=soft
8
Thread model: single
9
gcc version 4.5.0 (GCC)
10
11
Target: arm-none-eabi
12
Configured with: /scratch/julian/2010q1-release-eabi-lite/src/gcc-4.4-2010q1/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-eabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --enable-extra-sgxxlite-multilibs --with-gnu-as --with-gnu-ld --with-specs='%{O2:%{!fno-remove-local-statics: -fremove-local-statics}} %{O*:%{O|O0|O1|O2|Os:;:%{!fno-remove-local-statics: -fremove-local-statics}}}' --enable-languages=c,c++ --disable-shared --disable-lto --with-newlib --with-pkgversion='Sourcery G++ Lite 2010q1-188' --with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery --with-headers=yes --with-sysroot=/opt/codesourcery/arm-none-eabi --with-build-sysroot=/scratch/julian/2010q1-release-eabi-lite/install/arm-none-eabi --with-gmp=/scratch/julian/2010q1-release-eabi-lite/obj/host-libs-2010q1-188-arm-none-eabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/julian/2010q1-release-eabi-lite/obj/host-libs-2010q1-188-arm-none-eabi-i686-pc-linux-gnu/usr --with-ppl=/scratch/julian/2010q1-release-eabi-lite/obj/host-libs-2010q1-188-arm-none-eabi-i686-pc-linux-gnu/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-cloog=/scratch/julian/2010q1-release-eabi-lite/obj/host-libs-2010q1-188-arm-none-eabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/julian/2010q1-release-eabi-lite/install/arm-none-eabi/bin --with-build-time-tools=/scratch/julian/2010q1-release-eabi-lite/install/arm-none-eabi/bin
13
Thread model: single
14
gcc version 4.4.1 (Sourcery G++ Lite 2010q1-188)

von Eduard S. (rfk)


Lesenswert?

Auch dieses Thema hat sich erledigt, seit ich gegen die korrekte 
thumb2-Variante der libgcc linke!

von 900ss (900ss)


Lesenswert?

Eduard Steinberg schrieb:
> ich habe eine eigens übersetzte
> Toolchain und absichtlich keine libc und libmath...

Weshalb eigentlich selbst übersetzt?
Gibt es nichts fertiges für dich?
Evtl. hättest du dir den Ärger sparen können aber jetzt hast du
was gelernt ;-)

von Eduard S. (rfk)


Lesenswert?

Ich hab's doch auch mit der Toolchain von CodeSourcery versucht, doch 
auch da muss man nun mal gegen die thumb2-libgcc linken... ;-) Zum Thema 
selbst übersetzen: ich habe da einfach die bessere Kontrolle über 
diverse Einstellungen (z.B. SMALLMEM bei der newlib).

von falstaff (Gast)


Lesenswert?

Vieleicht eine division durch 0? Ja ich weiss, sollte es ned sein, 
berechne den Divident und Divisior vor und schau ob diese 0 sind...

Ansonsten wäre ein direkter vergleich der Disassemblies interessant (als 
Modul vs. in Main, mit dem gleichen Compiler...)

von Eduard S. (rfk)


Lesenswert?

Eduard Steinberg schrieb:
> Auch dieses Thema hat sich erledigt, seit ich gegen die korrekte
> thumb2-Variante der libgcc linke!

Aber Danke. ;-)

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.