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.

FFT algorithm on Delfino f28335



I am trying to compute the FFT transform using the FPU lib provided in Control Suite. Let me explain my experiment: My signal generator is giving me a sinusoidal wave which ranges from 500mV to 2.5V at aproximately 937 Hz. I am computing this data with the ADC at a frequency of 48 KHz and applying the FFT algorithm on it (2833x_RFFT_ADC_RT, provided on Control Suite). Looking at RFFTmagBuff[10] I find my highest value, which is around 82 is and correct in my program because each step on this buffer is equal to 9.37 Hz, but I don't understand exactly what it means. I first use the RFFT_adc_f32u() to compute the fixed point FFT and then use the RFFT_f32_mag to compute the floating point FFT, is that correct?

Luiz Moreira

  • Luiz,

    The steps you have outlined are correct. What size FFT are you running?
  • The FFT size is 512. The code I am using is the one posted here. Can you explain me what the value in each position of the RFFTmagBuff[] means? Can you explain me how the conversion from fixed to floating point works?


    // ========================================================================
    // This software is licensed for use with Texas Instruments C28x
    // family DSCs. This license was provided to you prior to installing
    // the software. You may review this license by consulting a copy of
    // the agreement in the doc directory of this library.
    // ------------------------------------------------------------------------
    // Copyright (C) 2010-2011 Texas Instruments, Incorporated.
    // All Rights Reserved.
    // ========================================================================
    //
    // File: Main.c -- Real-time RFFT with 12-bit ADC Input Test Example
    //
    // TITLE: DSP2833x Device Real-time Real FFT Test Program.
    //
    //=========================================================================
    // DESCRIPTION:
    //
    // This program shows how to compute a real FFT with 12-bit real-time ADC
    // input and associated spectrum magnitude, phase. The input data is
    // collected by interrupt service routine function adc_isr(). The signal
    // input (can be any signal from signal generator or sensor) is excerted
    // in ADC input A0. The signal is sampled by epwm module and sampling
    // frequency is defined in Lab.h. Here is 48kHz. The dynamic range of the
    // input signal should be less than 0~3V. Real time real FFT is conducted
    // frame by frame. As long as one frame of data is collected by adc_isr,
    // it will set the FFTStartFlag. Whenever the main program detect the
    // FFTStartFlag set, the FFT calculate starts. The FFTStartFlag is cleared
    // after the calculation finished.
    //
    // The input buffer must be aligned to a multiple of the FFT size if using
    // RFFT_adc_f32. If you do not wish to align the input buffer then use the
    // RFFT_adc_f32u function. In this case, the section alignment #pragma can
    // be commented. However, using this function will reduce cycle performance
    // of the algorithm.
    //
    //
    // FUNCTIONS:
    //
    // void RFFT_adc_f32 (RFFT_ADC_F32_STRUCT *)
    // void RFFT_f32_mag (RFFT_F32_STRUCT *)
    // void RFFT_f32_phase (RFFT_F32_STRUCT *)
    //
    // Where RFFT_ADC_F32_STRUCT is a structure defined as:
    //
    // typedef struct {
    // Uint16 *InBuf;
    // void *Tail;
    // } RFFT_ADC_F32_STRUCT;
    //
    // Where RFFT_F32_STRUCT is a structure defined as:
    //
    // typedef struct {
    // float32 *InBuf;
    // float32 *OutBuf;
    // float32 *CosSinBuf;
    // float32 *MagBuf;
    // float32 *PhaseBuf;
    // Uint16 FFTSize;
    // Uint16 FFTStages;
    // } RFFT_F32_STRUCT;
    //
    // ASSUMPTIONS:
    //
    // * OutBuf of RFFT_F32_STRUCT has to be passed to Tail of
    // RFFT_ADC_F32_STRUCT
    // * Input signal is stored in Signal.asm
    // * FFTSize must be a power of 2 (32, 64, 128, etc)
    // * FFTSize must be greater or equal to 32
    // * FFTStages must be log2(FFTSize)
    // * InBuf, OutBuf, CosSinBuf are FFTSize in length
    // * MagBuf and PhaseBuf are FFTSize/2+1 in length
    // * MagBuf and PhaseBuf are not used by this function.
    // They are only used by the magitude and phase calculation functions.
    //
    // Watch Variables:
    //
    // InBuf(RFFT_ADC_F32_STRUCT) Input buffer
    // InBuf(RFFT_F32_STRUCT) Not used
    // Tail Stored the address of OutBuf
    // OutBuf Output buffer
    // CosSinBuf Twiddle factor buffer
    // MagBuf Magnitude buffer
    // PhaseBuf Phase buffer
    // j Index of normalized digital frequency component
    // freq Real analog frequency of raw signal
    //
    //###########################################################################
    // $TI Release: C28x Floating Point Unit Library V1.30 $
    // $Release Date: January 04, 2012 $
    //###########################################################################

    #include "DSP28x_Project.h" // Device Headerfile and Examples Include File
    #include "math.h"
    #include "float.h"
    #include "FPU.h"

    #define RFFT_STAGES 9
    #define RFFT_SIZE (1 << RFFT_STAGES)

    #define ADC_BUF_LEN RFFT_SIZE // ADC buffer length
    #define ADC_SAMPLE_PERIOD 3124 // 3124 = (3125-1) = 48 KHz sampling w/ 150 MHz SYSCLKOUT

    #define F_PER_SAMPLE 48000.0L/(float)RFFT_SIZE //Internal sampling rate is 48kHz

    RFFT_ADC_F32_STRUCT rfft_adc;
    RFFT_F32_STRUCT rfft;

    float32 RFFToutBuff[RFFT_SIZE]; //Calculated FFT result
    float32 RFFTF32Coef[RFFT_SIZE]; //Coefficient table buffer
    float32 RFFTmagBuff[RFFT_SIZE/2+1]; //Magnitude of frequency spectrum

    //--- Global Variables
    Uint16 AdcBuf[ADC_BUF_LEN]; // ADC buffer allocation

    volatile Uint16 FFTStartFlag = 0; // One frame data ready flag

    Uint16 DEBUG_TOGGLE = 1; // Used in realtime mode investigation

    // Prototype statements for functions found within this file.
    interrupt void adc_isr(void);

    /**********************************************************************
    * Function: main()
    *
    * Description: Main function for C2833x Real-time RFFT
    **********************************************************************/
    void main(void)
    {
    Uint16 i,j;
    float32 freq; // Frequency of single-frequency-component signal

    //--- CPU Initialization
    InitSysCtrl(); // Initialize the CPU (FILE: SysCtrl.c)
    InitGpio(); // Initialize the shared GPIO pins (FILE: Gpio.c)
    InitPieCtrl(); // Initialize and enable the PIE (FILE: PieCtrl.c)
    InitPieVectTable();

    EALLOW;
    #if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT
    #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz
    #endif
    #if (CPU_FRQ_100MHZ)
    #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz
    #endif
    EDIS;

    // Define ADCCLK clock frequency ( less than or equal to 25 MHz )
    // Assuming InitSysCtrl() has set SYSCLKOUT to 150 MHz
    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK;
    EDIS;

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    EALLOW; // This is needed to write to EALLOW protected register
    PieVectTable.ADCINT = &adc_isr;
    EDIS; // This is needed to disable write to EALLOW protected registers

    //--- Peripheral Initialization
    InitAdc(); // Initialize the ADC (FILE: Adc.c)

    rfft_adc.Tail = &rfft.OutBuf; //Link the RFFT_ADC_F32_STRUCT to
    //RFFT_F32_STRUCT. Tail pointer of
    //RFFT_ADC_F32_STRUCT is passed to
    //the OutBuf pointer of RFFT_F32_STRUCT
    rfft.FFTSize = RFFT_SIZE; //Real FFT size
    rfft.FFTStages = RFFT_STAGES; //Real FFT stages
    rfft_adc.InBuf = &AdcBuf[0]; //Input buffer
    rfft.OutBuf = &RFFToutBuff[0]; //Output buffer
    rfft.CosSinBuf = &RFFTF32Coef[0]; //Twiddle factor
    rfft.MagBuf = &RFFTmagBuff[0]; //Magnitude output buffer

    RFFT_f32_sincostable(&rfft); //Calculate twiddle factor

    //Clean up output buffer
    for (i=0; i < RFFT_SIZE; i++)
    {
    RFFToutBuff[i] = 0;
    }

    //Clean up magnitude buffer
    for (i=0; i < RFFT_SIZE/2; i++)
    {
    RFFTmagBuff[i] = 0;
    }

    // Configure ADC
    AdcRegs.ADCMAXCONV.all = 0x0000; // Setup 1 conv's on SEQ1
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // Setup ADCINA0 as 1st SEQ1 conv.
    AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;// Enable SOCA from ePWM to start SEQ1
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt (every EOS)

    // Assumes ePWM1 clock is already enabled in InitSysCtrl()
    //EPwm1Regs.TBCTR = 0; //Contador do PWM.
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
    EPwm1Regs.ETSEL.bit.SOCASEL = 4; // Select SOC from from CPMA on upcount
    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event
    EPwm1Regs.CMPA.half.CMPA = 0x0080; // Set compare A value
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // TBCLK = SYSCLKOUT
    EPwm1Regs.TBPRD = ADC_SAMPLE_PERIOD;//0xFFFF; // Set period for ePWM1
    EPwm1Regs.TBCTL.bit.CTRMODE = 0; // count up and start

    // Enable ADCINT in PIE
    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
    IER |= M_INT1; // Enable CPU Interrupt 1
    EINT; // Enable Global interrupt INTM
    ERTM; // Enable Global realtime interrupt DBGM

    //--- Enable global interrupts
    // asm(" CLRC INTM, DBGM"); // Enable global interrupts and realtime debug

    //--- Main Loop
    while(1) // endless loop - wait for an interrupt
    {
    if(FFTStartFlag) // If one frame data ready, then do FFT
    {
    RFFT_adc_f32u(&rfft_adc); // This version of FFT doesn't need buffer alignment
    RFFT_f32_mag(&rfft); // Calculate spectrum amplitude


    j = 1;
    freq = RFFTmagBuff[1];
    for(i=2;i<RFFT_SIZE/2+1;i++)
    {
    //Looking for the maximum valude of spectrum magnitude
    if(RFFTmagBuff[i] > freq)
    {
    j = i;
    freq = RFFTmagBuff[i];
    }
    }

    freq = F_PER_SAMPLE * (float)j; //Convert normalized digital frequency to analog frequency

    FFTStartFlag = 0; //Start collecting the next frame of data
    }
    asm(" NOP");
    }
    } //end of main()

    interrupt void adc_isr(void)
    {
    static Uint16 *AdcBufPtr = AdcBuf; // Pointer to ADC data buffer
    static volatile Uint16 GPIO34_count = 0; // Counter for pin toggle

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Must acknowledge the PIE group

    //--- Manage the ADC registers
    AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1 to CONV00 state
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear ADC SEQ1 interrupt flag

    //--- Read the ADC result
    *AdcBufPtr++ = AdcMirror.ADCRESULT0; // Read the result

    //--- Brute-force the circular buffer
    if( AdcBufPtr == (AdcBuf + ADC_BUF_LEN) )
    {
    AdcBufPtr = AdcBuf; // Rewind the pointer to the beginning
    FFTStartFlag = 1; // One frame data ready
    }

    //--- Example: Toggle GPIO18 so we can read it with the ADC
    if(DEBUG_TOGGLE == 1)
    {
    GpioDataRegs.GPATOGGLE.bit.GPIO18 = 1; // Toggle the pin
    }

    //--- Example: Toggle GPIO34 at a 0.5 sec rate (connected to the LED on the ControlCARD).
    // (1/48000 sec/sample)*(1 samples/int)*(x interrupts/toggle) = (0.5 sec/toggle)
    // ==> x = 24000
    if(GPIO34_count++ > 24000) // Toggle slowly to see the LED blink
    {
    GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1; // Toggle the pin
    GPIO34_count = 0; // Reset the counter
    }

    return;
    } //end of main()

    //===========================================================================
    // End of File
    //===========================================================================
  • Luiz Moreira said:
    Can you explain me how the conversion from fixed to floating point works?

    Well since you are using the 12-bit ADC and, from the code comments, looks like your dyanmic range is 0 (0x0000) to 3V (0x1000), the FFT will convert the input directly to float so 0.000 to 4095.0, it does not know the dynamic range and will not convert it.

  • Sorry Visal, I did not undersand why you said it will not convert it. Can you put in other words? Can you show me how to interpret the data stored in RFFTmagBuf[x]? For example, if I read 41 on RFFTmagBuf[10], what does it mean? If I want to know the amplitude in Volts, which conversion do I have to make? 

  • Luiz, I did some checking in the code and my earlier post was incorrect. The first stage of the FFT takes the raw adc input as unsigned int, converts it to float, and then scales it by 1/4095.0

    so f = (float)a * (1/4095.0)

    The FFT does not normalize by the size of the FFT, i.e. it does not divide the result by 512 - you need to take your bin of interest and divde by 512 before running the mag operation on it to get the true amplitude. I was able to try this out on MATLAB: here is a good post on how to do that (see the response further down the page):

    Since the FFT puts the input in the range of 0.0 to 1.0 you will have to multiply by 3V (or whatever the upper limit on your reference is)

  • Hey can I know to which pin you have given the adc input for ?
  • Hi Vishal,

    We are doing the same FFT tests with RFFT_f32() & RFFT_adc_f32() on F28377x,
    and the output of RFFT_adc_f32() seems to be 1/4095 of the RFFT_f32() result .
    Is it because RFFT_adc_f32() scales the output by 1/4095.0 as you mentioned above?

    Could you please let me know which part of the source code "1/4095.0" is executed?
    I couldn't find it in the main.c of 2837x_RFFT_ADC project.

    Best Regards
    Kummi