EmbeddedRelated.com
Forums

Problem with GNU ARM Toolchain and math functions

Started by Fausto Marzoli October 29, 2007
Alle 15:30, luned29 ottobre 2007, Paul Curtis ha scritto:

> with "libm". I did not track down the problems with the underlying floating
> point problems, but we did submit a patch to CodeSourcery which eventually
> made it into their distribution.

I'm using the last source GNU-ARM distribution from gnuarm.org:
BINUTILS 2.17
GCC 4.2.0
NEWLIB 1.15.0
INSIGHT 6.6
> I wrote this not because the floating point had problems, but to ensure that
> our library is not covered by GPL and LGPL licenses. The fact that our code
> is faster, smaller, and executes correctly is a nice side effect.

Very nice!!!!! Expecially the last "side effect": it works!
;-)
> and MAXQ20 assembly code. After a while you get sick of writing it but you
> feel good when it's done.

I can understand what you mean.
> > I think it's an endianness problem (there are some unions for direct
> > byte access in floating point math that I don't like very much), but I'm
>
> Yep, I can say that it's not pleasant but I do the same type of thing.
> However, our code works on ARMs that have any byte order.

Well, to be honest I've often used ASM code to byte-access words or similars
in microcontroller based systems.
I've never used unions because I always guess how the compiler interprets
them, but I think it's the same as using ASM...
> > (I am very very very attracted by Crossworks, its C library and also
> > its multitask library. Some time ago I tried the linux demo version but I
> > had some trouble with USB jtag connection... but I will retry it soon).
>
> Which JTAG adapter?

I have Amontec JtagKey and Olimex ARM-USB-OCD: they both had some trouble in
being seen by the Crossworks IDE under Linux (I'm using SuSE Linux 10.2).

But I didn't go deep in the problem. I'll retry soon.
Well, I'm at a stop point with Newlib and float math, anyway...........

--
Fausto Marzoli - 8052.it - http://www.8052.it/

An Engineer's Guide to the LPC2100 Series

Alle 13:04, luned29 ottobre 2007, Paul Curtis ha scritto:

> Yeah, but I coded all that floating point tomfoolery, it's our own library.
> And, what's more, it *works* because it's passed a huge number of tests on
> all ARM architectures.

Did you coded it by scratch because you know that newlib is problematic? I
mean, do you know that some newlib function does not work properly with ARM7?
This information is very precious.

At the beginning I thought that it was a problem of my code or configuration
or linking or building options, or in the startup code, but now I'm quite
sure it's a newlib problem.
I made a lot of tests and debugging, also in the newlib library itself, but
I've not yet fixed the problem.
I think it's an endianness problem (there are some unions for direct byte
access in floating point math that I don't like very much), but I'm not sure.

(I am very very very attracted by Crossworks, its C library and also its
multitask library. Some time ago I tried the linux demo version but I had
some trouble with USB jtag connection... but I will retry it soon).

--
Fausto Marzoli - 8052.it - http://www.8052.it/
Alle 22:25, luned29 ottobre 2007, rtstofer ha scritto:

> I'm not saying that newlib works but, considering how many ports are
> out there and how many developers are using it, I would be hesitant to
> say there is a problem.

I agree with you: I am hesitant in saying that there is a problem in newlib.
But I'm starting to think so.

Having someone else that used math floating point functions with success would
make me sure that the problem is mine.
But noone confirmed to have used something like pow(3.2, 4.3) in a real
hardware (not simulator) with success up to now.

I will be very happy to learn that it's a problem in my code!
> There are some fundamental floating point operations: add, subtract,
> multiply and divide. From there, the other functions are built by
> using various series expansions or other well known algorithms. They
> all rely on the four fundamental operations to varying degrees. All
> of the high level operations are written in C - how hard can it be to
> verify the code?

For me, verifying the newlib source code in the real hardware is not so
simple.
I'm doing that, but it's not a simple task. Moreover, I'm not a math routine
expert.
> My guess: stack problem. Or some other unrelated issue such as nested
> interrupt routines.

Could be stack. Seems to be the stack and I hope it's the stack.
I can't fix where is the stack problem up to now, but this is a real
possibility.

My simple test program does not use interrupts, so can't be nested interrupts.
> A test program should take about 10 lines of code (not counting crt.s)
> and it really couldn't be that hard to debug. So write a 10 line
> program, bundle it up with crt.s, the makefile and linker script and
> post it in the files section. Then everybody can hack away at it and
> try to find the problem.

I'll do it as soon as possibile: thank you for the suggestion!
> Something really simple:
>
> #include
> #include float result;
>
> int main(void)
> {
> result = sin(0.523598333);
> printf("sin(30) = %f\n", result);
> }

Well, real hardware does not have "printf" without using UART and so using
interrupts and other complex routines that can interphere with the simple
math function we are debugging.

My test program simply blinks a led with a delay() routine when I press a
pushbutton; the delay() routine has a loop that calls a math function (only
to test it).

Do you think it could be simple enough for being tested by other people? Maybe
that the pushbutton and a LED are not available on every hardware. But I
can't think a simpler way to do it.
> printf("sin(30) = %f\n",sin(0.523598333));
>
> to main.c of John Wren's EXCELLENT LPC2148 demo code (just ahead of
> the task setup) and added -lm to the link flags and voila' The 2148
> prints:
>
> sin(30) = 0.500000

