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.

CCS/MSP430FR5994: Modify BOOSTXL-AUDIO SHARPLCD FFT for 512 Points

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

Tool/software: Code Composer Studio

I want to process audio, so I am using the BOOSTXL-AUDIO_430BOOST-SHARPLCD_FFT_FIR_LEA_MSP430FR5994 example as a starting point. Everything works fine with the original code. I will need more points, either 512 or 1024. I have attempted to modify the code for 512 points, but it doesn't work with the LEA. For this test, I am feeding a 2.2 kHz sine into the system. Without the LEA it works, with the LEA, I get 2 peaks, the expected peak at 2.2k, but I get a second peak at 1.8k. The second peak is always 4k minus the input frequency.

The horizontal is compressed for the 512 point tests, so all 4 of these should look the same. The left two pictures are with the LEA, the right two are without. 

You can find the changes that I have made by searching for VECTOR_SIZE_256.

I am using CCS 9.3. I just downloaded the example code a few days ago.

I am using the BoostXL-Audio and the Sharp 128 x 128 LCD. 

FFT.h

/* --COPYRIGHT--,BSD
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
//******************************************************************************
//!  TI-Design Signal Processing with LEA on MSP430FR5994
//!
//!  William Goh
//!  Texas Instruments Inc.
//!  April 2016
//******************************************************************************

#ifndef FFT_H
#define FFT_H

//#define VECTOR_SIZE_256       // Comment out for 512


#ifdef VECTOR_SIZE_256
#define VECTOR_SIZE     256
#define TWIDDLE_TABLE   msp_cmplx_twiddle_table_256_q15
#else
#define VECTOR_SIZE     512
#define TWIDDLE_TABLE   msp_cmplx_twiddle_table_512_q15
#endif


//#define LOG2_SIZE       8              // Not used
//#define SQRT_SIZE       16             // Not used
//#define SCALE_FACTOR    0x00026000     // Not used

extern void initFft(void);
extern void shutdownActivity(void);
extern void runFftWithoutLea(void);
extern void runFftWithLea(void);
extern void testFft(void);

#endif /* FFT_H */

FFT.c

