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.

CCS/EK-TM4C1294XL: ltoa() radix missing

Guru 55913 points
Part Number: EK-TM4C1294XL

Tool/software: Code Composer Studio

It would seem the conversion of a long 32 bit integer somehow omits the ones place holder decimal 0-9 ASCII.  So the results are not as expected when decoding base 10 radix into ASCII values. The results of ASCII conversion are close via output two 8 bit array stores but not exact and often can result in 0-255 being decoded across one, tens, hundreds positions via output of 3 array stores.

Is there some reason CCS compiler 18.12.2.LTS omits radix? What other function can be used to do inline conversions of long integers into ASCII and mirror integers into decimal values? CCS ltoa() seems to work accurately for shorts with 3 output buffers but fails to produces exact conversion for longs in either buffer case. It seems there is something wrong since the 1's decimal position often ends up being 4 or 5 yet 10's, 100's roll decimals 0-9 as expected from a long integer variable. The control in this experiment a high speed GUI that TI developed some time ago and GUI composer number spinner widgets without integer conversion to ASCII.

http://www.kev.pulo.com.au/pp/RESOURCES/cplusplus/ref/cstdlib/ltoa.html

  • Please understand the function ltoa is not required by the C standards.  That the TI RTS library supplies ltoa anyway is happenstance.  Future releases of the compiler may not include ltoa.  This change may occur at any time with no notice.  For this reason, you should find another way to solve your problem, or write your own implementation of ltoa.

    BP101 said:
    It would seem the conversion of a long 32 bit integer somehow omits the ones place holder decimal 0-9 ASCII

    Please supply an example of this behavior.  Show the input, the output, and the expected output.  All in precise detail.

    For the other similar complaints about ltoa behavior, please supply an example.

    BP101 said:
    Is there some reason CCS compiler 18.12.2.LTS omits radix?

    I don't know.  There is no published standard for how ltoa should work.  I suspect most implementations only support decimal, and we probably followed that common convention.

    Thanks and regards,

    -George

  • George Mock said:
    Please supply an example of this behavior.  Show the input, the output, and the expected output.  All in precise detail.

    usprintf() seems to have the very same odd behavior via the UART porting code listed near the end in the related question thread. I really do not think it should be this difficult to convert integers 0-9 to ASCII if the compiler is working correctly to port the data into the correct bit locations. It seems to me the Thumb instructions are not correct in either case and fail profusely to do simple byte porting via any TI library calls from an C+ array!

    So I was able to get 0-9 to output in the 1's position by multiplying ones place integer x 10 but not when the integer rolls from 99 to 100, the ones position stops counting at decimal 4 or 5. The odd part being this issue occurs in the low order byte (7:0) 0-255 and the final conversion value is off by a few decimal counts via two UART array[0], array[1] as previously documented and explained. The ltoa() uspritnf() integer values are more correct via 3 array cells but produce bazar decimal values in the code below.

    /* Set 123Number boxes sizeof and output integers as ASCII in each decimal position */
    if((uint16_t)g_ulMeasuredSpeed * 10 < 10000)
    {/* Set 123Number decimal length to 1's place */
      while(!(NexSendCmd("taco.lenth=1", 0, 0, 0)));
      while(!(NexSendCmd("taco.val=", (uint16_t)g_ulMeasuredSpeed * 10,  0, 0)));
    }
    if((uint16_t)g_ulMeasuredSpeed / 10)  // >= 100)
    {/* Set 123Number decimal length to 10's place */
      while(!(NexSendCmd("taco.lenth=2", 0, 0, 0)));
      while(!(NexSendCmd("taco.val=", (uint16_t)g_ulMeasuredSpeed, 0, 0))); 
    }
    if((uint16_t)g_ulMeasuredSpeed / 100) //>= 1000)
    {/* Set 123Number decimal length 100's place */
      while(!(NexSendCmd("taco.lenth=3", 0, 0, 0)));
      while(!(NexSendCmd("taco.val=", (uint16_t)g_ulMeasuredSpeed / 10, 0, 0)));
    }
    if((uint16_t)g_ulMeasuredSpeed / 1000) // >= 10000)
    {/* Set 123Number decimal length 1000's place */
      while(!(NexSendCmd("taco.lenth=4", 0, 0, 0)));
      while(!(NexSendCmd("taco.val=", (uint16_t)g_ulMeasuredSpeed / 100, 0, 0)));
    }

    It would seem to me the output of ASCII on a TI UART should be easy to port high speed integers as ASCII via built in functions. Oddly omitting ltoa() and simply subtracting 0x30 from any input *array integer <10 produces other than decimal 0-9 ASCII in the transmit UART array loop! It seems to me the functionality of char output has not been fully tested with TI UART other than by massive array buffering of TX data via UARTPrintf(). In the TM4C1294 MCU the buffer pointer is known to be corrupted from an Rx race condition and our TX code is running between 14-16KCPS error free!

    George Mock said:
    I don't know.  There is no published standard for how ltoa should work.  I suspect most implementations only support decimal, and we probably followed that common convention.

    I added the (int _radix) to ltoa() and made the input (Int) short but it made no difference to the seemingly embedded C++ ltoa() class inside the MCU. The latoa() call does not seem to exist in CCS compiler as a function, only a pointer is revealed. The radix can be other values other than 10 depending on the conversion type.

  • Capture edited log of above count conversion from decimal 1-458 or some part of that count anyway.

    Notice there are values in the count not considered part of the ASCII code set spit out by ltoa(), after integer division all cases. Seems integer to string conversion ltoa() and usprintf() do not always produce 0-9 decimal relative to the ASCII code set.

     How are MCU variables without any conversion displaying and counting monotonically only in GUI Composer number spinner boxes? It seems there is some kind of masking inside which works only for TI related integer objects. Oddly GUI composer number spinners work well with very same integer division shown above which links a symbolic name to address inside JTAG domain.   

    /cfs-file/__key/communityserver-discussions-components-files/81/Taco1.txt

    Edit: These number spinners ignore values outside the ASCII code set, no output display of value. Notice there are 3 bytes when only two array[] cells via UART output. So strlen() determines without added trim passed the uint16_t converted long integers mostly in 3 byte bursts. Short integers in no way overflows ltoa() so all the application variables are exceeding constraints and this is considered good programming in C++? Don't ever recall encountering integer issues like this coding in Macro editor via machine language. 

  • The 3rd party serial product documents makes false claim that all instructions and parameters are to be sent in ASCII code.

     However MCU variable parameters are converted integer strings via ltoa() sent via serial transport to GUI number boxes as RAW string values, not ASCII. Yet the text boxes show the integer values are outside the ASCII code set when 3 array cells are used to port the full variable via UART transport.

    Hence some confusion for lack of proper detail in 3rd party documentation relative to specific widgets. The number boxes are not dynamic length relative variable string data length. So we have to send a command to set the number box length each time since automatic length produces bazar decimal display from divided integers simple counting (0 - 20000). This example above is the same method for porting (All) application variables making most difficult to mirror decimal values from integer conversion sent to 3rd party number boxes. 

  • The first sentence in your first post says ...

    BP101 said:
    It would seem the conversion of a long 32 bit integer somehow omits the ones place holder decimal 0-9 ASCII.

    I asked for a detailed example which demonstrates this behavior.  I do not see that example in your other posts.  Until I get that example, I am unable to help you.

    Thanks and regards,

    -George

  • Geoge,

    You must be ignoring the posted code in the web based forum (Not email), the provided example UART array[0/1] output causing the issue. You don't need to run the code only inspect the syntax or load it with some other long variables. It don't freaking work correctly no matter how the integer is loaded into or pulled from the array storage. How is it the customers role to ensure proper binary math indirect memory addressing is functional in compilers output? I have done my part to point out this code example ain't working as it is expected to. One or more Thumb instructions appear to be incorrectly loading input bytes into SRAM via the array storage. 

    That said:

    The strlen(varin) is the culprit for 3 bytes to be output in the UART code loop, Taco1.txt. It would seem it is not compatible with short or long integers, adds a third phantom byte 53 from outer space. Replacing it with sizeof(varin) stopped the phantom byte but did not correct the missing 1's place in the 100' count space as counts roll from 99 to 100,101,102 is always 104-194, 204-294 or ~195, ~295 etc. Unsigned long integers only count correctly in TI GUI's do not in 3rd party number widgets. All the variable values are off by a few or several counts so the integers are missing bits when being converted to strings!

  • Posting an example of TI C++ flawed logic is not the desired outcome anyone would seek.

    Presenting short example code would require removing the UART which is part of the dis-functional output logic path to begin with.

    Clearly the SRAM pointers into the array are not exactly following the integer conversion 20 byte buffer built into ltoa().

    Most documents suggest the integer buffer is supposed to be external, not built into the ltoa() function as it has been designed. The integer pointer is an external pass in so the literal integer input array pointer is seemingly being fragmented via the 20 byte internal buffer when a UART exists inline.

  • Code itoa() below produces similar issue with inline integer conversion to strings. Oddly the swap does not reverse the string order passing it to the UART backwards. Yet very same and incorrect values as ltoa() occur. The char array pointer seems to be one possible cause as often one string may have another strings same last 2 digits, 4 total.  Inline integer conversions into char strings fail to produce correct values for reasons beyond my pay grade, 0$

    Smells like a dirty Thumb instruction or back to back writes of UARTDR REG1 has an undocumented errata.   

    /********************************************************
    *
    *! swap: interchange v[i] and v[j]
    *
    ********************************************************/
    void swap(char start, char end)
    {
    	//static char v;
    	static char z;
    
    	z = start;
    	start = end;
    	end = z;
    }
    
    /********************************************************
    *
    *! A utility function to reverse a string and remove NULL
    *
    *********************************************************/
    void reverse(char *str, int length)
    {
    	int start = 0;
        int end = length -1;
    
        while(start < end)
        {
            swap(*(str+start), *(str+end));
            start++;
            end--;
        }
    }
    
    /*****************************************************
    *
    *! Implementation of itoa()
    *
    * b\return converted character string
    *
    *****************************************************/
    char*
    itoa(int num, char* str, int base)
    {
        int i = 0;
        bool isNegative = false;
    
        /* Handle 0 explicitely, otherwise empty string is printed for 0 */
        if (num == 0)
        {
            str[i++] = '0';
            str[i] = '\0';
            return str;
        }
    
        // In standard itoa(), negative numbers are handled only with
        // base 10. Otherwise numbers are considered unsigned.
        if (num < 0 && base == 10)
        {
            isNegative = true;
            num = -num;
        }
    
        // Process individual digits
        while (num != 0)
        {
            int rem = num % base;
            str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
            num = num/base;
        }
    
        // If number is negative, append '-'
        if (isNegative)
        {
            str[i++] = '-';
        }
    
        // Append string terminator
        str[i] = '\0';
    
        // Reverse the string
        reverse(str, i);
    
        return str;
    }

  • George Mock said:
    That the TI RTS library supplies ltoa anyway is happenstance.  Future releases of the compiler may not include ltoa.

    Good enough reason to stop using TI MCU's since there is no way to otherwise correctly port high speed integers as strings via C++ or uartsdio.c. The entire reason for embedded MCU C++ language was to simplify & reduce coding hours versus older machine code. Machine code works so why not have an integer to string conversion based on Thumb2 instructions written in assembler? Call it tiota() - lol.

    There should be no reason to require flushing of FIFO during high speed data output, array pointers should remain consistent up to 2 gighertz CPU clock rate. Perhaps TI can ask Arduino guys how they are able to port high speed integers as strings via UART port. 

     Seemingly (uartstdio,c) masks UARTDR register1 issues, UARTprintf() includes a large TX buffer, flushing often in example applications.      

  • Dysfunctional long to short integer division is the compilers failure to correctly divide integers even via (float) added in front of the long integer converted to (float) prior to division. Issue occurs with relaxed FPv4SPD16  project setting and Tivaware calls in project shown below. The integer division shown above post does not produce correct 0-9 counts in 10's 100's 1000's places. We see this with an RTC counts in seconds being divided for serial output result in truncation of rolling counts 0-9 as previously described.

    These are all long integers converted inline either via (float) or (uint16_t) prior to array pointer assignment via ltoa(), posted or internal (libc.a) latoa(). The bigger an short or float integer division, e.g. >10, >100, >1000 far less output precision results or in some cases no results at all in the case of speed counts posted above. How does one make an example to show integer truncation? That is an undesired result of compiler interpretation Thumb instruction generation in the C++ language converting long to short characters or floating decimal in some cases. Integer truncation occurs during conversion in this higher compiler versions, 18.12.2.LTS..

    https://softwareengineering.stackexchange.com/questions/307993/why-does-integer-division-result-in-an-integer

    	 /* Enable NVIC Floating Point Unit, FPU */
    	 MAP_FPUEnable();
    
    	 /* Floating-point state is not saved on interrupt entry */
    	 MAP_FPULazyStackingEnable();