# Forum: ARM programming with GCC/GNU tools Newlib recompilation -> Support float with printf

Rate this post
 0 ▲ useful ▼ not useful
Hello all

Following my previous thread where I was surprised to not be able to
convert float  to string via printf(), i m looking to recompile the
newib (1.16.0) to add this functionality.

My question is: How do that ...

I read the web page suggested by Clifford Slocombe (Thanks to him for
all his precious informations) http://venus.billgatliff.com/node/3

This compilation must be done under Linux (or maybe on Windows with the
use of Cygwin, but i m not comfortable with it... I installed a OpenSUSE
11)... But i have some problem during the configuration / compilation of
newlib

1st : I m looking to regenerate a newlib for Arm (STR912, ARM9) and for
Yagarto. In this case, the target used for the configuration is :

--target=arm-elf

Is it Right ? (I used the following line to configure :
damien@linux-8urm:~/NewLibBuild> ../newlib-1.16.0/configure
--target=arm-elf --prefix=pwd)

Now, when i try to compile, i receive (after 3-4 page of script dump)

-----------------------------------------8<-----------------------------
------
make[5]: *** [lib_a-dummy.o] Error 127
make[5]: Leaving directory
/home/damien/NewLibBuild/arm-elf/newlib/libc/argz'
make[4]: *** [all-recursive] Error 1
make[4]: Leaving directory
/home/damien/NewLibBuild/arm-elf/newlib/libc'
make[3]: *** [all-recursive] Error 1
make[3]: Leaving directory /home/damien/NewLibBuild/arm-elf/newlib'
make[2]: *** [all] Error 2
make[2]: Leaving directory /home/damien/NewLibBuild/arm-elf/newlib'
make[1]: *** [all-target-newlib] Error 2
make[1]: Leaving directory /home/damien/NewLibBuild'
make: *** [all] Error 2
--------------Look attached file for more
details------------------------

I m little bit surprised, for 2 reasons :

1) I was fairly sure the GCC version (i mean the linux default
version) was able to compile for a huge range of target (including
ARM)), in this case, why it's necessary to look for another toolchain
(arm-elf-*) ?
If this toolchain is required, where i could find a binary
(I found a arm-elf-gcc binary, but seems not be able to be executed on
my x86 station -> maybe an ARM exec)?

2) What is arm-elf-cc, this arm-elf-cc file seems never included in
toolchain

Regards.

Damien

Rate this post
 0 ▲ useful ▼ not useful
First try to find you if your toolchain's newlib is configured eith
float-io disabled. If it is not the problem might be somehwere else and
there is no need to rebuild the newlib.

> 1) I was fairly sure the GCC version (i mean the linux default
> version) was able to compile for a huge range of target (including
> ARM)), in this case, why it's necessary to look for another toolchain
> (arm-elf-*) ?
The "default" toolchain should be a "native" (not cross) toolchain to
build software for the same system it is running on. So far I have not
seen a Linux distribution where a default toolchain package is
"multi-target".

> If this toolchain is required, where i could find a binary
> (I found a arm-elf-gcc binary, but seems not be able to be executed on
> my x86 station -> maybe an ARM exec)?

It's not very difficult to build a complete toolchain yourself on Linux
systems. See for example:
- http://openhardware.net/Embedded_ARM/Toolchain/ (remove the
newlib-config-option --disable-newlib-io-float to keep floating-point
support for printf et al.)
- http://www.gnuarm.org/support.html
- search for crosstool
- IRC there is an instruction to build an ARM toolchain from a user
Bingo on avrfreaks.net He has also published instructions to build an
AVR toolchain, so take care to get the right instructions.

available from codesourcery.com:
http://www.codesourcery.com/gnu_toolchains/arm/portal/package2553?@template=release

cross toolchain. Maybe someone already prepared a cross-toolchain.

> 2) What is arm-elf-cc, this arm-elf-cc file seems never included in
> toolchain
instructions above or use a ready made cross-toolchain.