/* --COPYRIGHT--,BSD
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
//******************************************************************************
//!  TI-Design Signal Processing with LEA on MSP430FR5994
//!
//!  William Goh, L Reynoso
//!  Texas Instruments Inc.
//!  August 2019
//******************************************************************************

#include <driverlib.h>
#include <stdint.h>
#include <grlib.h>
#include <stdio.h>
#include <math.h>
#include "DSPLib.h"
#include "FFT.h"
#include "FFT_430.h"
#include "benchmark.h"
#include "audio_collect.h"
#include "global.h"
#include "application.h"
#ifdef __SHARP96x96__
#include "Sharp96x96.h"
#elif defined (__SHARP128x128__)
#include "Sharp128x128.h"
#endif

// Rectangular to clear my FFT image after every round
const Graphics_Rectangle clearSpace = { 0, 10, LCD_HORIZONTAL_MAX, LCD_VERTICAL_MAX-13 };
const Graphics_Rectangle clearSpaceTopText = { 0, 0, LCD_VERTICAL_MAX, 7 };
const Graphics_Rectangle clearSpaceCycleText = { 10, LCD_VERTICAL_MAX-11, 65, LCD_VERTICAL_MAX };

#if defined(__IAR_SYSTEMS_ICC__)
// Real FFT values that can be used by user application
__persistent int16_t FFT_data[VECTOR_SIZE] = {0};

// FFT buffer that contains real and imaginary values after being calculated
__persistent int16_t FBuff[VECTOR_SIZE * 2] = {0};

// raw data buffer for processing by the FFT algorithm
__persistent int16_t voice_data[VECTOR_SIZE * 2] = {0};
#elif defined(__TI_COMPILER_VERSION__)
// Real FFT values that can be used by user application
#pragma PERSISTENT(FFT_data)
int16_t FFT_data[VECTOR_SIZE] = {0};

// FFT buffer that contains real and imaginary values after being calculated
#pragma PERSISTENT(FBuff)
int16_t FBuff[VECTOR_SIZE * 2] = {0};

// raw data buffer for processing by the FFT algorithm
#pragma PERSISTENT(voice_data)
int16_t voice_data[VECTOR_SIZE * 2] = {0};
#endif

#ifdef VECTOR_SIZE_256
const int bit_rev_index[] =
{0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50,
 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48,
 0xC8, 0x28, 0xA8,
 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8,
 0x78, 0xF8, 0x04,
 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14,
 0x94, 0x54, 0xD4,
 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC,
 0x2C, 0xAC, 0x6C,
 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C,
 0xFC, 0x02, 0x82,
 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92,
 0x52, 0xD2, 0x32,
 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A,
 0xAA, 0x6A, 0xEA,
 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
 0x06, 0x86, 0x46,
 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56,
 0xD6, 0x36, 0xB6,
 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE,
 0x6E, 0xEE, 0x1E,
 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01,
 0x81, 0x41, 0xC1,
 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1,
 0x31, 0xB1, 0x71,
 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69,
 0xE9, 0x19, 0x99,
 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85,
 0x45, 0xC5, 0x25,
 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35,
 0xB5, 0x75, 0xF5,
 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
 0x1D, 0x9D, 0x5D,
 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43,
 0xC3, 0x23, 0xA3,
 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3,
 0x73, 0xF3, 0x0B,
 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B,
 0x9B, 0x5B, 0xDB,
 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
 0x27, 0xA7, 0x67,
 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77,
 0xF7, 0x0F, 0x8F,
 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F,
 0x5F, 0xDF, 0x3F,
 0xBF, 0x7F, 0xFF};
#else
const int bit_rev_index[] =
{ 0x0, 0x100, 0x80, 0x180, 0x40, 0x140, 0xC0, 0x1C0,
  0x20, 0x120, 0xA0, 0x1A0, 0x60, 0x160, 0xE0, 0x1E0,
  0x10, 0x110, 0x90, 0x190, 0x50, 0x150, 0xD0, 0x1D0,
  0x30, 0x130, 0xB0, 0x1B0, 0x70, 0x170, 0xF0, 0x1F0,
  0x8, 0x108, 0x88, 0x188, 0x48, 0x148, 0xC8, 0x1C8,
  0x28, 0x128, 0xA8, 0x1A8, 0x68, 0x168, 0xE8, 0x1E8,
  0x18, 0x118, 0x98, 0x198, 0x58, 0x158, 0xD8, 0x1D8,
  0x38, 0x138, 0xB8, 0x1B8, 0x78, 0x178, 0xF8, 0x1F8,
  0x4, 0x104, 0x84, 0x184, 0x44, 0x144, 0xC4, 0x1C4,
  0x24, 0x124, 0xA4, 0x1A4, 0x64, 0x164, 0xE4, 0x1E4,
  0x14, 0x114, 0x94, 0x194, 0x54, 0x154, 0xD4, 0x1D4,
  0x34, 0x134, 0xB4, 0x1B4, 0x74, 0x174, 0xF4, 0x1F4,
  0xC, 0x10C, 0x8C, 0x18C, 0x4C, 0x14C, 0xCC, 0x1CC,
  0x2C, 0x12C, 0xAC, 0x1AC, 0x6C, 0x16C, 0xEC, 0x1EC,
  0x1C, 0x11C, 0x9C, 0x19C, 0x5C, 0x15C, 0xDC, 0x1DC,
  0x3C, 0x13C, 0xBC, 0x1BC, 0x7C, 0x17C, 0xFC, 0x1FC,
  0x2, 0x102, 0x82, 0x182, 0x42, 0x142, 0xC2, 0x1C2,
  0x22, 0x122, 0xA2, 0x1A2, 0x62, 0x162, 0xE2, 0x1E2,
  0x12, 0x112, 0x92, 0x192, 0x52, 0x152, 0xD2, 0x1D2,
  0x32, 0x132, 0xB2, 0x1B2, 0x72, 0x172, 0xF2, 0x1F2,
  0xA, 0x10A, 0x8A, 0x18A, 0x4A, 0x14A, 0xCA, 0x1CA,
  0x2A, 0x12A, 0xAA, 0x1AA, 0x6A, 0x16A, 0xEA, 0x1EA,
  0x1A, 0x11A, 0x9A, 0x19A, 0x5A, 0x15A, 0xDA, 0x1DA,
  0x3A, 0x13A, 0xBA, 0x1BA, 0x7A, 0x17A, 0xFA, 0x1FA,
  0x6, 0x106, 0x86, 0x186, 0x46, 0x146, 0xC6, 0x1C6,
  0x26, 0x126, 0xA6, 0x1A6, 0x66, 0x166, 0xE6, 0x1E6,
  0x16, 0x116, 0x96, 0x196, 0x56, 0x156, 0xD6, 0x1D6,
  0x36, 0x136, 0xB6, 0x1B6, 0x76, 0x176, 0xF6, 0x1F6,
  0xE, 0x10E, 0x8E, 0x18E, 0x4E, 0x14E, 0xCE, 0x1CE,
  0x2E, 0x12E, 0xAE, 0x1AE, 0x6E, 0x16E, 0xEE, 0x1EE,
  0x1E, 0x11E, 0x9E, 0x19E, 0x5E, 0x15E, 0xDE, 0x1DE,
  0x3E, 0x13E, 0xBE, 0x1BE, 0x7E, 0x17E, 0xFE, 0x1FE,
  0x1, 0x101, 0x81, 0x181, 0x41, 0x141, 0xC1, 0x1C1,
  0x21, 0x121, 0xA1, 0x1A1, 0x61, 0x161, 0xE1, 0x1E1,
  0x11, 0x111, 0x91, 0x191, 0x51, 0x151, 0xD1, 0x1D1,
  0x31, 0x131, 0xB1, 0x1B1, 0x71, 0x171, 0xF1, 0x1F1,
  0x9, 0x109, 0x89, 0x189, 0x49, 0x149, 0xC9, 0x1C9,
  0x29, 0x129, 0xA9, 0x1A9, 0x69, 0x169, 0xE9, 0x1E9,
  0x19, 0x119, 0x99, 0x199, 0x59, 0x159, 0xD9, 0x1D9,
  0x39, 0x139, 0xB9, 0x1B9, 0x79, 0x179, 0xF9, 0x1F9,
  0x5, 0x105, 0x85, 0x185, 0x45, 0x145, 0xC5, 0x1C5,
  0x25, 0x125, 0xA5, 0x1A5, 0x65, 0x165, 0xE5, 0x1E5,
  0x15, 0x115, 0x95, 0x195, 0x55, 0x155, 0xD5, 0x1D5,
  0x35, 0x135, 0xB5, 0x1B5, 0x75, 0x175, 0xF5, 0x1F5,
  0xD, 0x10D, 0x8D, 0x18D, 0x4D, 0x14D, 0xCD, 0x1CD,
  0x2D, 0x12D, 0xAD, 0x1AD, 0x6D, 0x16D, 0xED, 0x1ED,
  0x1D, 0x11D, 0x9D, 0x19D, 0x5D, 0x15D, 0xDD, 0x1DD,
  0x3D, 0x13D, 0xBD, 0x1BD, 0x7D, 0x17D, 0xFD, 0x1FD,
  0x3, 0x103, 0x83, 0x183, 0x43, 0x143, 0xC3, 0x1C3,
  0x23, 0x123, 0xA3, 0x1A3, 0x63, 0x163, 0xE3, 0x1E3,
  0x13, 0x113, 0x93, 0x193, 0x53, 0x153, 0xD3, 0x1D3,
  0x33, 0x133, 0xB3, 0x1B3, 0x73, 0x173, 0xF3, 0x1F3,
  0xB, 0x10B, 0x8B, 0x18B, 0x4B, 0x14B, 0xCB, 0x1CB,
  0x2B, 0x12B, 0xAB, 0x1AB, 0x6B, 0x16B, 0xEB, 0x1EB,
  0x1B, 0x11B, 0x9B, 0x19B, 0x5B, 0x15B, 0xDB, 0x1DB,
  0x3B, 0x13B, 0xBB, 0x1BB, 0x7B, 0x17B, 0xFB, 0x1FB,
  0x7, 0x107, 0x87, 0x187, 0x47, 0x147, 0xC7, 0x1C7,
  0x27, 0x127, 0xA7, 0x1A7, 0x67, 0x167, 0xE7, 0x1E7,
  0x17, 0x117, 0x97, 0x197, 0x57, 0x157, 0xD7, 0x1D7,
  0x37, 0x137, 0xB7, 0x1B7, 0x77, 0x177, 0xF7, 0x1F7,
  0xF, 0x10F, 0x8F, 0x18F, 0x4F, 0x14F, 0xCF, 0x1CF,
  0x2F, 0x12F, 0xAF, 0x1AF, 0x6F, 0x16F, 0xEF, 0x1EF,
  0x1F, 0x11F, 0x9F, 0x19F, 0x5F, 0x15F, 0xDF, 0x1DF,
  0x3F, 0x13F, 0xBF, 0x1BF, 0x7F, 0x17F, 0xFF, 0x1FF  };
#endif

uint16_t i, index;
int16_t imag, real, real_abs, imag_abs, mag, max, min;
int16_t scale;

msp_cmplx_fft_q15_params complexFftParams;

static uint8_t refreshDisp = 0;
static int8_t str[20];

void initFft(void)
{
    resetBenchmark();

    // Disable the audio playback for lowest power configuration
    Audio_stopPlayback(&gPlaybackConfig);

    // Initializes the FFT parameters
    complexFftParams.length = VECTOR_SIZE;
    complexFftParams.bitReverse = 1;
//    complexFftParams.twiddleTable = msp_cmplx_twiddle_table_256_q15;
    complexFftParams.twiddleTable = TWIDDLE_TABLE;

    // Initialize the microphone for recording
    gAudioConfig.audioBuffer1 = (int16_t *) adcBuffer0;
    gAudioConfig.audioBuffer2 = (int16_t *) adcBuffer1;
    gAudioConfig.bufferSize = VECTOR_SIZE;
    gAudioConfig.sampleRate = FFT_SAMPLING_FREQUENCY;
    gAudioConfig.twosComplement = true;
    Audio_setupCollect(&gAudioConfig);

    // Start the recording by enabling the timer
    Audio_startCollect(&gAudioConfig);
}

/**********************************************************************//**
 * @brief  Runs the FFT. Performs the FFT and puts it in FFT_data buffer.
 *
 * @param  none
 *
 * @return none
 *************************************************************************/

