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.

MSP430FR5994: Using 'double' declaration leads to a crash in debugging

Part Number: MSP430FR5994
Other Parts Discussed in Thread: BOOSTXL-AUDIO

I have a code that calculates some mathematical coefficients for a neural network. During the debugging process, I have a variable that needs to be of the 'double' datatype. When I use it in the code at a particular place, the code crashes during debugging. I am using the BOOSTXL-AUDIO Playback sample as a reference. Over the last couple of days, I tested different cases to observe in which cases this crash occurs. Out of the two scenarios I found, in one case the code works properly and continues with the execution when I use the 'double' datatype for declaring a variable but in the other case, the exact same code fails to execute and goes into either 'spin forever' condition or just shuts the code down and branches into the 'boot.c' file. I have absolutely no idea why it would behave differently for the exact same code except for one change where a variable is defined as 'double' and not 'float'. 

PS. The variable needs to be in 'double' format according to the function definition. 

Here is a part of the code where the crash occurs. I am adding both the 'main.c' and 'application.c' file from the project.

int main(void)
{
     WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer

    initClock();
    initGpio();

    PM5CTL0 &= ~LOCKLPM5;           // Clear lock bit

    // vm1010 mode pin (P6.1), o/p, low at start for normal mode
    P6OUT &= ~BIT1;             // vm1010
    P6DIR |= BIT1;              // vm1010
    // vm1010 mic power on (P6.2)
    P6OUT |= BIT2;              // vm1010
    P6DIR |= BIT2;              // vm1010

    // vm1010 mode pin, o/p, high for WoS mode
    P6OUT |= BIT1;              // vm1010

    P5IFG &= ~BIT6;             // Clear interrupt on P5.6
    P5IE |= BIT6;               // Enable interrupt on P5.6
    P5IFG &= ~BIT5;             // Clear interrupt on P5.5
    P5IE |= BIT5;               // Enable interrupt on P5.5

    // vm1010
    P5IFG &= ~BIT7;             // Clear interrupt on P5.7
    P5IE |= BIT7;               // Enable interrupt on P5.7

    // Enable Switch interrupt
    GPIO_clearInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);
    GPIO_enableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);

    // Initialize DAC
	DAC8311_init();

	// Set the DAC to low power mode with output high-Z
	DAC8311_setLowPowerMode(DAC8311_OUTPUT_HIGHZ);

	__bis_SR_register(GIE);

    // Starts the application. It is a function that never returns.
    runApplication();

    return 1;
}
      
void runApplication(void)
{
    while(1)
    {
        P5IE &= ~BIT7;      // Disable interrupt on P5.7 // vm1010
        P5IE &= ~BIT6;      // Disable interrupt on P5.6
        P5IE &= ~BIT5;      // Disable interrupt on P5.5

		// Disable button interrupt
		GPIO_disableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);

    	switch(applicationMode)
        {
    	    volatile uint16_t j;
            case RECORD:
*                runRecord();
*                amplify_data();
*                fft_init();
                while(window_number < 64)
                {
                    fft_cal();
                }
                window_number=0;
                for(j = 1; j < (VECTOR_SIZE / 2); j++)  // vm1010
                {
                    // vm1010
                    real = fft_res[2 * j] << 2;
                    imag = fft_res[2 * j + 1] << 2;
                    if(real < 0)
                    {
                        real_abs = ~real + 1;
                    }
                    else
                    {
                        real_abs = real;
                    }
                    if(imag < 0)
                    {
                        imag_abs = ~imag + 1;
                    }
                    else
                    {
                        imag_abs = imag;
                    }
                    if(real_abs >= imag_abs)
                    {
                        max = real_abs;
                        min = imag_abs;
                    }
                    else
                    {
                        max = imag_abs;
                        min = real_abs;
                    }
                    mag = max + 3 * (min >> 3);
                    FFT_data[j] = mag << 1;
                }
                break;
            default: break;
        }

        // Toggle app mode
		applicationMode = DEFAULT;

		P6OUT &= ~BIT1;                 // vm1010

		// Set a Switch debounce to 500ms
        __delay_cycles(0.5 * __SYSTEM_FREQUENCY_MHZ__);

        P5IFG &= ~BIT6;                 // Clear interrupt on P5.6
        P5IE |= BIT6;                   // Enable interrupt on P5.6
        P5IFG &= ~BIT5;                 // Clear interrupt on P5.5
        P5IE |= BIT5;                   // Enable interrupt on P5.5
        P5IFG &= ~BIT7;                 // Clear interrupt on P5.7 // vm1010
        P5IE |= BIT7;                   // Enable interrupt on P5.7 // vm1010
        // vm1010 mode pin, o/p, high for WoS mode
        P6OUT |= BIT1;  // vm1010

        GPIO_clearInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);        // Clear the interrupt flag
        GPIO_enableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);       // Re-enable the interrupt

        // Enter low power mode
        
