This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294KCPDT: Floating point issue when sprintf

Part Number: TM4C1294KCPDT


Hi,,

I wan to send a string data to ethernet, I am facing issue with sprintf function when casting float values as below.

float rffth =12.523;

char thbuffer[10];

sprintf(thbuffer,"%0.2f",rffth);

sprintf crashes application. I have crosschecked include library requirements also. in integer or string it works.

I am using CCS v9.1  and TI RTOS v:- 2.16.1.14

Please help

Regards

Khodidas Domadiya

Embedded Engineer

  • sprintf crashes application. I have crosschecked include library requirements also.

    Formatting floating point values probably requires more stack space than formatting integer or string values.

    Is the problematic sprintf call from a TI-RTOS task or from main()?

    What stack size is being used?

  • Oddly seeing the same issue this week crashing too (%u) non-OS fprint() via interrupt vector. Yet printing the decimal value seems to work.  You can see the floating point decimal equiv in CCS debug. Trying to print the decimal point %c'.' crashes too. Some odd floating char conversion takes place for the %i or %d .

  • Hi,

      Did Chester resolve your question? Did you increase the stack? With enough stack allocated (e.g. 1536) , I have no problem with the sprintf. Note I create a simple program by pasting your code. See the value stored in thbuffer. 

  • Hi Charles,

    What was your printf() format character after the % sign? The posters code does not have format argument added after % sign, rather at the end. Also assuming C++ printf() spin off RTOS System_printf() and UARTprintf(). Oddly sprintf() is not covered in my C++ coding document. I been using UARTprintf() so that may be why it hard faults Nmi for (single precision floats) using various format characters. I don't believe the FPU IEEE supports double precision (f) nor does project runtime support (rtsv7M4_T_le_v4SPD16_eabi.lib) 

    3.1.5 Floating-Point Unit (FPU)
    This section describes the Floating-Point Unit (FPU) and the registers it uses. The FPU provides:
    ■ 32-bit instructions for single-precision (C float) data-processing operations

    TABLE 7-1. BASIC PRINTF CONVERSIONS

    f double;[-1m.dddddd, where the number of d's is given by the precision (default 6).


    e,E double;[-1m.dddddde±xx or [-1m.ddddddE±XX, where thenumber of d's is given by the precision (default 6).


    g,G double;use %e or %E if the exponent is less than -4 or greater than or equal to the precision; otherwise use %f. Trailing zeros and a trailing decimal point are not printed.

  • The various standard functions like sprintf() are compiled into a library called libc.a.

    If you dig around, you'll find the sources for the library are in a directory like C:\ti\ccs1030\ccs\tools\compiler\ti-cgt-arm_20.2.5.LTS\lib\src.

    And if you dig further you'll see that sprintf() calls printf() which ultimately gets implemented in the file _printfi.c.

    And in that file you'll find that the function fcvt() is used for the floating-point conversions.

    That function (among others) is gated on and off with some macros like NOFLOAT and MINIMAL. If neither of those macros are defined, then processing for floating-point conversions is built into the library. If they are defined, then floating-point support is omitted.

    And it looks like the particular version of libc.a you are using does not have floating-point support enabled, hence the crash in sprintf().

    Here's the billion-dollar question: how the hell is anyone supposed to know what support is built into this library? The Makefile and everything is completely inscrutable.

    At least the simple implementation of usprintf() in the TivaWare library ustdlib.c is clearly documented and explicit about what format specifiers are supported: Spoiler: not the floating point.

  • If you dig around, you'll find the sources for the library are in a directory like C:\ti\ccs1030\ccs\tools\compiler\ti-cgt-arm_20.2.5.LTS\lib\src.

    Don't normally add that path to our CCS projects. Yet project general tab auto added ~18.12.4.LTS/include/libcxx which omits both sprintf() and printf(). Adding { ${CG_TOOL_ROOT}/lib/libc.a } to C++ general libraries tab, code check does not scan index for lib.ca functions, so the directive sprintf(), printf() functions are not supported.  

    Point being these older C++ printing functions are skirted perhaps for good reason. IEEE 754 standard seems to predate C99 addendum, where suffix (f) denotes single precision FPU operations. Yet the compiler asserts double precision FPU operations for (suffix(f)) thereby setting FPSCR flag true and Nmi hard fault exception is immediately triggered.  

  • BTW: Adding #include <stdio.h> does not configure a UART peripheral for spfintf() and the CCS console is occupied by CDT builds. We must use UARTprintf() or some other function that has a UART output to buffer connection or our own UART driver to virtual COM.  Seems sprintf() and printf() data streams are ported to sdio.dll drivers for Visual Studio IDE consoles and MSBasic debug run times. I haven't been inside Windows debug Basic for a decade now, almost forget how to get in there from cmd prompt

  • Here's the billion-dollar question: how the hell is anyone supposed to know what support is built into this library? The Makefile and everything is completely inscrutable.

    From the ARM Optimizing C/C++ Compiler v20.2.0.LTS User's Guide :

    I.e. the library should get built with all options, and the -printf_support option tells the linker to select the appropriate support.

    And it looks like the particular version of libc.a you are using does not have floating-point support enabled, hence the crash in sprintf().

    With ti-cgt-arm_20.2.0.LTS used the following code:

    #include <stdio.h>
    
    /**
     * main.c
     */
    int main(void)
    {
        float rffth =12.523;
    
        char thbuffer[10];
    
        sprintf(thbuffer,"%0.2f",rffth);
    
    	return 0;
    }

    And in the CCS project options under CCS Build -> ARM Compiler -> Advanced Options -> Language Options set "Level of printf/scanf support required (-printf_support)" to nofloat.

    That resulted in a compile error:

    Building file: "../main.c"
    Invoking: ARM Compiler
    "/home/mr_halfword/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 -me --include_path="/home/mr_halfword/workspace_v10/TM4C1294KCPDT_float_printf" --include_path="/home/mr_halfword/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/include" --define=ccs="ccs" --define=PART_TM4C1294KCPDT -g --gcc --printf_support=nofloat --diag_warning=225 --diag_wrap=off --display_error_number --verbose_diagnostics --abi=eabi --preproc_with_compile --preproc_dependency="main.d_raw"  "../main.c"
     
    >> Compilation failure
    subdir_rules.mk:7: recipe for target 'main.obj' failed
    "../main.c", line 14: error #2632: Conversion f not allowed in printf_support=nofloat mode
          sprintf(thbuffer,"%0.2f",rffth);
                                        ^
     
    1 error detected in the compilation of "../main.c".
    I.e. provided you use constant format strings, the compiler should trap use of an unsupported option.

  • And in the CCS project options under CCS Build -> ARM Compiler -> Advanced Options -> Language Options set "Level of printf/scanf support required (-printf_support)" to nofloat.

    AHA! Thank you. This is very much appreciated.

    I just checked a project I recently finished. Two things.

    One, libc.a is included as a library in the linker settings

    Two, in Language Options, "Level of printf/scanf support required (--printf_support)" was set to "full."

    The project was created from one of the templates, so these settings were inherited from the examples.

    The thing is, I was using the usprintf() provided in the TivaWare ustdlib.c library, and that function doesn't support floating-point operations. I did so because all of the examples used usprintf() in favor of sprintf(). The project uses the Kentec graphic LCD to display temperature and humidity readings from one of the sensor boards. Those readings are floats (after scaling), and since usprintf() doesn't support float, I ended up writing a little function that "cracks" a float into its integer and fractional parts, each of which are represented by uint32_t.

    Time to update that project and get rid of usprintf() and just use the sprintf()! I learned something today!

  • Hi,

    This project options are not there in TI -RTOS based application, if any other options or something else is needed to do the sprintf, as i need it to send to ethernet as a string format in my application. 

  • Hi,

      Here is a small program to store the floating point value to a string using sprintf and later print out using both UARTprintf and printf.

    #include <stdint.h>
    #include <stdio.h>
    #include <stdbool.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/gpio.h"
    #include "drivers/pinout.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable the GPIO Peripheral used by the UART.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Configure GPIO Pins for UART mode.
        //
        ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
        ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000); // Default 16Mhz SYSCLK using PIOSC
    }
    
    
    //*****************************************************************************
    //
    // Print "Hello World!" to the UART on the Intelligent UART Module.
    //
    //*****************************************************************************
    int
    main(void)
    {
    	float rffth =12.523;
    	int abc = 123;
    
    	char thbuffer[10];
    
    	sprintf(thbuffer,"%0.2f",rffth);
    
        ConfigureUART();
    
        UARTprintf("Using UARTprintf\n");
        UARTprintf("rffth is %s\n", thbuffer);
    
        printf("Using printf\n");
        printf("rffth is %s\n", thbuffer);
    
    
    	while (1);
    
    }
    

  • RTOS System_printf()
    as i need it to send to ethernet as a string format in my application. 

    You may need to add #include <streams.h> to route printf() strings into the ring buffer for Ethernet TXD transport? How is printf() even with streams.h to know the console port is to use CCS IDE? I tried to get printf() to work years ago even with CCS forum help it was not possible at that time. The RTOS System_print() outputs to the Debug message console as I recall.

    BTW: This works to simulate a decimal point for floating point values, UARTprinf("MyPointer->0.%i\n", VarOutput)

  • will test and revert soon