AnsweredAssumed Answered

A workaround for the AC6 gcc libe float/double printf/sprintf fault

Question asked by Kent Swan on Apr 22, 2018

From: Kent Swan,  White Bird Engineering, Inc.

 

The current STM32 workbench (eg AC6) has a well known (by now) standard library support which will cause a fault when attempting to convert float or double to string via sprintf or printf.   I've got the latest workbench installed coupled to CubeMx version 4.23 with a STM32L462 selected which implements hardware floating point and have been generally pretty happy with everything except for the above issue.   I really wish this was fixed!

 

Poking around on the internet I found some (flawed) code which kind of performed the conversions which didn't handle negative values thus only supported positive floats which was marginally useful.    I've worked through and corrected the code and have created two routines which perform the required conversion properly one for float (ftoa) and one for double (fdtoa) with the ability to handle signed input and control of how many digits are printed after the decimal point (from 0 to n). 

 

Please note that the maximum usable decimal digits for float is 6 and for double is 15.  This means if you have very large numbers then the fractional part beyond the above digits limit will be toast.  See the attached C and H files.

 

A snippet of my validation code follows.  The test code resides within a task and the output is echoed to a virtual serial terminal on a com port using the USB CDC implemented by STM32 CubeMx.

 

case 31:    // test float print
    {
    static char    tmpStr[16];
    static char outStr[256];
    float    fx[]=
            {0.0
            ,1.0
            ,-1.0
            ,1.234567890
            ,12.34567890
            ,123.4567890
            ,1234.567890
            };
    int i;
    int cnt = (sizeof(fx)/sizeof(float));
    for(i=0;i<cnt;i++)
        {
        ftoa(tmpStr, fx[i], 0);
        sprintf(outStr,"%s\r\n", tmpStr);
        ftoa(tmpStr, fx[i], 1);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        ftoa(tmpStr, fx[i], 2);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        ftoa(tmpStr, fx[i], 4);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        ftoa(tmpStr, fx[i], 6);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        ftoa(tmpStr, fx[i], 8);
        osDelay(1);
        APP_USB_Send_FS((uint8_t*)outStr, strlen(outStr));
        }
    }
    break;

 

case 33:    // test double print
    {
    static char    tmpStr[16];
    static char outStr[512];
    double    fd[]=
            {0.0
            ,1.0
            ,-1.0
            ,1.2345678901234567890
            ,12.345678901234567890
            ,123.45678901234567890
            ,1234.5678901234567890
            ,12345.678901234567890
            ,1234567.8901234567890
            ,12345678.901234567890
            ,123456789.01234567890
            ,1234567890.1234567890
            ,12345678901.234567890
            ,123456789012.34567890
            ,1234567890123.4567890
            ,12345678901234.567890
            };
    int i;
    int cnt = (sizeof(fd)/sizeof(double));
    APP_USB_Send_FS((uint8_t*)"***\r\n", 5);
    for(i=0;i<cnt;i++)
        {
        memset(outStr,0x00,sizeof(outStr));
        fdtoa(tmpStr, fd[i], 0);
        sprintf(outStr,"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 1);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 2);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 4);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 6);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 8);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 10);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 12);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);
        fdtoa(tmpStr, fd[i], 14);
        sprintf(&outStr[strlen(outStr)],"%s\r\n", tmpStr);

 

        APP_USB_Send_FS((uint8_t*)outStr, strlen(outStr));
        osDelay(1);
        }
    }
    break;

 

Enjoy.

Attachments

Outcomes