Vasile Guta_Ciucur

How to activate floating point for sprintf in your project

Discussion created by Vasile Guta_Ciucur on Nov 3, 2017

I'm using the gcc-arm-none-eabi-6-2017-q2-update toolchain for Linux 64bit downloaded from the ARM site and it doesn't come with floating point compiled. At least, it is not included in the Makefiles generated by the STM32CubeMX for Low Layer driver (Nucleo-L152RE board).


Well, the real reason for this is that the project use newlib-nano, which in turn has a default optimized printf/scanf implementation that gets rid of floats and other less needed cruft. As a side-effect it also reduces the RAM foot print substantially by using less memory for impure data. @GrumpyOldPizza, from Arduino for STM32 forums.



What I needed it for? I bought a LUX sensor, MAX44009 (0.045 Lux to 188,000 Lux Range) which provide a precision of 3 decimals. So I had this code that showed nothing (with a serial communication function that I omitted to show it here):


lux = (float)((pow(2,(float)exponent) * (float)mant) * 0.045);
sprintf(t32_buff, "%10.3f", lux);


I got just blank space on the serial terminal, not even zeros. I searched on community and then on Internet and found out how to activate the floating point for my project.


1. In the Makefile generated by CubeMX, search for the following comment/line:

# float-abi

 ... and add the following line bellow it:

FLOAT-ABI = -mfloat-abi=soft


2. Go down in the file until you find the LDFLAGS variable and edit the line by inserting the following string (maybe just after $(LIBS)  ):

-u _printf_float

Now my LDFLAGS line looks like this one:

LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -u _printf_float -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections


3. Save the Makefile file, clean and build your project

make clean

then upload the code on your board. Now you should see the floating point numbers flowing on your terminal or LCD. Before this, I thought I messed up the i2c functions again, or that the pins are not soldered correctly on the sensor's board.




In the end, I think I will display LUX values as 32bit unsigned integers but now I know how to display floating point numbers with sprintf . In this case, we are still using float for calculations, but with sprintf without floating point support, as is provided in nano library. So, considering the steps above, you will execute only the step one and three, omitting the step two, and the code will look like this:

lux = (float) ((pow(2, (float) exponent) * (float) mant) * 0.045);
lux = lux * 1000; // because we have three decimals...
sprintf(t32_buff, "%u.%03u", (uint32_t)lux/1000, (uint32_t)lux%1000);

The economy regarding code size, is a difference around 6Kb of code...



BTW, if you didn't knew, this is how you do it in Atollic TrueStudio IDE Activating the floating point support for sprintf in Atollic