Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

FFT for ADC output using dsPIC30F dsp library

Status
Not open for further replies.

helmi_mjd

Member level 2
Member level 2
Joined
Feb 20, 2011
Messages
45
Helped
2
Reputation
4
Reaction score
2
Trophy points
1,288
Activity points
1,668
Hi guys,
I have one question related to FFT computation in dsPIC30F4013. Below is the code I used (basically from example CE018 C30 compiler) but with input signal from ADC pin. However, i got incorrect result. Please anybody could help me resolve this issue and check whether i make mistake in my code. I'm using MPLAB IDE and C30 comipiler.

Thanks in advance.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Include the neccesary header files
#include <p30F4013.h>
#include <dsp.h>
#include <stdio.h>
#include <math.h>
#include "system.h"
#include "lcd.h"
#include "delay.h"
#include "uart.h" 
#include "adc.h"
 
/*******************************************************************************
* DEVICE CONFIGURATION WORDS                                                   *
*******************************************************************************/
 
_FOSC(CSW_FSCM_OFF & XT_PLL8);                  // Primary Oscillator Mode = XT with PLL 8x.
                                        // Clock Switching and Monitor = Off.
_FWDT(WDT_OFF);                         // Watchdog Timer = Off.
_FBORPOR(PBOR_OFF & PWRT_64 & MCLR_EN);                 // Brown Out Reset = Off. POR Timer Value = 64ms. 
                                        // Master Clear = Enabled. 
_FGS(CODE_PROT_ON);                             // Code Protection = On.
 
 
/*******************************************************************************
* PRIVATE FUNCTION PROTOTYPES                                                  *
*******************************************************************************/
 
void lcd_1stline_msg(const char* csz_string);
void lcd_2ndline_msg(const char* csz_string);
void alert_lamp (void);
void test_uart1 (void);
void test_uart2 (void);
void test_uart1a (void); 
 
//Extern definition
extern fractcomplex sigCmpx[FFT_BLOCK_LENGTH]       // Typically, the input signal to an FFT  
__attribute__ ((section (".ydata, data, ymemory"),          // routine is a complex array containing samples
aligned (FFT_BLOCK_LENGTH * 2 *2)));                // of an input signal. For this example,
                                        // we will provide the input signal in an
                                        // array declared in Y-data space.
 
/*******************************************************************************
* Global Variables                                                             *
*******************************************************************************/
 
unsigned char c_received_data = 0;          // data received through UART
int peakFrequencyBin = 0;                   // Declare post-FFT variables to compute the 
unsigned long peakFrequency = 0;                   // frequency of the largest spectral component 
 
// Global Definitions
#ifndef FFTTWIDCOEFFS_IN_PROGMEM
fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2]             // Declare Twiddle Factor array in X-space
__attribute__ ((section (".xbss, bss, xmemory"), aligned (FFT_BLOCK_LENGTH*2)));
#else
extern const fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2]    // Twiddle Factor array in Program memory
__attribute__ ((space(auto_psv), aligned (FFT_BLOCK_LENGTH*2)));
#endif
 
fractcomplex sigCmpx[FFT_BLOCK_LENGTH] __attribute__ ((section (".ydata, data, ymemory"), aligned (FFT_BLOCK_LENGTH * 2 *2))) ={0};
 
 
/*******************************************************************************
* MAIN FUNCTION                                                                *
*******************************************************************************/
 