*		__bis_SR_register(LPM4_bits + GIE);
		
		float mfcc_result;
		float mfcc_value[13];
		float mfcc_features_f[12];
*        if(FFT_data[1] != 0)
        {
            // MFCC Calculations can be included here

            double spectrum[512];  // when double changes to float - the code runs correctly
            int i;
            for(i=0;i<512;i++)
            {
                spectrum[i] = (double)FFT_data[i];
            }

I have also marked with an ' * ' the locations of my debug points in the second file. I tried looking at different documents detailing the behavior of the data type and declarations but I could not find a reason for this behavior. The calculation of coefficients does work correctly when executed with the exact same logic - including the 'double' declaration -  when executed separately in another project. If I could get any idea about what might be going wrong here, I could try it out. Please let me know if any more details are needed to help understand the question better. 

  • If you can use floats, you should be able to use doubles. Can you pare down your program to a smallish example that shows the issue?

    As a WAG, you might try to increase the stack space a bit.

  • // Returns the specified (mth) MFCC
    double GetCoefficient(double* spectralData, unsigned int samplingRate, unsigned int NumFilters, unsigned int binSize, unsigned int m);
    
    void runApplication(void)
    {
        while(1)
        {
            P5IE &= ~BIT7;      // Disable interrupt on P5.7 // vm1010
            P5IE &= ~BIT6;      // Disable interrupt on P5.6
            P5IE &= ~BIT5;      // Disable interrupt on P5.5
    
    		// Disable button interrupt
    		GPIO_disableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);
    
        	switch(applicationMode)
            {
        	    volatile uint16_t j;
                case RECORD:
                    runRecord();
                    amplify_data();
                    fft_init();
                    while(window_number < 64)
                    {
                        fft_cal();
                    }
                    window_number=0;
                    // Some code for calculations
                    break;
                default: break;
            }
    
            // Toggle app mode
    		applicationMode = DEFAULT;
    
    		P6OUT &= ~BIT1;                 // vm1010
            GPIO_clearInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);        // Clear the interrupt flag
            GPIO_enableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);       // Re-enable the interrupt
    
            // Enter low power mode
    		__bis_SR_register(LPM4_bits + GIE);
    		
    		float mfcc_result;
    		float mfcc_value[13];
    		float mfcc_features_f[12];
            if(FFT_data[1] != 0)
            {
                // MFCC Calculations can be included here
                double spectrum[512];
                int i;
                for(i=0;i<512;i++)
                {
                    spectrum[i] = (double)FFT_data[i];
                }
                int coeff;
                for(coeff = 0; coeff < 13; coeff++)
                {
                        mfcc_result = GetCoefficient(&spectrum[coeff], 44100, 48, 128, coeff);
                        mfcc_value[coeff] = mfcc_result;
                }
            }
        }
    }
    
    int main(void)
    {
         WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer
    
        initClock();
        initGpio();
    
        PM5CTL0 &= ~LOCKLPM5;           // Clear lock bit
    
        // vm1010 mode pin (P6.1), o/p, low at start for normal mode
        P6OUT &= ~BIT1;             // vm1010
        P6DIR |= BIT1;              // vm1010
        // vm1010 mic power on (P6.2)
        P6OUT |= BIT2;              // vm1010
        P6DIR |= BIT2;              // vm1010
    
        // vm1010 mode pin, o/p, high for WoS mode
        P6OUT |= BIT1;              // vm1010
    
        P5IFG &= ~BIT6;             // Clear interrupt on P5.6
        P5IE |= BIT6;               // Enable interrupt on P5.6
        P5IFG &= ~BIT5;             // Clear interrupt on P5.5
        P5IE |= BIT5;               // Enable interrupt on P5.5
    
        // vm1010
        P5IFG &= ~BIT7;             // Clear interrupt on P5.7
        P5IE |= BIT7;               // Enable interrupt on P5.7
    
        // Enable Switch interrupt
        GPIO_clearInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);
        GPIO_enableInterrupt(PUSHBUTTON1_PORT, PUSHBUTTON1_PIN);
    
        // Initialize DAC
    	DAC8311_init();
    
    	// Set the DAC to low power mode with output high-Z
    	DAC8311_setLowPowerMode(DAC8311_OUTPUT_HIGHZ);
    
    	__bis_SR_register(GIE);
    
        // Starts the application. It is a function that never returns.
        runApplication();
    
        return 1;
    }

    I tried to encapsulate the issue as succintly as possible here. The idea is that I have a function called GetCoefficient() which returns a value in the 'double' format. I want to use this function to calculate some coefficients using the MSP430. Before I calculate the coefficients, the input to this function needs to be provided from an external microphone - When I debug the code, the code is supposed to first branch into the runApplication function and enter the low power mode via -  __bis_SR_register(LPM4_bits + GIE); - once the MSP430 is removed from here, it checks an array and records the sound and does some calculations - after which it ends up in the low power mode again via - __bis_SR_register(LPM4_bits + GIE);  - once it's removed from here, the next task is to calculate the coefficients using the 'double()' function - at this position I run into the issue. If I use 'float' insteaf of 'double' for declaring the variable 'spectrum' - the MSP430 runs smoothly - however when 'spectrum' is defined as 'double'  - the code abruptly halts in the very first half without even entering the low power mode. I am not sure how this problem occurs as I tried using 'float' values in place of 'double' arguments - they merely showed warnings in those programs - also, here I am trying to maintain the datatype by storing the calculations in a 'double' variable and only after this step do I move it into another 'float' variable.

    I apologize for the lengthy response, but please let me know if any more details are necessary to clarify my question further. Thanks a lot.

  • >     double spectrum[512];

    This eats up 8*512=4KB of stack by itself.  Have you provided that much? As float it's only 2KB.

    As a quick experiment, move this variable outside the function (so it's global) and see if the program links.

  • As soon as I sent this reply, I realized that and moved the variable outside the function - the code is working now - I will just verify it once the entire function runs and then update the issue as resolved. Thanks Bruce! Also Thanks Keith for your response and suggestion!

  • I had heard that ccs was smart enough to use malloc() for large defininitions so they would not be on the stack.

  • Gee, I hope not. I try not to let malloc anywhere near my code.

  • I know, me neither, But you would have not tried to allocate that much data on the stack, anyway.

  • I had heard that ccs was smart enough to use malloc() for large defininitions so they would not be on the stack.

    I'm not aware of any automatic method the TI MSP430 compiler uses to decide if definitions are to be allocated by malloc rather than the stack.

    With the TI MSP430 v21.6.0 compiler the following allocates spectrum[] on the stack:

    int main(void)
    {
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    	
        double spectrum[512];
    
        spectrum[0] = 1.2345;
    
    	return (int) spectrum[0];
    }
    

    Whereas if define spectrum as a variable-length-array (VLA) then the compiler calls __vla_alloc() to allocate space for the array on the heap (and a call to __vla_dealloc to free the variable when goes out of scope):

    int main(void)
    {
    	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    
    	int spectrum_size = 512;
        double spectrum[spectrum_size];
    
        spectrum[0] = 1.2345;
    
    	return (int) spectrum[0];
    }
    

  • Thanks Chester for this clarification. I think I finally have some clarity of how and where CCS will store values. 

  • Ah, yes, I was vaguely remembering a VLA discussion.

**Attention** This is a public forum