Rate this post
 0 ▲ useful ▼ not useful
I have sucessfully compiled newlib on Windows. You do not need Cygwin or
Linux to do that. I cannot remember exactly how I did it, but I may have
used MinGW's MSYS shell. This is a minimal bash-like shell that is often
sufficient to run a configure script. Once the make file was genereated
I was able to perform the build from the normal Windows command line.

However, in my case I think I did not even to that. I only needed one
configuration - for VFP support - and that was not part of the standard
build in any case, so I simply took te source and generated a suitable
makefile (probably using Dev-C++ to generate the basic make, then
modifying it by hand). It is not a complex build.

If you run it on Windows, you will ensure that the library is built with
the same compiler (Yagarto in your case) you are ultimately going to be
using (unless you are so enamoured with Linux you are going to stick
with it!). I think perhaps you might have come here first, installing
Linux just for that seems somewhat dreastic. And even on Linux, you
still need a cross-compiler - its not magic! Bill Gatliff shows you how
to do that too: http://venus.billgatliff.com/node/18

All that said, I think you are doing this the (very) hard way. I am not
sure why you are rebuilding newlib for floating point support rather
than using an existing build that already supports it. As I said
previously WinARM's build of Newlib already supports it. Even if you
continue to use Yagarto, I am pretty sure that Martin's Newlib build
will work with it directly.

Also since it is likely that you only need floating point display in a
few, why could you not simply implement a float to string function that
does just what you need, and then use %s to output it? That would
probably end up smaller that burdoning stdio with floating point support
- unless you made it as flexible as printf, which you probably don't
need.

For example:

char* ftostr( char* buffer, float value, int places )
{
int whole ;
int fraction ;
char sign[2] = "" ;

if( value < 0 )
{
value = -value ;
sign[0] = '-' ;
sign[1] = '\0' ;
}

whole = (int)value ;
fraction = (int)((value - whole) * pow(10.0f,places) + 0.5f) ;
sprintf( buffer, "%s%d.%*.*d", sign, whole, places, places, fraction
) ;

return buffer ;
}

Usage example:

float as = 80.027f;
char buf[23] ;
printf( "%s", ftostr( buf, as, 2  ) ) ;

diaplays: 80.03

If you application is single threaded, you can make the buffer static to
reduce the stack requirement, but you need to make the buffer large
enough for all possible values (not a bad idea in any case, the above is
by no means 'safe' code. That's 10 digits for each int, plus the
decimal, a possible -ve sign, and the nul termionator. E.g:

char* ftostr( float value, int places )
{
static buffer[23] ;
int whole ;
int fraction ;
char sign[2] = "" ;

if( value < 0 )
{
value = -value ;
sign[0] = '-' ;
sign[1] = '\0' ;
}

whole = (int)value ;
fraction = (int)((value - whole) * pow(10.0f,places) + 0.5f) ;
sprintf( buffer, "%s%d.%*.*d", sign, whole, places, places, fraction
) ;

return buffer ;
}

Rate this post
 0 ▲ useful ▼ not useful
Clifford Slocombe wrote:
>     fraction = (int)((value - whole) * pow(10.0f,places) + 0.5f) ;

A minor correction:

fraction = (int)((value - whole) * powf(10.0f,places) + 0.5f) ;

To force the use of the float rather than double version of pow() which
is a little faster. If you use C++ compilatin and include <cmath> it
does not matter since pow() is overloaded for all fp types in any case.

I implemented it for float rather than double because %f was the format
specifier you were using in your original post, and because double
precision manipulation is significantly slower on a 32bit integer
processor than float. Not the use of the f suffix on all the constants
to enforce single procision. You should do that in your own code to
ensure maximum efficiency.

Also even if you are using double precision for calculations, it is
unlikely that you will want to display so many decimal places that you
need it for display, so casting a double to a float when calling this
function may be adequate.`

• $formula (LaTeX syntax)$