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.

  • Resolved

CCS/MSP-EXP430FR5994: BOOSTXL-AUIDIO EXAMPLE FFT

Part Number: MSP-EXP430FR5994

Tool/software: Code Composer Studio

Hi everyone.

I have been playing with the msp430fr5994 for 2 months. I'm still learning C so sorry if my questions are obvious.

First of all i'm very confussed with the adc data. The values are (for expample) between -31472 and 22992. I can´t undestand it if the adc is 12 bits.

The second one is about the variable status wich is the return from de fft function. I can't si it on the watch window, why?

The last one is about the LEA memory. In the .map appears the length, and for the LEARAM is 0x00000ec8, 3784 bytes, why is not 4096? what is LEASTACK? if the real memory available is less than 4kb, which is the maximum fft possible?

Thank you.

Marcos.

  • Hi Marcos, 

    Marcos Llorente
    First of all i'm very confussed with the adc data. The values are (for expample) between -31472 and 22992. I can´t undestand it if the adc is 12 bits.

    It's important to note that in this example, the ADC is setup to store the results in two's complement format.  This is done at approximately line 127 in the audio_collect.c file. So theoretically, when the ADC input voltage is -Vref the result is 0x8000 which is the two's complement representation of -32768. Similarly when the ADC input voltage is +Vref, the result is 0x7FF0 which is +32752. So when you consider that an audio signal is a sinusoidal wave, you will see voltage at the ADC input that periodically dips "negative" and then goes back to positive. You can learn more about two's complement representation of numbers here: 

    Marcos Llorente
    The second one is about the variable status wich is the return from de fft function. I can't si it on the watch window, why?

    The compiler is most likely optimizing the code in a way that the "status" variable is not used or defined anymore. If you turn off optimizations completely, you'll be able to view this variable in the Expressions window. 

    Marcos Llorente
    The last one is about the LEA memory. In the .map appears the length, and for the LEARAM is 0x00000ec8, 3784 bytes, why is not 4096? what is LEASTACK?

    LEA RAM is 4KB in length. When viewing the .map file you've already noticed that some memory is allocated to the LEA stack. In reality the LEA module is a CPU that is independent of the MSP430 CPU. It performs operations and requires the use of a stack just like the MSP430 CPU to be able to call functions and return successfully. You can read more on the purpose of a stack in computing here: 

    Marcos Llorente
    if the real memory available is less than 4kb, which is the maximum fft possible?

    This is determined by the ability to align data to the appropriate borders within the LEA memory. For example, the msp_fixed_fft_q15 function requires the input data to be aligned to a 2*(input data length) boundary. This means that a 512 point FFT must be aligned to a memory boundary that is a multiple of 1024. Similarly, the largest FFT supported by LEA is a 2048 point FFT because it must be aligned to a memory boundary that is a multiple of 4096. Anything larger than this does not have a valid memory boundary within LEA RAM. For example a 4096 point FFT would need to be aligned to a memory location that's a multiple of 8192 but there is no memory location in LEA RAM (0x2C00-0x3BFF) that fits this requirement.

    Fortunately, this isn't something you need to do by hand. TI provides  predefined macros with DSPLIB that will perform the data alignment for you and let you know whether the data will fit into LEA RAM at compile time. You can learn more about data alignment, considerations when using LEA, and other functions supported by LEA in the DSPLIB User's Guide

    Hope this helps and let me know if you have any follow-up questions. 

    Best regards, 
    Caleb Overbay

  • In reply to Caleb Overbay:

    Thanks for the reply.


    I still have doubts about fft. to run the msp_fixed_fft_q15 function requires the input data to be aligned to a 2*(input data length) boundary. So If I choose a 2048 point fft I need 4096 bytes and LEA RAM haven't got that because of the LEASTACK. Therefore, the maximum size will be 1024 point for fft using msp_fixed_fft_q15 function .

    To check it I downloaded the transform_ex1_fft_fixed_q15 example to modify it and try different sizes. Unfortunately the example didn't work. When I try to debug the code and suspend the debug, the code is always at the same line:

    case MSP_LEA_INCORRECT_REVISION:
    /* LEA incorrect revision, loop forever. */
    while(true) __no_operation();

    Why? I haven't modified the code.

    I also tried changing the bootxl-audio example code, #define VECTOR_SIZE inside FFT.h , to try a bigger fft. The result is status=MSP_LEA_OUT_OF_RANGE.

    Could you check if transform_ex1_fft_fixed_q15 example is ok?

    I would be very grateful if you could provide a code that works with a msp_fixed_fft_q15 using 1024 points.


    Best regards.
    Marcos.
  • In reply to Marcos Llorente:

    Hi Marcos, 

    Marcos Llorente
    So If I choose a 2048 point fft I need 4096 bytes and LEA RAM haven't got that because of the LEASTACK. Therefore, the maximum size will be 1024 point for fft using msp_fixed_fft_q15 function

    I think you're confusing data alignment with amount of memory required. Aligning data to a 4096 boundary does not mean the data has to consume 4096 bytes. it only means that the starting address of that data must be evenly divisible by 4096. 

    Marcos Llorente
    case MSP_LEA_INCORRECT_REVISION:
    /* LEA incorrect revision, loop forever. */
    while(true) __no_operation();

    This seems like you may have an outdated version of DPSLIB or DRIVERLIB. Can you ensure you've downloaded and installed that latest CCS and MSP430Ware versions?

    Best regards, 
    Caleb Overbay

  • In reply to Caleb Overbay:

    Hi.

    I have checked the versions and I have the lastest ones. Also I have tried the code in CCS Cloud with the same result.

    Could you check it?

    Best regards.

    Marcos.

  • In reply to Marcos Llorente:

    Hi Marcos,

    You probably have rev. A silicon which requires you to add a predefined symbol to the compiler options. Under compiler options, select the predefined symbols and add the following to the list of predefined names:

    MSP_LEA_REVISION=0

    By default DSPLib will set MSP_LEA_REVISION=1 which is for rev. B silicon when MSP_LEA_REVISION is not explicitly defined in the compiler options. The source code must be built for the correct revision in order to provide workarounds for LEA functions that have changed between revisions. If the LEA version does not match what the library is built against you may get unexpected results which is why the code returns the MSP_LEA_INCORRECT_REVISION status and traps execution.

    The LEA section of the DSPLib Users Guide has more information and sample code to check the revision (link).

    Regards,

    Brent

  • In reply to Brent Peterson:

    Thank you for the attention.

    I have solve the problem, I don't know exactly how, but it's solved. Now I'm able to debug and analyze what msp_fft_fixed_q15 returns. I have found that the status variable is MSP_SIZE_ERROR when it is supoused to be MSP_SUCCESS. Why? How is the fft result affected?

    I am very grateful for your help.

    Marcos.
  • In reply to Marcos Llorente:

    Hi Marcos,

    The error you're receiving means you have passed an incorrect size to the msp_fft_fixed_q15 function. Did you make any changes to the example project? It might be helpful if you posted your code using the syntax highlighter so I can double check if there are any bugs.

    Best regards,
    Caleb Overbay

  • In reply to Caleb Overbay:

    This is the original code

    //******************************************************************************
    // Real FFT with fixed scaling.
    //
    // Brent Peterson, Jeremy Friesenhahn
    // Texas Instruments Inc.
    // April 2016
    //******************************************************************************
    #include "msp430.h"
    #include <math.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "DSPLib.h"
    /* Input signal parameters */
    #define FS                  8192
    #define SAMPLES             256
    #define SIGNAL_FREQUENCY1   200
    #define SIGNAL_AMPLITUDE1   0.6
    #define SIGNAL_FREQUENCY2   2100
    #define SIGNAL_AMPLITUDE2   0.15
    /* Hamming window parameters */
    #define HAMMING_ALPHA       0.53836
    #define HAMMING_BETA        0.46164
    /* Constants */
    #define PI                  3.1415926536
    /* Generated Hamming window function */
    DSPLIB_DATA(window,4)
    _q15 window[SAMPLES];
    /* Input signal and FFT result */
    DSPLIB_DATA(input,MSP_ALIGN_FFT_Q15(SAMPLES))
    _q15 input[SAMPLES];
    /* Temporary data array for processing */
    DSPLIB_DATA(temp,4)
    _q15 temp[3*SAMPLES/2];
    /* Benchmark cycle counts */
    volatile uint32_t cycleCount;
    /* Function prototypes */
    extern void initSignal(void);
    extern void initHamming(void);
    void main(void)
    {
        msp_status status;
        msp_mpy_q15_params mpyParams;
        msp_fft_q15_params fftParams;
        /* Disable WDT */
        WDTCTL = WDTPW + WDTHOLD;
        
        /* Initialize input signal and Hamming window */
        initSignal();
        initHamming();
        /* Multiply input signal by generated Hamming window */
        mpyParams.length = SAMPLES;
        status = msp_mpy_q15(&mpyParams, input, window, input);
        msp_checkStatus(status);
        /* Initialize the fft parameter structure. */
        fftParams.length = SAMPLES;
        fftParams.bitReverse = true;
        fftParams.twiddleTable = msp_cmplx_twiddle_table_256_q15;
        /* Perform real FFT with fixed scaling */
        msp_benchmarkStart(MSP_BENCHMARK_BASE, 16);
        status = msp_fft_fixed_q15(&fftParams, input);
        cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE);
        msp_checkStatus(status);
    
        /* End of program. */
        __no_operation();
    }
    void initSignal(void)
    {
        msp_status status;
        msp_add_q15_params addParams;
        msp_sinusoid_q15_params sinParams;
        /* Generate Q15 input signal 1 */
        sinParams.length = SAMPLES;
        sinParams.amplitude = _Q15(SIGNAL_AMPLITUDE1);
        sinParams.cosOmega = _Q15(cosf(2*PI*SIGNAL_FREQUENCY1/FS));
        sinParams.sinOmega = _Q15(sinf(2*PI*SIGNAL_FREQUENCY1/FS));
        status = msp_sinusoid_q15(&sinParams, input);
        msp_checkStatus(status);
        /* Generate Q15 input signal 2 to temporary array */
        sinParams.length = SAMPLES;
        sinParams.amplitude = _Q15(SIGNAL_AMPLITUDE2);
        sinParams.cosOmega = _Q15(cosf(2*PI*SIGNAL_FREQUENCY2/FS));
        sinParams.sinOmega = _Q15(sinf(2*PI*SIGNAL_FREQUENCY2/FS));
        status = msp_sinusoid_q15(&sinParams, temp);
        msp_checkStatus(status);
        /* Add input signals */
        addParams.length = SAMPLES;
        status = msp_add_q15(&addParams, input, temp, input);
        msp_checkStatus(status);
    }
    void initHamming(void)
    {
        msp_status status;
        msp_sub_q15_params subParams;
        msp_copy_q15_params copyParams;
        msp_fill_q15_params fillParams;
        msp_sinusoid_q15_params sinParams;
        /* Generate sinusoid for cosine function */
        sinParams.length = 3*SAMPLES/2;
        sinParams.amplitude = _Q15(HAMMING_BETA);
        sinParams.cosOmega = _Q15(cosf(2*PI/(SAMPLES-1)));
        sinParams.sinOmega = _Q15(sinf(2*PI/(SAMPLES-1)));
        status = msp_sinusoid_q15(&sinParams, temp);
        msp_checkStatus(status);
        /* Shift sinusoid by pi/2 to create cosine function */
        copyParams.length = SAMPLES;
        status = msp_copy_q15(&copyParams, &temp[SAMPLES/4], &temp[0]);
        msp_checkStatus(status);
        /* Fill temporary array with alpha constant */
        fillParams.length = SAMPLES;
        fillParams.value = _Q15(HAMMING_ALPHA);
        status = msp_fill_q15(&fillParams, window);
        msp_checkStatus(status);
        /* Subtract generated cosine from alpha constant to generate final window */
        subParams.length = SAMPLES;
        status = msp_sub_q15(&subParams, window, temp, window);
        msp_checkStatus(status);
    }

    And the same with some modifications

    #include "msp430.h"
    
    #include <math.h>
    #include <stdint.h>
    #include <stdbool.h>
    
    #include "DSPLib.h"
    
    /* Input signal parameters */
    #define FS                  3000
    #define SAMPLES             1024
    #define SIGNAL_FREQUENCY1   90
    #define SIGNAL_AMPLITUDE1   0.6
    #define SIGNAL_FREQUENCY2   2100
    #define SIGNAL_AMPLITUDE2   0.15
    
    /* Hamming window parameters */
    #define HAMMING_ALPHA       0.53836
    #define HAMMING_BETA        0.46164
    
    /* Constants */
    #define PI                  3.1415926536
    
    ///* Generated Hamming window function */
    //DSPLIB_DATA(window,4)
    //_q15 window[SAMPLES];
    
    /* Input signal and FFT result */
    DSPLIB_DATA(input,MSP_ALIGN_FFT_Q15(SAMPLES))
    _q15 input[SAMPLES];
    
    /* Temporary data array for processing */
    //DSPLIB_DATA(temp,4)
    //_q15 temp[3*SAMPLES/2];
    
    /* Benchmark cycle counts */
    volatile uint32_t cycleCount;
    
    /* Function prototypes */
    extern void initSignal(void);
    extern void initHamming(void);
    
    void main(void)
    {
    
        /* Check that the correct revision is defined. */
        if (msp_lea_getRevision() != MSP_LEA_REVISION) {
            // The defined value of MSP_LEA_REVISION does not match LEA revision.
            __no_operation();
        }
    
        msp_status status;
        msp_mpy_q15_params mpyParams;
        msp_fft_q15_params fftParams;
    
        /* Disable WDT */
        WDTCTL = WDTPW + WDTHOLD;
        
        /* Initialize input signal and Hamming window */
        initSignal();
    //    initHamming();
    
    //    /* Multiply input signal by generated Hamming window */
    //    mpyParams.length = SAMPLES;
    //    status = msp_mpy_q15(&mpyParams, input, window, input);
    //    msp_checkStatus(status);
    
        /* Initialize the fft parameter structure. */
        fftParams.length = SAMPLES;
        fftParams.bitReverse = true;
        fftParams.twiddleTable = msp_cmplx_twiddle_table_256_q15;
    
        /* Perform real FFT with fixed scaling */
        msp_benchmarkStart(MSP_BENCHMARK_BASE, 16);
        status = msp_fft_fixed_q15(&fftParams, input);
        cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE);
        msp_checkStatus(status);
        
        // Check status flag.
                           if(status == MSP_SUCCESS)
                           {
                               // ERROR!
                               __no_operation();
                           }
                           else if (status == MSP_SIZE_ERROR)
                           {
                                       // ERROR!
                                       __no_operation();
                                   }
                           else if (status == MSP_SHIFT_SIZE_ERROR)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_TABLE_SIZE_ERROR)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_BUSY)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_INVALID_ADDRESS)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_OUT_OF_RANGE)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_SCALAR_INCONSISTENCY)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_COMMAND_OVERFLOW)
                                  {
                                              // ERROR!
                                              __no_operation();
                                          }
                           else if (status == MSP_LEA_INCORRECT_REVISION)
                                         {
                                                     // ERROR!
                                                     __no_operation();
                                                 }
                           else
                           {
                               __no_operation();
                           }
    
        /* End of program. */
        __no_operation();
    }
    
    void initSignal(void)
    {
        msp_status status;
        msp_add_q15_params addParams;
        msp_sinusoid_q15_params sinParams;
    
        /* Generate Q15 input signal 1 */
        sinParams.length = SAMPLES;
        sinParams.amplitude = _Q15(SIGNAL_AMPLITUDE1);
        sinParams.cosOmega = _Q15(cosf(2*PI*SIGNAL_FREQUENCY1/FS));
        sinParams.sinOmega = _Q15(sinf(2*PI*SIGNAL_FREQUENCY1/FS));
        status = msp_sinusoid_q15(&sinParams, input);
        msp_checkStatus(status);
    
    //    /* Generate Q15 input signal 2 to temporary array */
    //    sinParams.length = SAMPLES;
    //    sinParams.amplitude = _Q15(SIGNAL_AMPLITUDE2);
    //    sinParams.cosOmega = _Q15(cosf(2*PI*SIGNAL_FREQUENCY2/FS));
    //    sinParams.sinOmega = _Q15(sinf(2*PI*SIGNAL_FREQUENCY2/FS));
    //    status = msp_sinusoid_q15(&sinParams, temp);
    //    msp_checkStatus(status);
    
    //    /* Add input signals */
    //    addParams.length = SAMPLES;
    //    status = msp_add_q15(&addParams, input, temp, input);
    //    msp_checkStatus(status);
    }
    
    //void initHamming(void)
    //{
    //    msp_status status;
    //    msp_sub_q15_params subParams;
    //    msp_copy_q15_params copyParams;
    //    msp_fill_q15_params fillParams;
    //    msp_sinusoid_q15_params sinParams;
    //
    //    /* Generate sinusoid for cosine function */
    //    sinParams.length = 3*SAMPLES/2;
    //    sinParams.amplitude = _Q15(HAMMING_BETA);
    //    sinParams.cosOmega = _Q15(cosf(2*PI/(SAMPLES-1)));
    //    sinParams.sinOmega = _Q15(sinf(2*PI/(SAMPLES-1)));
    //    status = msp_sinusoid_q15(&sinParams, temp);
    //    msp_checkStatus(status);
    //
    //    /* Shift sinusoid by pi/2 to create cosine function */
    //    copyParams.length = SAMPLES;
    //    status = msp_copy_q15(&copyParams, &temp[SAMPLES/4], &temp[0]);
    //    msp_checkStatus(status);
    //
    //    /* Fill temporary array with alpha constant */
    //    fillParams.length = SAMPLES;
    //    fillParams.value = _Q15(HAMMING_ALPHA);
    //    status = msp_fill_q15(&fillParams, window);
    //    msp_checkStatus(status);
    //
    //    /* Subtract generated cosine from alpha constant to generate final window */
    //    subParams.length = SAMPLES;
    //    status = msp_sub_q15(&subParams, window, temp, window);
    //    msp_checkStatus(status);
    //}

    Both have the same status value.

    Best.

    Marcos.

  • In reply to Marcos Llorente:

    Hi Marcos,

    I tested out both sets of code you provided above and did not observe the issue you are experiencing. Can you provide the DPSLib version, CCS version, and MSP430FR5994 silicon revision you are working on so I can try to reproduce the issue?

    Best regards,
    Caleb Overbay

  • In reply to Caleb Overbay:

    Hi Caleb,

    Versions:

    Code Composer Studio Version: 7.2.0.00013 
    DSPLib_1_20_03_01

    I had rechecked it again, and I noticed that in the window expression the value of status variable is MSP_SUCCESS. In the code posted, there are som ifs to check the status value and the is there status == MSP_SIZE_ERROR is true while status == MSP_SUCCESS is false.

    I don't undestand why.

    Best,

    Marcos Llorente Ortega.

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.