void runFftWithoutLea(void)
{
    int16_t * currentAdcBuffer;

    // Initialize the number of times to refresh the display
    refreshDisp = 2;

    // Clear the screen first
    Graphics_clearDisplay(&g_sContext);

    // Draw the basic structure
    GrStringDraw(&g_sContext, "0",
                 AUTO_STRING_LENGTH, 1, LCD_VERTICAL_MAX-10,
                 TRANSPARENT_TEXT);
    GrStringDraw(&g_sContext, "Fs 2",
                 AUTO_STRING_LENGTH, 70, LCD_VERTICAL_MAX-10,
                 TRANSPARENT_TEXT);
    GrLineDrawH(&g_sContext, 0, LCD_VERTICAL_MAX, LCD_VERTICAL_MAX-12);

    // Draw the title once
    Graphics_drawString(&g_sContext, "FFT w/o LEA",
                        AUTO_STRING_LENGTH, 0, 0,
                        GRAPHICS_OPAQUE_TEXT);

    // Flush Buffer to LCD
    Graphics_flushBuffer(&g_sContext);

    keepAppRunning = true;

    while(keepAppRunning)
    {
        __bis_SR_register(LPM3_bits + GIE);

        // Copy recorded ADC data to LEA RAM buffer for FFT processing
        currentAdcBuffer = Audio_getActiveBuffer(&gAudioConfig);

        for(i = 0; i < (VECTOR_SIZE); i++)
        {
            ((int32_t *)voice_data)[i] = currentAdcBuffer[i];
        }

        resetBenchmark();
        startBenchmark();

        // Perform FFT and store
        FFT_prog();

        stopBenchmark();

        // Calculate magnitude for the positive frequency domain
        for(i = 0; i < (VECTOR_SIZE / 2); i++)
        {
            index = bit_rev_index[i];
            real = FBuff[2 * index];
            imag = FBuff[2 * index + 1];
            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[i] = mag;
        }

#ifndef PWR_BENCHMARK
        if(refreshDisp)
        {
            sprintf((char *) str, "Cyc:%lu", cycleCounts);
        }

        // Clear the lines by drawing a box
        Graphics_setForegroundColor(&g_sContext, ClrWhite);
        Graphics_fillRectangle(&g_sContext, &clearSpace);
        if(refreshDisp)
        {
            Graphics_fillRectangle(&g_sContext, &clearSpaceCycleText);
        }
        Graphics_setForegroundColor(&g_sContext, ClrBlack);
        if(refreshDisp)
        {
            Graphics_drawString(&g_sContext, str,
                                AUTO_STRING_LENGTH, 10, LCD_VERTICAL_MAX-10,
                                GRAPHICS_OPAQUE_TEXT);
            refreshDisp--;
        }

        // Draw the FFT magnitudes but restricting it to only 96 pixel screen
        for(i = 0; i < LCD_HORIZONTAL_MAX; i++)
        {
            // Restricting it to only 96 pixel screen
            if(i < LCD_HORIZONTAL_MAX)
            {

#ifdef VECTOR_SIZE_256
                // set the scale and restrict it to the size of the display
                scale = ((FFT_data[i]) >> 6);
#else // 512
                // Set the scale and restrict it to the size of the display
                // Since we have 256 data points and the display is only 128 wide, compress by 2
                scale = ((FFT_data[i*2] + FFT_data[i*2+1]) >> 6);
#endif

                // Check if is out of bounds.
                if(scale < 0)
                {
                    scale = 12;
                }
                else if(scale > LCD_VERTICAL_MAX-24)
                {
                    scale = LCD_VERTICAL_MAX-25;
                }

                if(scale != 0)
                {
                    // Draw each line only if scale the mag is 0 pixels
                    Graphics_drawLineV(&g_sContext, i, LCD_VERTICAL_MAX-13, LCD_VERTICAL_MAX- 13 - scale);
                }
            }
        }

        // Flush this content to display
        Graphics_flushBuffer(&g_sContext);
#endif
    }

    Audio_stopCollect(&gAudioConfig);
    Audio_shutdownCollect(&gAudioConfig);
}

