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.

TMS320F28379D: Crash in vsnprintf()

Part Number: TMS320F28379D

Hello,

To be able to do some printf-style debuging, I wrote this little function:

    void log_msg( const char *restrict format, ... )
    {
        va_list args;
        va_start(args, format);

        static char buffer[ 1024 ];

        int size = vsnprintf( buffer, sizeof( buffer ) / sizeof( buffer[ 0 ] ) , format, args );
        va_end(args);

        log_write_data(buffer, MIN( sizeof( buffer ) / sizeof( buffer[ 0 ] ), size ) );
        log_write_data("\n", 1);
    }

This function works seamless when called without any parameters. If called with a format string, that contains "%f" and given an additional double argument, the execution of the CPU stucks and is not debug-able in the debugger. When I break into the debugger, I do not get any callback and when looking at the registers, the PC is 0x0000. Nearly all Core Registers are 0x0000, exepct for:

STO: 0x0010
ST1: 0x0803
SP: 0x89A5
IFR: 0x0040

log_write_data() and log_write_data() sends the data using an UART. The calling side looks like this:

static float i = 0.1;
i += 0.1;
// a log message
log_msg("Blink: %f", (double)i);

If I replace "%f" by "%g", vsnprintf() returns and and the expected data is send to the UART.

I was debugging the call to vsnprintf through the assembler code and finaly got the following callstack:

memset()
_setfield()
__TI_printfi()

Then within memset():

    memset():
    08501b:   FF58        TEST         ACC
    08501c:   C4A4        MOVL         XAR6, @XAR4
    08501d:   6104        SB           C$L2, EQ
            C$L1:
    08501e:   1901        SUBB         ACC, #1
    08501f:   7D86        MOV          *XAR6++, AR5
    085020:   60FE        SB           C$L1, NEQ

