LP-MSPM0C1104: how to use UART to print float number ?

Part Number: LP-MSPM0C1104
Other Parts Discussed in Thread: MSPM0C1104, MSPM0L1306

Tool/software:

i download the example of uart_rw_multibyte_fifo_poll_LP_MSPM0C1104_nortos_ticlang

can print at UART with 4 words, "MSP!"

and if i have a float variable,

is there any way i can print at UART?

just like below code.

include <stdio.h>
int main(){
    uint8_t correct_word[4] = {'M', 'S', 'P', '!'};
    DL_UART_Main_fillTXFIFO(UART_0_INST, &correct_word[0], 4);
    while (DL_UART_Main_isBusy(UART_0_INST))
        ;
    // previous is work correctly, show the "MSP!" correct
    // below will be compile ok, but nothing show at UART.
    
    float tmp =23.6f;
    char buffer[50]={0};
    sprintf(buffer, "%4.1f", tmp);
    
    
    DL_UART_Main_fillTXFIFO(UART_0_INST, &buffer[0], 4);
    while (DL_UART_Main_isBusy(UART_0_INST))
        ;
}

as i know, maybe i need something like FTOA function or need compile with float support or else,

is there any hints can provide to me?

  • Hi CK,

    I would suggest looking over this article and seeing if it helps with your implementation: https://software-dl.ti.com/ccs/esd/documents/sdto_cgt_tips_for_using_printf.html

    Best,

    Owen

  • hi, Owen, 

    i just read the article, 

    and i retry some different ways,

    #include "ti_msp_dl_config.h"
    #include <stdio.h>
    
    #define ENABLE_LOOPBACK_MODE true
    #define UART_PACKET_SIZE (4)
    
    #define UART_TX_DELAY (160000)
    
    uint8_t txPacket[UART_PACKET_SIZE] = {'M', 'S', 'P', '!'};
    
    int main(void)
    {
        char buffer[50]={0};
        int a = 33;
        sprintf(buffer,"%d",a);
        DL_UART_Main_fillTXFIFO(UART_0_INST, &buffer[0], UART_PACKET_SIZE);
    
        /* Wait until all bytes have been transmitted and the TX FIFO is empty */
        while (DL_UART_Main_isBusy(UART_0_INST))
            ;
    
    //previous code works correctly, will show "33" at UART.
    //below code will stuck at sprintf(buffer, "%4.1f", tmp); no response,
    
    
        float tmp =23.6f;
        buffer[0]=0;
    
        /* Optional delay to ensure UART TX is idle before starting transmission */
        delay_cycles(UART_TX_DELAY);
        sprintf(buffer, "%4.1f", tmp);
        /* Set LED to indicate start of transfer */
        DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
    
        /* Fills TX FIFO with data and transmits the data */
        DL_UART_Main_fillTXFIFO(UART_0_INST, &buffer[0], UART_PACKET_SIZE);
    
        /* Wait until all bytes have been transmitted and the TX FIFO is empty */
        while (DL_UART_Main_isBusy(UART_0_INST))
            ;
    }

    i think what i fail is sprintf not support "change float to char".

    is there any ways can make it , or just not try to coding like this ? 

    i just read another link have almost the same issue,

    MSPM0C1106: How to enable the floating point printf(); function output with Keil

    but i read the link and not find  C1104 can sprintf float to character or not.

    (or just not support ? )

  • Hi CK,

    I tried implementing what you had provided and I came up with a workaround. The reason why it isn't working for you is most likely because of memory constraints on the MSPM0C1104. In the document I had sent you, it suggested allocating 400 bytes for the stack and about 512-1024 bytes for the heap. Overall, just one printf using float can take thousands of bytes. This E2E is for an MSP430, but is still relevant for this scenario.

    Here is the workaround I came up with:

    float tmp =23.6f;
    int int_part = (int)tmp;
    int frac_part = (int)((tmp - int_part) * 100);
    sprintf(buffer, "%d.%02d", int_part, frac_part);

    This avoids the need for true floating point, but still allows you to print floats over UART.

    Please let me know if this is a sufficient solution for you, or if you need further assistance.

    Best,

    Owen

  • snprintf (and friends) really does take up >350B of stack; I noticed this when it overwrote some of my (other) data. I ended up writing an itoa() equivalent.

    I haven't tried the (software) floating point library for the MSPM0, but I would expect the cost for that to be mostly flash (code) space, not RAM. The C1104 flash isn't all that small, so it might be adequate.

    Combining these could fill out Owen's suggestion.

  • Hi Bruce and CK,

    To clarify, the issue isn't with FLASH. There is plenty of FLASH to support the sprintf function, however I believe the problem is because sprintf requires significant stack space in SRAM during execution. Given that the MSPM0C1104 only has 1kB of SRAM, stack overflow may be the problem. I tried adjusting the stack and heap in my project settings and linker file, but I would hit the Default Handler stepping over:

    sprintf(buffer, "%4.1f", tmp);

    I flashed the same code to an MSPM0L1306, which has 4kB of SRAM, and there are no issues with converting a float using sprintf.

    I would suggest using manual float as I had shared in my previous reply.

    Best,

    Owen

  • I was also talking about SRAM (stack), and suggesting that snprintf not be used at all, rather itoa/ltoa/similar.

    I only mentioned flash since, in the specific example you used (all compile-time constants), it's possible the floating-point functions weren't actually linked in.

    [Edit: Minor clarification]

  • I was curious about the symptom you see, so I tried it. 

    It is a stack overflow; the HardFault results from the stack running off the bottom of SRAM (it tried to write to 0x1fffffe0), i.e. the stack occupied all of RAM and then some.

    This is even bigger than what I saw last year, so either (1) the floating support expands the stack by quite a bit or (2) the implementation changed in the meantime.

    That said: I still suggest not using snprintf on the C1104; even if it "works" now, as your program grows it eventually won't.

  • Hi Owen and Bruce,

    thank you so kindly solved my question,

    before today, i didn't realized about the float will reach the limit of SRAM(1KB)

    and  although the code provide by Owen works fine (separate display int_part and frac_part ).

    i think the best solution is try pass the raw data to another device unit, don't display at 1104-self uart,

    try to make 1104-self uart works simply.(although current sprintf works fine at int part now )

  • I know you've closed this thread, but I thought I'd add some more (unsolicited) findings: I created a "dummy" .bss array which filled the unused SRAM (between the top of data and bottom of the (nominal) stack) with 0x55, and then stepped through the program.

    1) The sprintf("%d") call appeared to use >840 bytes of stack, i.e. 80% of SRAM just for the simpler case. This will "work" as long as you have very little other data.

    2) We suppose that the rest of the 1K for the sprintf("%f") call was taken up with the stack for the floating-point library (as used by TI_printfi()). format.h defines a symbol FLOAT_VALUE_BUFSIZE=100 which may also be part of this.

    3) The stack usage is dominated by a single stack variable "char fld[FORMAT_CONVERSION_BUFSIZE]" of size 510 bytes. It gets initialized with 0x20-s so it really stands out in the Memory Browser. The comment in format.h says "The minimum max conversion size to be C89 compliant is 509 ". I recalled this variable being more like 250 bytes, but my memory is often faulty.

    4) I didn't find a Build Setting to select between alternative printf() implementations. The _printfi.c source only seems to distinguish between MINIMAL, MSP430, and <other>.

    5) ltoa() appears to be in libc.a, but not ftoa() nor itoa(). ltoa() could be useful in Owen's "split into integers" method. (I wrote my own ltoa() equivalent since ltoa() doesn't have array-bounds checking.)