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 Not working

Other Parts Discussed in Thread: CONTROLSUITE, CCSTUDIO

I am using the sample DSP code which allows you to take an ADC signal and compute an FFT. The ADC part of the code is working however the FFT results are incorrect.

I am inputting a sine wave into the microcontroller.

Thanks.

 

  • Hi Ava,

    If you could post the graphed ADC sampled signal and the FFT output, I can try and debug on my end.

  • Thanks for the  help. If you need the code, let me know.

  • Yes, could you post the code as well. What is the input signal voltage and frequency.. I cant make out from the graph?

  •  

    I am inputting 1000 Hz at 2.0 V.  Below is my code:

     

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


    #define FFT_REAL_STAGES 9


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

    RFFT_ADC_F32_STRUCT rfft_adc;
    RFFT_F32_STRUCT rfft;

    #pragma DATA_SECTION(FFTReal_out,"FFTReal_Output");
    #pragma DATA_SECTION(FFTReal_CosSinTable,"FFTReal_CosSin");
    #pragma DATA_SECTION(FFTReal_Magnitude,"FFTReal_Magnitude");


    float32 FFTReal_out[FFT_REAL_SIZE];                //Calculated FFT result
    float32 FFTReal_CosSinTable[FFT_REAL_SIZE];        //Coefficient table buffer
    float32 FFTReal_Magnitude[FFT_REAL_SIZE/2+1];      //Magnitude of frequency spectrum


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

    // Global variables used in this example:
    Uint16 LoopCount;
    Uint16 ConversionCount;

    Uint16 DEBUG_TOGGLE =1;

    Uint16 SampleTable[FFT_REAL_SIZE];

    int FFTStart =0; 


    main()
    {


    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the DSP2833x_SysCtrl.c file.
       InitSysCtrl();


       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;

    // Step 2. Initialize GPIO:
    // This example function is found in the DSP2833x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();  // Skipped for this example

    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
       DINT;

    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the DSP2833x_PieCtrl.c file.
       InitPieCtrl();
     

    // Disable CPU interrupts and clear all CPU interrupt flags:
       IER = 0x0000;
       IFR = 0x0000;

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in DSP2833x_DefaultIsr.c.
    // This function is found in DSP2833x_PieVect.c.
       InitPieVectTable();

    // 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

    // Step 4. Initialize all the Device Peripherals:
    // This function is found in DSP2833x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       InitAdc();  // For this example, init the ADC


    // Step 5. User specific code, enable interrupts:

    // 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


       LoopCount = 0;


    // Configure ADC
       AdcRegs.ADCMAXCONV.all = 0x0000;       // Setup 2 conv's on SEQ1
       AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // Setup ADCINA3 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.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.TBPRD = 0xFFFF;              // Set period for ePWM1
       EPwm1Regs.TBCTL.bit.CTRMODE = 0;    // count up and start


    // 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


     //Clear input buffer 
     for(i=0; i< FFT_REAL_SIZE; i++)
     {
      SampleTable[i]=0;

     }

      //FFT Declarations
       rfft_adc.Tail = &rfft.OutBuf;
       rfft.FFTSize =FFT_REAL_SIZE;
       rfft.FFTStages = FFT_REAL_STAGES;

       rfft_adc.InBuf = &SampleTable[0];
       rfft.OutBuf=&FFTReal_out[0];
       rfft.CosSinBuf = &FFTReal_CosSinTable[0]; //Twiddle factor
       rfft.MagBuf = &FFTReal_Magnitude[0];  //Magnitude output buffer

       RFFT_f32_sincostable(&rfft);      //Calculate twiddle factor
     
      //Clean up output buffer
        for (i=0; i < FFT_REAL_SIZE; i++)
        {
          FFTReal_out[i] = 0;
        }
      
        //Clean up magnitude buffer
        for (i=0; i < FFT_REAL_SIZE/2; i++)
        {
          FFTReal_Magnitude[i] = 0;
        } 


    // Wait for ADC interrupt
       for(;;)
       {
          LoopCount++;

       if(FFTStart ==1)
       {

      RFFT_adc_f32(&rfft_adc);
      RFFT_f32_mag(&rfft);

      FFTStart=0;

      }


     }
    }

    interrupt void  adc_isr(void)
    {
    for(i=0; i<512; i++)
    { 

     SampleTable[i] = ((AdcRegs.ADCRESULT0 >>4));  //>>4 shifts data to right by 4 places
    }
    if(i==512)
     {
      FFTStart =1;
     
      }

      // Reinitialize for next ADC sequence
     AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;         // Reset SEQ1
     AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;       // Clear INT SEQ1 bit
     PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;   // Acknowledge interrupt to PIE

      return;

    }

  • If the first graph is the signal and the second graph is the FFT then it actually looks like it is working properly. Without having time to look at the code in depth it looks like you have both the positive and negative spectras in your result, which creates the four peaks (one at DC, one at the actual frequency x2 [for +ve and -ve spectra] ).  I think (you may need to do some experimenting to verify this) that if you just take the first 256 samples of your FFT output you should have the result you are looking for.

    Tim

  • Hi Tim,

    When I try putting a straight dc voltage (no sine wave) into the ADC I don't get the vertical representation on the FFT graph.

    Thanks.

  • Ava,

    Since the verticle should be a the axis is there a chance the graph is cutting it off?  As Tim mentioned the DC component is showing up in your graph.

    Perhaps this is not crucial to this forum post, but I am curious as to the signal input range shown on the other graph, is there a reason to only use 300 codes of the FSR of the converter.  This will ultimately effect the SNR you can achieve.

     

    Best,

    Matthew

  • Hi Matthew,

    I'm not really understanding your question in depth, but there is a chance that the graph is cutting off.

  • In controlSUITE folder. There is one FFT example code for testing real time FFT with ADC input. Did you test that code or you just wrote you own code? I tested that code it was working properly with 28335 evaluation board.

    You can find that example code in controlSUITE/libs/dsp/FPU/v120/examples_ccsv4/2833x_RFFT_ADC_RT. If that example code is not working on your testbench, then there might be your CCS setup problem.

     

  • Yes I did use that example. The only issue is that I am using CCStudio 3.3 not 4 so I had to make the necessary changes to make that example work. I'm thinking that the issue I am having now is mainly understanding the graphs. When I change the amplitude and frequency the FFT graph basically stays the same - when I plot the magnitude and the fft out portions. From my understanding the x-axis represents the sample number.

     

    Thanks.

  • x-axis (frequency domain) represents frequency normalized by sampling frequency and sampled by fft size. for example, your raw sinusoidal signal frequency F, and your sampling frequency Fs, and your FFT size is 1024, Then the x-axis sample interval equals to 2*pi*F/Fs/1024.

    if you signal frequency is 1KHz, sampling frequency is 48KHz, then the spike of sinusoidal wave should be in 1/48*1024=21.33, should be between 21 to 22 points.

    x-axis(time domain), if you raw signal is sin(2*pi*F*t), then your sampled data should be sin(2*pi*F/Fs*n); If still not clear, you can use matlab to simulate these sampled signal. (if you have matlab).

    At least make sure the time domain signal changes with your signal generator and then adjust the amplitude and frequency. Finally check the frequency domain. If the signal is single-end signal with DC components, a big spikes certainly will show up at 0 position in x-axis.

     

     

  • I'm still having trouble with this. The other peaks from the graph are at the same magnitude as the DC component of the signal. If I am inputting a frequency with a DC component of 2 Volts, I don't understand why the graph shows 750 when the x-axis equals zero. Is there a scaling issue going on?  

    My first peak at the x-axis seems to be accurate to what is calculated. My main problem is verfying that the FFT actually works using the graphs.  

    Any additional help is greatly appreciated.

  • the amplitude in the position of x-axis=0 is linearly related to the DC component. You can change the DC offset to see the change of amplitude in x-axis=0. Or you can use matlab to simulate the signal to get the X(0) (frequency domain).

  • There is likely to be a scaling issue somewhere, I have always had problems scaling FFTs in the past.

    There are two ways to verify the FFT:

    1) Use CCS's FFT.  Instead of (or even as well as) plotting single time graphs, plot FFTs of the raw data.  This will compute an FFT on your computer and you can compare it to this.

    2) Input some deterministic data.  For example, try inputting clean DC and see what you get and input a sine wave at quarter sampling frequency and see what you get. 

    If you need help deciphering your results just repost the graphs and I am sure myself and others can help.

    Tim

  • Thanks Tim. Attached are the graphs for your #1.
    1000 Hz; 2V input; 1 VDC offset.docx
  • I've been constantly working on this and I am still having trouble. It looks like when I have no generated signal input into the ADC pin there is still a sine wave being displayed on the CCStudio graphs. Could this noise be a problem with the results I am getting?

  • use ur oscilliscope to  check the ADC input pin. if there is signal over there. that means ur ADC is not setting up correctly.

  • Thanks Yu. I checked the ADC pin using the oscilliscope and there is a signal shown even though I'm not inputting one from the signal generator. Could this be an issue with my code?

     

    Thanks.

  • Disregard my previous post. When the oscilloscope is connected directly to the ADC pin and not going through the connection of the signal generator as well, there is no waveform being shown on the oscilliscope. When the signal generator is connected there is a waveform shown even with the output not on.

    I guess my main problem is still interpreting the graphs.

  • that means u do not ground ur probe very well.

  • I was able to fix that problem.

  • I have had a brief look at your graphs and your code but can not find any immediate faults.  I will probably run my own code up when I get a chance (in a few days time).  In the meantime I suggest you take the ADC out of the equation by following these steps.

    1) Disable your ADC code, or at least where it transfers data to SampleTable.  Just  comment these lines out for now.

    2) Create a sine wave in Sampletable by using the sin tables in the OTP ROM.

    3) Pass this through the FFT and see if you get a nice clean peak.

    4) For more checks I suggest you try sine waves of different frequencies and amplitudes.

    5) Finally make Sampletable all the same value (i.e. DC) and try that. 

    If you post your sampletable and your FFT result graphs for different sine waves and DC then we can look over them.

    Tim