void runFftWithLea(void)
{
    msp_status status;
    uint16_t i;
    int16_t * currentAdcBuffer;

    // Initialize the number of times to refresh the display
    refreshDisp = 2;

    // Clear the screen first
    Graphics_clearDisplay(&g_sContext);

    // Draw the basic structure
    GrStringDraw(&g_sContext, "0",
                 AUTO_STRING_LENGTH, 1, LCD_VERTICAL_MAX-10,
                 TRANSPARENT_TEXT);
    GrStringDraw(&g_sContext, "Fs 2",
                 AUTO_STRING_LENGTH, 70, LCD_VERTICAL_MAX-10,
                 TRANSPARENT_TEXT);
    GrLineDrawH(&g_sContext, 0, LCD_HORIZONTAL_MAX, LCD_VERTICAL_MAX-12);

    // Draw the title once
    GrStringDraw(&g_sContext, "FFT w/ LEA",
                 AUTO_STRING_LENGTH, 0, 0,
                 GRAPHICS_OPAQUE_TEXT);

    // Flush Buffer to LCD
    Graphics_flushBuffer(&g_sContext);

    // Initialize LEA module
    initFft();

    keepAppRunning = true;

    while(keepAppRunning)
    {
        __bis_SR_register(LPM3_bits + GIE);

        // Get the latest buffer pointer to be copied
        currentAdcBuffer = Audio_getActiveBuffer(&gAudioConfig);

        // Copy recorded ADC data to LEA RAM buffer for FFT processing
        for(i = 0; i < (VECTOR_SIZE); i++)
        {
            ((int32_t *)leaMemoryStartAdd.fftDataParam.fftInputOutput)[i] =
                currentAdcBuffer[i] & 0x0000FFFF;
        }

        resetBenchmark();
        startBenchmark();

        // Call fixed scaling fft function.
        status = msp_cmplx_fft_fixed_q15(&complexFftParams,
                                         leaMemoryStartAdd.fftDataParam.fftInputOutput);

        // Check status flag.
        if(status != MSP_SUCCESS)
        {
            // ERROR!
            __no_operation();
        }

        stopBenchmark();

        // Calculate magnitude for the positive frequency domain
        for(i = 0; i < (VECTOR_SIZE / 2); i++)
        {
            real = leaMemoryStartAdd.fftDataParam.fftInputOutput[2 * i];
            imag = leaMemoryStartAdd.fftDataParam.fftInputOutput[2 * i + 1];
            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[i] = mag;
        }

#ifndef PWR_BENCHMARK
        // Refresh the display
        if(refreshDisp)
        {
            sprintf((char *) str, "Cyc:%lu", cycleCounts);
        }

        // Clear the lines by drawing a box
        Graphics_setForegroundColor(&g_sContext, ClrWhite);
        if(refreshDisp)
        {
            Graphics_fillRectangle(&g_sContext, &clearSpaceCycleText);
        }
        Graphics_fillRectangle(&g_sContext, &clearSpace);
        Graphics_setForegroundColor(&g_sContext, ClrBlack);
        if(refreshDisp)
        {
            Graphics_drawString(&g_sContext, str,
                                AUTO_STRING_LENGTH, 10, LCD_VERTICAL_MAX-10,
                                GRAPHICS_OPAQUE_TEXT);
            refreshDisp--;
        }

        // Draw the FFT magnitudes but restricting it to only 96 pixel screen
        for(i = 0; i < LCD_HORIZONTAL_MAX; i++)
        {

#ifdef VECTOR_SIZE_256
            // set the scale and restrict it to the size of the display
            scale = ((FFT_data[i]) >> 6);
#else // 512
            // Set the scale and restrict it to the size of the display
            // Since we have 256 data points and the display is only 128 wide, compress by 2
            scale = ((FFT_data[i*2] + FFT_data[i*2+1]) >> 6);
#endif

            // Check if is out of bounds.
            if(scale < 0)
            {
                scale = 12;
            }
            else if(scale > LCD_VERTICAL_MAX-24)
            {
                scale = LCD_VERTICAL_MAX-25;
            }

            if(scale != 0)
            {
                // Draw each line only if scale the mag is 0 pixels
                Graphics_drawLineV(&g_sContext, i, LCD_VERTICAL_MAX-13, LCD_VERTICAL_MAX-13 - scale);
            }
        }

        // Flush this content to display
        Graphics_flushBuffer(&g_sContext);
#endif
    }
}

  • Hi Matthew,

    I downloaded a tone generator app to my phone and was able to test the project with 256 and 512 vector size. It looks like there are actually some lower frequency harmonics present even with a vector size of 256.  I'm wondering if the issue is related to how the data is getting formatted from LEA. 

    I'm not seeing the same artifacts that you've posted with a vector size of 512.  I'm seeing that lower harmonic with the graph cut in half. I built my project with CCS v8.2.

    BR,
    Leo

    BR,
    Leo

  • Just to be sure that it isn't a hardware issue, I tried a second setup with a different FR5994, different Boost-Audio, and a Sharp 96 x 96 LCD (since that is what you have). Same result.

    The spurious peak is almost the same size as the proper peak; I am seeing something different from what you are experiencing.

    It is always 4 kHz minus the input frequency. There is some weird frequency fold-back going on. It never happens without the LEA.

    Are you using the exact DSPLib that is included in the example? Is there a bug in some of the DSPLibraries?

    Thanks.

  • Hi Matthew,

    While it's possible that there could be a bug in our DSP libraries, the more likely case is that there is a bug somewhere in the application code (or in our tools).   Have you tried building with IAR?

    BR,
    Leo

  • On a hunch, I played with the linker settings and got it to work properly. From what I read about the alignment requirements, the default follows the alignment rules for a vector size of 512 (memory size of 1k), the original should work.

    Can you explain why this fixed the issue?  I am OK now, but the next person may get frustrated and find another MCU.

    Why doesn't the third choice compile?  2k should be enough shared memory.

    Thanks.

    /****************************************************************************/
    /* Specify the LEA memory map                                               */
    /****************************************************************************/
    
    #define LEASTACK_SIZE   0x138
    
    MEMORY
    {
    //    LEARAM                  : origin = 0x2C00, length = 0x1000 - LEASTACK_SIZE        // Original, has spurious spike at 4kHz - input freq (foldback issue)
        LEARAM                  : origin = 0x3000, length = 0xC00 - LEASTACK_SIZE           // Works correctly, fixes foldback issue
    //    LEARAM                  : origin = 0x3400, length = 0x800 - LEASTACK_SIZE         // Won't compile, won't fit
        LEASTACK                : origin = 0x3C00 - LEASTACK_SIZE, length = LEASTACK_SIZE
    }
    

  • Hi Matthew,

    In application.c replace

    #pragma DATA_SECTION(leaMemoryStartAdd, ".leaRAM") 

    with

    DSPLIB_DATA(leaMemoryStartAdd,MSP_ALIGN_FFT_Q15(VECTOR_SIZE * 2))

    This was a bug in the application code.

    BR,
    Leo