• AVR Freaks

Hot!Can you explain the following FFT code ?

Author
indula
New Member
  • Total Posts : 10
  • Reward points : 0
  • Joined: 2019/10/19 06:35:00
  • Location: 0
  • Status: offline
2019/11/15 01:28:20 (permalink)
0

Can you explain the following FFT code ?

I've following code I got from the internet that does FFT calculation on ADC input. Could you explain the code in simple terms what it does and how the input and outputs are defined so I can understand how the code is written to edit it to my use case. Specially the ADC part of the code. 
 
/*
 * File: main.c
 * Author: irmun
 *
 * Created on November 15, 2019, 12:52 PM
 */
#include <xc.h>
#include <p30f4013.h>
#include <dsp.h>

#define FFT_BLOCK_LENGTH 256
#define LOG2_BLOCK_LENGTH 8
#define SAMPLING_RATE 10000

unsigned long counter;
fractcomplex sigCmpx[FFT_BLOCK_LENGTH] __attribute__ ((space(ymemory)));
fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2] __attribute__ ((space(xmemory)));
fractional SquareMagnitude [FFT_BLOCK_LENGTH/2];

int peakFrequencyBin = 0; /* Declare post-FFT variables to compute the */

unsigned long peakFrequency = 0; /* frequency of the largest spectral component */

void start_timer(unsigned int time_value){
    T1CONbits.TON = 0;
    TMR1 = 0;
    PR1 = time_value;
    T1CONbits.TON = 1;
    return;
}

fractional getADCValue(){
    unsigned int ADCValue;
    ADCON1bits.SAMP = 1;
    while(!ADCON1bits.DONE); //checks if conversion is done
    ADCValue = ADCBUF0;
    return ADCValue - 16384;
}

void __attribute__((interrupt, auto_psv))_T1Interrupt(void){
    if (counter < FFT_BLOCK_LENGTH){
        sigCmpx[counter].real = getADCValue();
        sigCmpx[counter].imag = 0;
    }else{
        int i = 0;
        fractional *p_real = &sigCmpx[0].real ;
        fractcomplex *p_cmpx = &sigCmpx[0] ;
        fractional *p_fract = &sigCmpx[0].real ;

        for ( i = 0; i < FFT_BLOCK_LENGTH; i++ )/* The FFT function requires input data */
        { /* to be in the fractional fixed-point range [-0.5, +0.5]*/
            *p_real = *p_real >>1 ; /* So, we shift all data samples by 1 bit to the right. */
            *p_real++; /* Should you desire to optimize this process, perform */
        } /* data scaling when first obtaining the time samples */
      /* Or within the BitReverseComplex function source code */

        p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real ; /* Set up pointers to convert real array */
        p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ; /* to a complex array. The input array initially has all */
      /* the real input samples followed by a series of zeros */
        for ( i = FFT_BLOCK_LENGTH; i > 0; i-- ) /* Convert the Real input sample array */
        { /* to a Complex input sample array */
            (*p_cmpx).real = (*p_real--); /* We will simpy zero out the imaginary */
            (*p_cmpx--).imag = 0x0000; /* part of each data sample */
        }

 /* Perform FFT operation */
        FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA);
        
 /* Store output samples in bit-reversed order of their addresses */
        BitReverseComplex(LOG2_BLOCK_LENGTH, &sigCmpx[0]);

 /* Compute the square magnitude of the complex FFT output array so we have a Real output vetor */
        SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real);
        sigCmpx[0].real = 0;
        sigCmpx[0].imag = 0;
        p_fract = &sigCmpx[0].real ; //inicia ponteiro
        for( i = 0; i < FFT_BLOCK_LENGTH/2; i++ )
        {
            SquareMagnitude [i] = *p_fract;
            *p_fract++; //incrementa o ponteiro
        }
 /* Find the frequency Bin ( = index into the SigCmpx[] array) that has the largest energy*/
 /* i.e., the largest spectral component */
        VectorMax(FFT_BLOCK_LENGTH/2, &SquareMagnitude[0], &peakFrequencyBin);
 /* Compute the frequency (in Hz) of the largest spectral component */
        peakFrequency = peakFrequencyBin*(SAMPLING_RATE/FFT_BLOCK_LENGTH);
        
        //PWM(peakFrequency*0.00465);
        if(peakFrequency < 1500){
            LATD = 0x0001;
        }else if(peakFrequency > 6000){
            LATD = 0x0004;
        }else{
            LATD = 0x0002;
        }
        counter = 0;
    }
    counter++;
    IFS0bits.T1IF = 0;
    return;
}

 
void time1_init(void){
    T1CONbits.TCS = 0;
    T1CONbits.TGATE = 0;
    T1CONbits.TCKPS = 0;
    IPC0bits.T1IP = 5;
    IFS0bits.T1IF = 0;
    IEC0bits.T1IE = 1;
    start_timer(800);
    return;
}