In the debugger, I see register ACC being decremented and XAR6 being incremented. When setting a break point at memset(), I think, the function is called with a destination of XAR4 (0x464), a fill pattern of XARG5 (0x0020 -> space) and a length of ACC (0x1FE) (Note, that I don't know the C2000 ABI, so I might be wrong). 0x464 seems to be a buffer on the stack (probably not `buffer` from log_msg()), as according to my linker script / map, the stack is located at 0x400 with a length of 0x0003F8. But then, 0x1FE seems way to large as this would span nearly half of my stack.

Is it possible, that I ran into a stackoverflow caused by __TI_printfi() allocating a ~1kByte buffer on the stack? Is there any chance to get my hand on the source code to investigate further into this?

Maybe I have to link against an ABI compatible C standard library? My compiler and linker invokations look like this:

    /Applications/ti/ti-cgt-c2000_20.2.2.LTS/bin/cl2000 
    --compile_only 
    --c_file=/Users/todi/ambibox/pfc/source/drivers/log.c 
    -DCAN_TEST_MESSAGES 
    -DCPU1 
    -DCROSSCOMPILING 
    -DCROSSCOMPILING=1 
    -DEVAL_BOARD=1 
    -DNASSERT 
    -D_FLASH 
    -D_LAUNCHXL_F28379D 
    --include_path=/Users/todi/ambibox/pfc/source/drivers/.. 
    --include_path=/Applications/ti/c2000/C2000Ware_3_02_00_00/device_support/f2837xd/common/include 
    --include_path=/Applications/ti/c2000/C2000Ware_3_02_00_00/device_support/f2837xd/headers/include 
    --include_path=/Applications/ti/c2000/C2000Ware_3_02_00_00/driverlib/f2837xd/driverlib 
    --include_path=/Applications/ti/ti-cgt-c2000_20.2.2.LTS/include 
    --include_path=/Users/todi/ambibox/pfc/source/control/.. 
    --silicon_version=28 
    --large_memory_model 
    --unified_memory 
    --cla_support=cla1 
    --float_support=fpu32 
    --fp_mode=relaxed 
    --tmu_support=tmu0 
    --vcu_support=vcu2 
    --display_error_number 
    --symdebug:dwarf 
    --c99 
    --gen_func_subsections 
    --gen_data_subsections=on 
    --opt_level=4 
    --output_file=CMakeFiles/drivers.dir/log.c.obj


    /Applications/ti/ti-cgt-c2000_20.2.2.LTS/bin/cl2000 
    --run_linker 
    --output_file=pfc.out 
    --map_file=pfc.out.map 
    --stack_size=0x3F8 
    --heap_size=0 
    --entry_point=code_start 
    --rom_model 
    CMakeFiles/pfc.out.dir/pfc.c.obj 
    CMakeFiles/pfc.out.dir/ring_buffer.c.obj 
    CMakeFiles/pfc.out.dir/main_thread.c.obj 
    CMakeFiles/pfc.out.dir/parameters.c.obj 
    CMakeFiles/pfc.out.dir/controller.c.obj 
    CMakeFiles/pfc.out.dir/versions.c.obj 
    CMakeFiles/pfc.out.dir/curve.c.obj 
    CMakeFiles/pfc.out.dir/state_machine.c.obj   
    --search_path=/Applications/ti/ti-cgt-c2000_20.2.2.LTS/lib  
    --search_path=/Applications/ti/ti-cgt-c2000_20.2.2.LTS/include  
    --search_path=/Applications/ti/c2000/C2000Ware_3_02_00_00/device_support/f2837xd/common/cmd  
    --search_path=/Applications/ti/c2000/C2000Ware_3_02_00_00/device_support/f2837xd/headers/cmd  
    drivers/libdrivers.a libc2000ware.a 
    ../../source/linker_script.cmd control/libcontrol.a 
    libcla_math.a 
    libstartup_files.a 
    --library=rts2800_fpu32.lib 
    --library=F2837xD_Headers_nonBIOS_cpu1.cmd 

Target hardware is a F28379D. I havn't found any example in the SDK that makes use of vsnprintf().

best regards,

Torsten

  • This is the hardest to explain ...

    Torsten Robitzki said:
    If I replace "%f" by "%g", vsnprintf() returns and and the expected data is send to the UART.

    Because the handling of %f and %g is similar.

    Please see if one of the Tips for using printf resolves the problem.  In particular, make the stack and the heap as large as you can.  

    Thanks and regards,

    -George

  • Hi George,

    thank you for the fast reply. My working theory is, that the TI implementation puts a 1kByte buffer on the stack. Without source code, I can't prove that. I'm using an alternative implementation now and that works without any problems and surprises.

    best regards,

    Torsten

  • The source code to the RTS is part of the compiler installation.  In your case, it is located in ...

    /Applications/ti/ti-cgt-c2000_20.2.2.LTS/lib/src

    The problem is with this function ...

    /*****************************************************************************/
    /* _PCONV_F -  Perform the %f conversion                                     */
    /*                                                                           */
    /*    Upon input, **a_it points to where the least significant digit will    */
    /*    be written; this function writes backwards from this point.  *a_it is  */
    /*    moved backward as characters are written; upon return, *a_it points    */
    /*    to the character before the digit sequence.                            */
    /*                                                                           */
    /*    Upon input, cvt is in [0, LDBL_MAX]                                    */
    /*                                                                           */
    /*****************************************************************************/
    static void _pconv_f(long double cvt, _PFIELD *pfield, char **a_it)
    {
       /*------------------------------------------------------------------------*/
       /* Local variables                                                        */
       /*------------------------------------------------------------------------*/
       char  tmpbuf[F_CONVERSION_BUFSIZE];
    

    It is in the source file _printfi.c.  It is called to process the %f of a format string.  Focus on the local buffer tmpbuf defined on the last line.  F_CONVERSION_BUFSIZE is 510.  The standards, and the tests based on those standards, require the buffer to be this big.

    There are two alternatives to consider.  One is to make this buffer static.  In that case, it permanently takes up memory in the program.  But it does not require you to set aside as much memory for the stack.

    The other alternative is to make this buffer smaller.  Then the stress tests of %f conversions will fail.  But, in your program, you may not care about that.

    If you decide to change the RTS source code, please remember to make that change every time you upgrade to another version of the compiler.

    Thanks and regards,

    -George