Great! You did it on a real hardware? Which compiler/newlib version?
May you please email me or upload somewhere the demo code with the
compiling/linking/etc options?

I just downloaded the John Wren's LPC2148 demo code: I just have to use it to
test your sin() code?

Thank you very much for your suggestions: I'm going to try the John Wren's
demo code today.
Fausto

--
Fausto Marzoli - 8052.it - http://www.8052.it/
> > printf("sin(30) = %f\n",sin(0.523598333));
> >
> > to main.c of John Wren's EXCELLENT LPC2148 demo code (just ahead of
> > the task setup) and added -lm to the link flags and voila' The 2148
> > prints:
> >
> > sin(30) = 0.500000
>
> Great! You did it on a real hardware? Which compiler/newlib version?
> May you please email me or upload somewhere the demo code with the
> compiling/linking/etc options?
>

I don't have a simulator, the test was done on real hardware. Even if
I did have a simulator, I wouldn't trust it.

I tried pow(9.0, 3.0) and this is the result:

pow(9.0, 3.0) = 729.000000

arm-elf-gcc (GCC) 4.0.2
newlib 1.14 as far as I can tell.

Changes to main.c of demo code:

#include <-- existing include
#include <-- added this line
...
...
memset (taskHandles, 0, sizeof (taskHandles)); <-- existing code

printf("sin(30) = %f\n",sin(0.523598333)); <-- added this line
printf("pow(9.0, 3.0) = %f\n",pow(9.0, 3.0)); <-- added this line

Changes to Makefile:

export LINKER_FLAGS=-lm $(COMMON)/common.a -Xlinker -olpc2148.elf
-Xlinker -M -Xlinker -Map=lpc2148.map <-- added -lm to start of flag

Richard
Alle 15:24, marted30 ottobre 2007, rtstofer ha scritto:

> I don't have a simulator, the test was done on real hardware. Even if
> I did have a simulator, I wouldn't trust it.

Perfect. So do I.
> I tried pow(9.0, 3.0) and this is the result:
>
> pow(9.0, 3.0) = 729.000000

Thank you for your attenction to me and my problem.

pow() works correctly also for me when using integer arguments, even if you
treat them as float. I mean, pow(9.0, 3.0) works but pow(9.2, 3.3) does NOT
work (in my tests). I found out that newlib math library calls different
procedures with a "wrapper" function depending on the arguments.
> Changes to main.c of demo code:
>
> #include <-- existing include
> #include <-- added this line
> ...
> ...
> memset (taskHandles, 0, sizeof (taskHandles)); <-- existing code
>
> printf("sin(30) = %f\n",sin(0.523598333)); <-- added this line
> printf("pow(9.0, 3.0) = %f\n",pow(9.0, 3.0)); <-- added this line
>
> Changes to Makefile:
>
> export LINKER_FLAGS=-lm $(COMMON)/common.a -Xlinker -olpc2148.elf
> -Xlinker -M -Xlinker -Map=lpc2148.map <-- added -lm to start of flag

Very good. Thank you very much. I'll try to adapt the code to my LPC2106
hardware and try it.
Or I will buy the same Olimex hardware for LPC2148, if necessary.
If it works, my problem is in the linker .ld file or in the startup code.

Thank you again. I will report on this group my test results.
Fausto

--
Fausto Marzoli - 8052.it - http://www.8052.it/
> pow() works correctly also for me when using integer arguments, even
if you
> treat them as float. I mean, pow(9.0, 3.0) works but pow(9.2, 3.3)
does NOT
> work (in my tests). I found out that newlib math library calls
different
> procedures with a "wrapper" function depending on the arguments.

You need to look at the ANSI standard definition for pow(x,y) because
y MUST be an integer and x must be positive.
http://www.thinkage.ca/english/gcos/expl/c/lib/pow.html

Or look at the code in "The Standard C Library" by P.J. Plauger along
with his description of the function.

The real prototype for pow() is:

double pow (double x, double y);

This, again, from the hardware:

pow(9.3, 3.0) = 804.357000

and it agrees with my calculator.

I really don't think your problem has anything to do with the library.
I always use a mental test when I come up against this kind of thing.
What is the probability that I am the only one to discover this
'bug'? Even if it is a bug, someone will have already discovered it
and found a way around. I will never be the first...

Of course the library uses 'wrappers'. Why calculate cos(x) when it
is exactly sin((pi/2) - x)? So the cos() and sin() functions call the
same underlying sine() function (I forgot the exact function name)
with a flag to indicate whether to compute sin() or cos().

Richard
Richard,

> You need to look at the ANSI standard definition for pow(x,y) because
> y MUST be an integer and x must be positive.
> http://www.thinkage.ca/english/gcos/expl/c/lib/pow.html