int main(void) 
{
    int i = 0;                          // FFT size index
    unsigned int ADC_val[]={0};
 
    // Clear all ports.
    LATA = 0;
    LATB = 0;
    LATC = 0; 
    LATD = 0;
    LATF = 0;
    
    // Initialize I/O directions.
    TRISA = 0;                  // PORTA
    TRISAbits.TRISA11 = 1;      // SW1 is connected at RA11
    TRISB = 0;
    TRISC = 0;
    TRISD = 0;
    TRISDbits.TRISD8 = 1;       // SW2 is connected at RD8  
    TRISF = 0;
    TRISBbits.TRISB12 = 1;      // ADC input PIN as B12 [AN12]
    
    lcd_initialize();           // initialize LCD
    lcd_clear();                // clear LCD
     
    config_module_adc();        // configure ADC module    
    change_channel_adc(12);     // AN12 channel [1100=12] 
 
// Acquire signal from ADC pin   
  
    for (i=0;i<FFT_BLOCK_LENGTH;i++){
        ADC_val[i] = sampling_and_conversion_adc();     // get ADC value
        sigCmpx[i].real = Float2Fract(ADC_val[i]);      // replace real part with ADC value
        sigCmpx[i].imag = 0;                            // set imiginary part with 0
    }
 
    // the ADC value in float format. So we need to change to fractional format for
    // library compatibality
 
 
// FFT computation
    
    fractional *p_real = &sigCmpx[0].real ;     // initialize real pointer
    fractcomplex *p_cmpx = &sigCmpx[0] ;        // initialize imaginary pointer
 
    #ifndef FFTTWIDCOEFFS_IN_PROGMEM                                // Generate TwiddleFactor Coefficients 
        TwidFactorInit (LOG2_BLOCK_LENGTH, &twiddleFactors[0], 0);  // We need to do this only once at start-up 
    #endif
 
    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
    #ifndef FFTTWIDCOEFFS_IN_PROGMEM
        FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA);
    #else
        FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));
    #endif
 
    // 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);
 
    // 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, &sigCmpx[0].real, &peakFrequencyBin);
 
    // Compute the frequency (in Hz) of the largest spectral component 
    peakFrequency = peakFrequencyBin*(SAMPLING_RATE/FFT_BLOCK_LENGTH);
 
    for (i=0; i<FFT_BLOCK_LENGTH;i++)
    {       
        lcd_1stline_msg("FFT num : ");              // display the adc value
        lcd_2ndline_msg("ADC val : ");              // display the decibel value    
        lcd_goto(0x80+10);                          // jump to the desired position on lcd
        lcd_bcd(4, sigCmpx[i].real);                // write adc value to lcd
        lcd_goto(0xC0+10);                          // jump to the desired position on lcd
        lcd_bcd(4, peakFrequency);                  // write dB value to lcd
        delay_ms(500);  
        lcd_clear();
    } 
 
     while (1); // Place a breakpoint here and observe the watch window variables
}

 
Last edited by a moderator:

dear how you say that results are not correct.
can you share the results and circuit diagram please.
 

dear how you say that results are not correct.
can you share the results and circuit diagram please.

Thanks shahbaz for your reply. I just discovered that the ADC value is incorrect. I don't know why the value is larger than 4096 (12 bits ADC). By the way, do you think my code is correct? Especially when I read ADC value into the array sigCmpx. My ADC code are as follow:

Code:
#include <p30F4013.h>
#include <libpic30.h>
#include "ADC.h"
#include "delay.h"
#include "system.h"

/********************************************************************************/

void config_module_adc(void)
{
    ADCON1bits.ADON = 0;		// adc module OFF
    ADCON3bits.ADRC = 0;		// adc clock is derived from system clock
    ADCON3bits.SAMC = 0b11111;	// auto sample Time at 31 TAD
    ADCON3bits.ADCS = 0b000000;	// conversion clock which is Tcy/2. (2.5 MHz in this case)

    ADCON2bits.CSCNA = 0;		// scanning inputs OFF
    ADCON2bits.BUFS = 0;		// filling buffer 0
    ADCON2bits.SMPI = 0b0000;	// interrupt at completion of sampling and conversion
    ADCON2bits.BUFM = 0;		// one 16 bit buffer
    ADCON2bits.ALTS = 0;		// no alternate settings (MUX A)

    ADCON1bits.ADSIDL = 0;		// continue module in idle mode
    ADCON1bits.FORM = 0b10;		// data output type 1 selected integer type	
    ADCON1bits.SSRC = 0b000;	// conversion trigger at SAMP bit
    ADCON1bits.ASAM = 0;		// sampling begins by setting SAMP bit

    ADPCFG = 0xFFFF;			// ADPCFG Register 
    ADPCFGbits.PCFG12 = 0;		// Set up channels AN12 as analog input and configure rest as digital
	
}
/********************************************************************************/

void change_channel_adc(unsigned char channel)
{
    ADCON1bits.ADON = 0;                       // adc off      
    delay_ms(1);
    ADCHSbits.CH0SA = (channel & 0b00011111);  // channel changed 
    delay_ms(1);
    ADCON1bits.ADON = 1;                       // adc on          

}
/*******************************************************************************/

unsigned int sampling_and_conversion_adc(void)
{
    ADCON1bits.SAMP = 1;                       // start sampling input    
    while(!ADCON1bits.SAMP);
    ADCON1bits.SAMP = 0;                       // end sampling 
    while(ADCON1bits.SAMP);
    while(!ADCON1bits.DONE);
    return ADCBUF0;
}
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top