void init_ADC(void){
    ADCON1bits.ADSIDL = 0; //continues operation while microcontroller in idle(), 0 so it doesn't
    ADCON1bits.FORM = 3; //integer form, 1 for signed integer, 2 for fractional, 3 for signed fractional (sddd dddd dddd 0000)
    ADCON1bits.SSRC = 7; //7 for auto-convert, 0 for manual convert
    
    ADCON1bits.ASAM = 0; //0 for sampling begin when SAMP bit set, 1 for samp bit auto-step (start conversion after last one is finished)
    
    ADCON2bits.VCFG = 0; //which voltage references use for A/D
    ADCON2bits.CSCNA = 1; //0 to not scan inputs, 1 to scan inputs
    ADCON2bits.SMPI = 0; //
    ADCON2bits.BUFM = 0;
    ADCON2bits.ALTS = 0;
    
    ADCON3bits.SAMC = 1;
    ADCON3bits.ADRC = 0;
    ADCON3bits.ADCS = 21;
    
    ADCHS = 0;
    ADCSSL = 0x0001;
    ADPCFG = 0;
    
    IPC2bits.ADIP = 3;
    IEC0bits.ADIE = 0;
    IFS0bits.ADIF = 0;
    
    ADCON1bits.ADON = 1; //A/D module on, 0 for off
    
    return;
}

int main(void) {
    TwidFactorInit (LOG2_BLOCK_LENGTH, &twiddleFactors[0], 0);
    init_ADC();
    time1_init();
    //time2_init();
    //PWM_setup();
    TRISB = 0x0001; //definir que portas sao input e output
    TRISD = 0x0000;
    counter = 0;
    while(1){
        Idle();
    }
    return 0;
}

post edited by indula - 2019/11/15 01:29:41
#1

5 Replies Related Threads

    Alpha Whisky
    Super Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/10/02 07:05:22
    • Location: 0
    • Status: offline
    Re: Can you explain the following FFT code ? 2019/11/15 01:55:12 (permalink)
    5 (2)
    Waiting on a peripheral inside an interrupt service routine is a very bad idea.
     
    Calculating an FFT inside an interrupt service routine is an incredibly bad idea.
    #2
    indula
    New Member
    • Total Posts : 10
    • Reward points : 0
    • Joined: 2019/10/19 06:35:00
    • Location: 0
    • Status: offline
    Re: Can you explain the following FFT code ? 2019/11/15 04:18:57 (permalink)
    0
    Hi Alpha Whisky,
    Thank you for the reply. Why is it a bad idea?
    #3
    JPortici
    Super Member
    • Total Posts : 847
    • Reward points : 0
    • Joined: 2012/11/17 06:27:45
    • Location: Grappaland
    • Status: online
    Re: Can you explain the following FFT code ? 2019/11/15 06:01:17 (permalink)
    0
    because it takes time and the MCU won't be able to process equal or lower priority interrupts in the meantime.
    #4
    crosland
    Super Member
    • Total Posts : 1696
    • Reward points : 0
    • Joined: 2005/05/10 10:55:05
    • Location: Warks, UK
    • Status: offline
    Re: Can you explain the following FFT code ? 2019/11/15 06:04:11 (permalink)
    5 (2)
    Is this a homework assignment?
     
    What level of experience of microcontrollers and FFT do you have?
    #5
    mpgmike
    Super Member
    • Total Posts : 332
    • Reward points : 0
    • Joined: 2014/01/23 17:27:06
    • Location: NJ
    • Status: offline
    Re: Can you explain the following FFT code ? 2019/11/15 09:25:50 (permalink)
    0
    I'm going through Microchip's Online Course on DSP (while simultaneously reading a book on DSP).  The Microchip Course uses ASM to perform DSP functions.  At least the OP has shown snippets of how these ASM functions are configured in C.  I have no positive information to offer, merely a thank you.

    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
    #6
    Jump to:
    © 2019 APG vNext Commercial Version 4.5