No, that's complete nonsense, sorry. ;-) Your reference does not say that!
It says that *if* x is negative or zero then y cannot be other than an
integer. It does not constrain y for x>0.

> Or look at the code in "The Standard C Library" by P.J. Plauger along
> with his description of the function.
>
> The real prototype for pow() is:
>
> double pow (double x, double y);
>
> This, again, from the hardware:
>
> pow(9.3, 3.0) = 804.357000

Try pow(9.3, 3.3) and pow(9.9, -3). This should give your calculator and
the library a small workout. It's quite possible to compute these values.

> I really don't think your problem has anything to do with the library.

Actually, that may *not* be true. There are indeed special cases for
dealing with discontinuities, branch cuts, and so on, typically values < and
>= 1 by using different approximations.

Whilst in all probability it is user error, there is a small but finite
chance it is not.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks for ARM, MSP430, AVR, MAXQ, and now Cortex-M3 processors
--- In l..., "Paul Curtis" wrote:
>
> Richard,
>
> > You need to look at the ANSI standard definition for pow(x,y) because
> > y MUST be an integer and x must be positive.
> > http://www.thinkage.ca/english/gcos/expl/c/lib/pow.html
>
> No, that's complete nonsense, sorry. ;-) Your reference does not
say that!
> It says that *if* x is negative or zero then y cannot be other than an
> integer. It does not constrain y for x>0.
>

Yup, you're right! Sloppy reading on my part.

HOWEVER, the library still works for:

pow(9.3, 3.3) = 1570.340134

And, yes, it agrees with my calculator.

There might be a finite probability of an error in the library but we
aren't even close to boundary conditions.

The library does work, it does get the right answer and it doesn't
crash - in my simple tests. Obviously, I have neither the time,
talent or interest to prove it works for ALL cases. But, for simple
examples, it works fine. The code has been around a very long time
and the algorithms even longer.

There is a MUCH higher probability of a user problem.

Richard
Alle 17:55, marted30 ottobre 2007, rtstofer ha scritto:

> You need to look at the ANSI standard definition for pow(x,y) because
> y MUST be an integer and x must be positive.
> http://www.thinkage.ca/english/gcos/expl/c/lib/pow.html

No, this is not correct. I looked with attenction at the code in "The Standard
C Library" by P.J. Plauger before trying the math pow() operation when I
started testing its speed execution.

What the ANSI standard says is: in pow(x,y) if "x" is non-positive AND "y" is
not an integer, "pow" return -HUGE_VAL and sets "errno".

"AND", not "OR".

Only when both the conditions (x < 0) and (y not integer) are true, the
function returns an error. pow(9.2, 3.3) should work.

Why accept a floating point double y argument, if the y argument has to be
integer?

Moreover, I tried compiling the following code in linux with GCC in order to
test the corrispondence of the pow() function with the exp(y*log) function,
and it works:
-------------
int main(void)
{
double x = 10.2, y = 0.2;

do {
printf("%f\n", pow(x, y));
printf("%f\n", exp(y*log(x)));
y++;
} while(y < 11.0);

return 0;
}
-------------

I also tried the pow() function with IAR compiler for ARM, and it works. So
it's not an ANSI standard problem. It's a problem of my code, or of my
compiling/linking options, or of the library, or of the compiler.

Does your hardware executes pow(9.2, 3.3) correctly?
> I really don't think your problem has anything to do with the library.
> I always use a mental test when I come up against this kind of thing.
> What is the probability that I am the only one to discover this
> 'bug'? Even if it is a bug, someone will have already discovered it
> and found a way around. I will never be the first...

This is not always true... I agree in most cases, but if it was so easy there
would be no bugs in the world...
Anyway, I'm not saying that there is a bug in the library: I'm just trying to
understand why my code doesn't work.
--
Fausto Marzoli - 8052.it - http://www.8052.it/
--- In l..., Fausto Marzoli wrote:
>
> Hi all!
>
> I have a problem that I can't fix with GNU ARM Toolchain and math
functions.
> Maybe someone has experimented floating point math function with
GNU ARM
> Toolchain and can help me...
>
> This is the problem: when using floating point arguments, some math
functions
> cause a program crash with "data abort" or "undefined instruction".
>
> I've done some tests with the newlib math functions with float
arguments, GNU
> arm toolchain and ARM7 NXP LPC2106 microcontroller:
> log works
> log10 works
> sqrt works
> tan Error (uncorrect result)
> cos Crash
> sin Crash
> pow Crash
>
> I've tried a lot of pre-compiled toolchains: YAGARTO, Ronetix,
CodeSourcery...
> I also compiled myself the toolchain (under linux): I tried a lot
of
> different compiling options, always with the same results.
>
> I can't fix it. My test program is a simple test program that
blinks a led on
> a development board and in the led delay functions makes a dummy
math call
> (only to test the math call speed).
>
> If someone is interested in this argument, I can give you all the
info about
> compiling options or any other information you need.
>
> Anyone tried floating point math with GNU ARM Toolchain (arm-elf)
and newlib?

They work OK with CrossWorks, which uses gcc.

Leon