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.

MSP432P401R: Math.h functions cause exceptions, unpredictable behavior

Part Number: MSP432P401R


Executing the following code causes random, unrelated variables to be set to 0 for no reason:

x = sin(1); // Causes device to behave unpredictably

However, if I use the float version of the same function it works just fine.

x = sinf(1); // This works fine

What's going on here?

  • I am using IAR EWARM 7.80.3
  • Did you include math.h?

    Can you provide a small example that shows this behavior?
  • sin uses double arguments, whereas sinf uses float arguments.

    The data type float is always represented using 32 bits. Whereas if you use the IAR compiler option --double={32|64}, you can choose whether data declared as double should be represented with 32 bits or 64 bits.

    If double is set as 64 bits then calls to sin will require more stack space than sinf, so maybe the errors are caused by insufficient stack space.

  • Hi Keith, yes I'm including <math.h>. It's grabbing math.h from the "Embedded Workbench 7.5\arm\inc\c\math.h" directory. 

    When things go haywire after "sin(1)", what happens is a pointer stored at 0x20001CCC is reset to 0. All it takes is call to the sin function with any value.

  • Chester, sizeof(double) is 8 bytes according to the debugger. Wouldn't it be the opposite problem though; sinf() would be the troublemaker instead of sin()? Thanks - David
  • Possibly related: when I use the sprintf() function (with any input) I get the same unpredictable behavior. Only by not using sprintf does the code work properly.
  • I used IAR 8.11.2 to look at the stack usage for a program for a MSP43P401R. In the General Options -> Target:

    - The Device was set to MSP43P401R.
    - The Floating point settings had the FPU as "VFPv4 single precision".

    Under the Linker -> Advanced Options enabled the "Enable stack usage analysis" option, which causes the linker to perform stack usage analysis.

    1. With a program just calling sin() from main the Stack Usage in the linker .map file was:

    *******************************************************************************
    *** STACK USAGE
    ***
    
      Call Graph Root Category  Max Use  Total Use
      ------------------------  -------  ---------
      interrupt                      0          0
      Program entry                 88         88
    
    
    Program entry
      "__iar_program_start": 0x00000a1d
    
      Maximum call chain                               88  bytes
    
        "__iar_program_start"                           0
        "__cmain"                                       0
        "main"                                          8
        "__iar_vfp_sin"                                 8
        "__iar_sin64"                                   0
        "__iar_Sin64" in cos_sin64.o [4]               48
        "__aeabi_dadd"                                 12
        "__iar_dsub"                                   12
    
    interrupt
      "__default_handler" in vector_table_M.o [5]: 0x0000062b
    
      Maximum call chain                                0  bytes
    
        "__default_handler" in vector_table_M.o [5]     0

    I.e. the call to sin resulted in a call to the run time library function __iar_vfp_sin and the total stack usage for the program was 88 bytes.

    2. With a program just calling sinf() from main the Stack Usage in the linker .map file was:

    *******************************************************************************
    *** STACK USAGE
    ***
    
      Call Graph Root Category  Max Use  Total Use
      ------------------------  -------  ---------
      interrupt                      0          0
      Program entry                 12         12
    
    
    Program entry
      "__iar_program_start": 0x00000311
    
      Maximum call chain                               12  bytes
    
        "__iar_program_start"                           0
        "__cmain"                                       0
        "__iar_data_init3"                              8
        "__iar_copy_init3"                              4
    
    interrupt
      "__default_handler" in vector_table_M.o [5]: 0x000002a9
    
      Maximum call chain                                0  bytes
    
        "__default_handler" in vector_table_M.o [5]     0

    I.e. changing from sin() to sinf() reduced the required amount of stack.

    Can you enable the linker stack analysis and compare the required stack usage reported by the linker against the actual stack size set for the project?

  • Chester, I think you're onto something. The "systemStack" array size in the msp432_startup_ewarm.c file was being set to 128. I increased this to 1024 and now the unpredictable behavior is gone. Here's the code copied from msp432_startup_ewarm.c:

    //*****************************************************************************
    //
    // Reserve space for the system stack.
    //
    //*****************************************************************************
    static uint32_t systemStack[1024] @ ".noinit"; // (This was [128] when it wasn't working, increasing to [1024] fixed it - David)
    
    //*****************************************************************************
    //
    // A union that describes the entries of the vector table.  The union is needed
    // since the first entry is the stack pointer and the remainder are function
    // pointers.
    //
    //*****************************************************************************
    typedef union
    {
        void (*handler)(void);
        uint32_t ptr;
    }
    uVectorEntry;
    
    //*****************************************************************************
    //
    // The vector table.  Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000.
    //
    //*****************************************************************************
    __root const uVectorEntry __vector_table[] @ ".intvec" =
    {
        { .ptr = (uint32_t)systemStack + sizeof(systemStack) },
                                                // The initial stack pointer
        ResetISR,                               // The reset handler
        NmiSR,                                  // The NMI handler
        FaultISR,                               // The hard fault handler
        IntDefaultHandler,                      // The MPU fault handler
        IntDefaultHandler,                      // The bus fault handler
        IntDefaultHandler,                      // The usage fault handler
        0,                                      // Reserved
        0,                                      // Reserved
        0,                                      // Reserved
        0,                                      // Reserved
        IntDefaultHandler,                      // SVCall handler
        IntDefaultHandler,                      // Debug monitor handler
        0,                                      // Reserved
        IntDefaultHandler,                      // The PendSV handler
        SysTick_ISR,                            // The SysTick handler
        IntDefaultHandler,                      // PSS ISR
        IntDefaultHandler,                      // CS ISR 
        IntDefaultHandler,                      // PCM ISR
        IntDefaultHandler,                      // WDT ISR
        IntDefaultHandler,                      // FPU ISR
        IntDefaultHandler,                      // FLCTL ISR
        IntDefaultHandler,                      // COMP_E0_MODULE ISR
        IntDefaultHandler,                      // COMP_E1_MODULE ISR
        IntDefaultHandler,                      // TA0_0 ISR
        IntDefaultHandler,                      // TA0_N ISR
        IntDefaultHandler,                      // TA1_0 ISR
        IntDefaultHandler,                      // TA1_N ISR
        IntDefaultHandler,                      // TA2_0 ISR
        IntDefaultHandler,                      // TA2_N ISR
        IntDefaultHandler,                      // TA3_0 ISR
        IntDefaultHandler,                      // TA3_N ISR
        UARTa0_ISR,                             // EUSCIA0 ISR
        UARTa1_ISR,                             // EUSCIA1 ISR
        UARTa2_ISR,                             // EUSCIA2 ISR
        UARTa3_ISR,                             // EUSCIA3 ISR
        IntDefaultHandler,                      // EUSCIB0 ISR
        IntDefaultHandler,                      // EUSCIB1 ISR
        IntDefaultHandler,                      // EUSCIB2 ISR
        IntDefaultHandler,                      // EUSCIB3 ISR
        IntDefaultHandler,                      // ADC12 ISR
        IntDefaultHandler,                      // T32_INT1 ISR
        IntDefaultHandler,                      // T32_INT2 ISR
        IntDefaultHandler,                      // T32_INTC ISR
        IntDefaultHandler,                      // AES ISR
        IntDefaultHandler,                      // RTC ISR
        IntDefaultHandler,                      // DMA_ERR ISR
        IntDefaultHandler,                      // DMA_INT3 ISR
        IntDefaultHandler,                      // DMA_INT2 ISR
        IntDefaultHandler,                      // DMA_INT1 ISR
        IntDefaultHandler,                      // DMA_INT0 ISR
        IntDefaultHandler,                      // PORT1 ISR
        PORT2_ISR,                              // PORT2 ISR
        IntDefaultHandler,                      // PORT3 ISR
        IntDefaultHandler,                      // PORT4 ISR
        IntDefaultHandler,                      // PORT5 ISR
        IntDefaultHandler,                      // PORT6 ISR
        IntDefaultHandler,                      // Reserved 41
        IntDefaultHandler,                      // Reserved 42
        IntDefaultHandler,                      // Reserved 43
        IntDefaultHandler,                      // Reserved 44
        IntDefaultHandler,                      // Reserved 45
        IntDefaultHandler,                      // Reserved 46
        IntDefaultHandler,                      // Reserved 47
        IntDefaultHandler,                      // Reserved 48
        IntDefaultHandler,                      // Reserved 49
        IntDefaultHandler,                      // Reserved 50
        IntDefaultHandler,                      // Reserved 51
        IntDefaultHandler,                      // Reserved 52
        IntDefaultHandler,                      // Reserved 53
        IntDefaultHandler,                      // Reserved 54
        IntDefaultHandler,                      // Reserved 55
        IntDefaultHandler,                      // Reserved 56
        IntDefaultHandler,                      // Reserved 57
        IntDefaultHandler,                      // Reserved 58
        IntDefaultHandler,                      // Reserved 59
        IntDefaultHandler,                      // Reserved 60
        IntDefaultHandler,                      // Reserved 61
        IntDefaultHandler,                      // Reserved 62
        IntDefaultHandler,                      // Reserved 63
        IntDefaultHandler                       // Reserved 64
    };
    

    I'm not quite sure what's going on here, why the original size of [128] didn't work, or what the "right" size of systemStack should be. Any insight would be appreciated. Thanks -David

  • David Humphrey said:
    I'm not quite sure what's going on here, why the original size of [128] didn't work...

    Chester's test program hit 88 bytes of stack usage with a single call to sin() from main. If your program has a deeper call graph with more local variables you could easily blow through the rest of that 128-byte default stack. You have some interrupt service routines listed in your last post too, those will use extra stack space when triggered.

    Do you particularly need to use double-precision float for your calculations? The MSP432 has single-precision floating point hardware, but the support for double-precision will be emulated in software. That's going to be a lot slower, and will take up more stack space.

  • Robert, thanks for your reply. I generally understand the concept of the C stack and the dangers that come with having one too small (I'm very familiar with MSP430s and their stack architecture).

    I think what's confusing to me is this startup.c file. Is the "systemStack" the same thing as the user stack? The "CSTACK"? If I change the stack size via the linker file, will it get overwritten by the value of this systemStack? Are they even the same thing? It seems like this startup.c file is redundant with my project settings, can I do away with it altogether and safely move the interrupt vector definitions into the main code? Those are the kinds of things that I still unclear to me. Thanks -David
  • David Humphrey said:
    I'm not quite sure what's going on here, why the original size of [128] didn't work, or what the "right" size of systemStack should be.

    The "right" size of the system stack requires an analysis of the stack usage of each function and then the worst-case stack use for the call tree of the functions which be called.

    The following IAR web pages show how IAR Embedded Workbench may be used to determine the stack usage of a program:

    Mastering stack and heap for system reliability

    Find the stack usage of your application with IAR Embedded Workbench for RX

    Stack usage and stack usage control files

    Note that the way the startup_msp432p401r_ewarm.c file uses systemStack for the stack means the IAR debug Stack view doesn't recognize the location of the stack.

  • Thanks for this Chester. One more follow-up question: how can I change systemStack in the startup_msp432401r_ewarm.c file so that the stack view works properly in IAR? This has been a problem.

    I also want the stack size to be decided by my linker file instead of this systemStack variable in the startup file. Thanks -David

  • David Humphrey said:
    One more follow-up question: how can I change systemStack in the startup_msp432401r_ewarm.c file so that the stack view works properly in IAR?

    I tried to look at that, but haven't yet determined the required change.

    [I am not a regular user of IAR Embedded Workbench, hopefully someone else will reply]

  • I've had a look at this and I suggest you apply the following changes to startup_msp432p401r_ewarm.c:

    ---

    ...

    //*****************************************************************************
    //
    // Reserve space for the system stack.
    //
    //*****************************************************************************
    #if 1
    extern uint32_t CSTACK$$Limit;
    #else
    static uint32_t systemStack[128] @ ".noinit";
    #endif

    ...

    //*****************************************************************************
    //
    // The vector table. Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000.
    //
    //*****************************************************************************
    __root const uVectorEntry __vector_table[] @ ".intvec" =
    {
    #if 1
    {.ptr= (uint32_t)(&CSTACK$$Limit)}, /* Initial Stack Pointer */
    #else
    { .ptr = (uint32_t)systemStack + sizeof(systemStack) },
    #endif

    ...

    ---

    This will make the stack show up in the stack viewer as well as using the stack that is defined for the purpose in the linker file, msp432p401r.icf

    I suggest that TI cleans this up in their simplelink examples

    The issue is that the stack viewer looks for a few standard stack names and "systemStack" is not one of them 

**Attention** This is a public forum