Hi. I am facing strange problem implementing FFT on stm32f4 kit. i am using Virtual Com Port to transmit serial data which is plotted on QT (C++) platform.

The problem i am facing is that some time output is correct but most of the times wrong data is being plotted. Even when correct data is plotted still some wrong samples are

there to ruin theplot. Here is my code. Any help would be appreciated. Thanks in advance.

===== CODE =====

#define FFT_SAMPLES 2048

#define FFT_SIZE FFT_SAMPLES/2

#define FFT_TIM_PRESCALE 420-1// 100 KH-z Clock

#define FFT_TIM_PERIOD 10-1//100 KHz down to 10 Khz

#define FFT_SAMPLE_FRQ ADC_SampleTime_15Cycles

#define FFT_SAMPLE_DELAY ADC_TwoSamplingDelay_5Cycles

uint16_t fftAdc[FFT_SAMPLES/2];

float32_t fftInput[FFT_SAMPLES];

float32_t fftOutput[FFT_SIZE];

uint16_t fftInc=0;

uint16_t fftI=0;

double fftAdcValue;//after conversion -1 to +1

uint32_t fftMaxIndex;

float32_t fftMaxValue;

uint8_t fftFlag=0;

int main(void){

arm_cfft_radix4_instance_f32 FFT_InitStruc;

FFT_NVIC_ADC();

FFT_GPIO();

FFT_TIM2();

FFT_ADC();

status = arm_cfft_radix4_init_f32(&FFT_InitStruc,FFT_SIZE,0,1);

while(1){

if(fftFlag == 1){

fftFlag = 0;

arm_cfft_radix4_f32(&FFT_InitStruc,fftInput);

arm_cmplx_mag_f32(fftInput,fftOutput,FFT_SIZE);

arm_max_f32(fftOutput,FFT_SIZE,&fftMaxValue,&fftMaxIndex);

if(fftMaxIndex >= FFT_SIZE/2){

fftMaxIndex = FFT_SIZE - fftMaxIndex;

}

for(frInc=0;frInc<FFT_SIZE/2;frInc+=16){

sprintf(strPut,"#%d+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%d+%.0f+~",frInc,fftOutput[frInc],fftOutput[frInc+1],

fftOutput[frInc+2],fftOutput[frInc+3],fftOutput[frInc+4],fftOutput[frInc+5],fftOutput[frInc+6],fftOutput[frInc+7],fftOutput[frInc+8],fftOutput[frInc+9],fftOutput[frInc+10],fftOutput[frInc+11],

fftOutput[frInc+12],fftOutput[frInc+13],fftOutput[frInc+14],fftOutput[frInc+15],fftMaxIndex,fftMaxValue);

TM_USB_VCP_Puts(strPut);

Delay(7000);

}

}

}

}

void FFT_GPIO(void){

GPIO_InitStruc.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStruc.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStruc.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStruc.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA,&GPIO_InitStruc);

}

void FFT_NVIC_ADC(void){

NVIC_InitStruc.NVIC_IRQChannel = ADC_IRQn;

NVIC_InitStruc.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruc.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStruc.NVIC_IRQChannelSubPriority = 0;

NVIC_Init(&NVIC_InitStruc);

}

void FFT_TIM2(void){

TIM_DeInit(TIM2);

TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruc);

TIM_TimeBaseInitStruc.TIM_Period = FFT_TIM_PERIOD;

TIM_TimeBaseInitStruc.TIM_Prescaler = FFT_TIM_PRESCALE;

TIM_TimeBaseInitStruc.TIM_ClockDivision = 0;

TIM_TimeBaseInitStruc.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInitStruc.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruc);

TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Update);

TIM_Cmd(TIM2,ENABLE);

}

void FFT_ADC(void){

DMA_DeInit(DMA2_Stream0);

DMA_InitStruc.DMA_Channel = DMA_Channel_0;

DMA_InitStruc.DMA_PeripheralBaseAddr = (uint32_t) &ADC1->DR;

DMA_InitStruc.DMA_Memory0BaseAddr = (uint32_t) &fftAdc[0];

DMA_InitStruc.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStruc.DMA_BufferSize = FFT_SIZE;

DMA_InitStruc.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStruc.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStruc.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

DMA_InitStruc.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

DMA_InitStruc.DMA_Mode = DMA_Mode_Circular;

DMA_InitStruc.DMA_Priority = DMA_Priority_High;

DMA_InitStruc.DMA_FIFOMode = DMA_FIFOMode_Disable;

DMA_InitStruc.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

DMA_InitStruc.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMA_InitStruc.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(DMA2_Stream0,&DMA_InitStruc);

DMA_Cmd(DMA2_Stream0,ENABLE);

ADC_DeInit();

ADC_CommonInitStruc.ADC_Mode = ADC_Mode_Independent;

ADC_CommonInitStruc.ADC_Prescaler = ADC_Prescaler_Div2;

ADC_CommonInitStruc.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

ADC_CommonInitStruc.ADC_TwoSamplingDelay = FFT_SAMPLE_DELAY;

ADC_CommonInit(&ADC_CommonInitStruc);

ADC_InitStruc.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStruc.ADC_ScanConvMode = DISABLE;

ADC_InitStruc.ADC_ContinuousConvMode = DISABLE;

ADC_InitStruc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;

ADC_InitStruc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

ADC_InitStruc.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStruc.ADC_NbrOfConversion = 1;

ADC_Init(ADC1,&ADC_InitStruc);

ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,FFT_SAMPLE_FRQ);

ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);

ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);

ADC_DMACmd(ADC1,ENABLE);

ADC_Cmd(ADC1,ENABLE);

ADC_SoftwareStartConv(ADC1);

}

void ADC_IRQHandler(void){

float32_t *pData;

uint16_t *pConvertedValues;

ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);{

if(fftFlag ==0){

fftFlag = 1;

pData = &(fftInput[0]);

pConvertedValues = & (fftAdc[0]);

for(fftI =0;fftI<FFT_SIZE;fftI++){

*pData = (float32_t) ((float32_t)*pConvertedValues - (float32_t) 2048) / (float32_t) 2048;

pData ++;

*pData = 0;

pData ++;

pConvertedValues ++;

}

}

}

}

The problem i am facing is that some time output is correct but most of the times wrong data is being plotted. Even when correct data is plotted still some wrong samples are

there to ruin theplot. Here is my code. Any help would be appreciated. Thanks in advance.

===== CODE =====

#define FFT_SAMPLES 2048

#define FFT_SIZE FFT_SAMPLES/2

#define FFT_TIM_PRESCALE 420-1// 100 KH-z Clock

#define FFT_TIM_PERIOD 10-1//100 KHz down to 10 Khz

#define FFT_SAMPLE_FRQ ADC_SampleTime_15Cycles

#define FFT_SAMPLE_DELAY ADC_TwoSamplingDelay_5Cycles

uint16_t fftAdc[FFT_SAMPLES/2];

float32_t fftInput[FFT_SAMPLES];

float32_t fftOutput[FFT_SIZE];

uint16_t fftInc=0;

uint16_t fftI=0;

double fftAdcValue;//after conversion -1 to +1

uint32_t fftMaxIndex;

float32_t fftMaxValue;

uint8_t fftFlag=0;

int main(void){

arm_cfft_radix4_instance_f32 FFT_InitStruc;

FFT_NVIC_ADC();

FFT_GPIO();

FFT_TIM2();

FFT_ADC();

status = arm_cfft_radix4_init_f32(&FFT_InitStruc,FFT_SIZE,0,1);

while(1){

if(fftFlag == 1){

fftFlag = 0;

arm_cfft_radix4_f32(&FFT_InitStruc,fftInput);

arm_cmplx_mag_f32(fftInput,fftOutput,FFT_SIZE);

arm_max_f32(fftOutput,FFT_SIZE,&fftMaxValue,&fftMaxIndex);

if(fftMaxIndex >= FFT_SIZE/2){

fftMaxIndex = FFT_SIZE - fftMaxIndex;

}

for(frInc=0;frInc<FFT_SIZE/2;frInc+=16){

sprintf(strPut,"#%d+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%.0f+%d+%.0f+~",frInc,fftOutput[frInc],fftOutput[frInc+1],

fftOutput[frInc+2],fftOutput[frInc+3],fftOutput[frInc+4],fftOutput[frInc+5],fftOutput[frInc+6],fftOutput[frInc+7],fftOutput[frInc+8],fftOutput[frInc+9],fftOutput[frInc+10],fftOutput[frInc+11],

fftOutput[frInc+12],fftOutput[frInc+13],fftOutput[frInc+14],fftOutput[frInc+15],fftMaxIndex,fftMaxValue);

TM_USB_VCP_Puts(strPut);

Delay(7000);

}

}

}

}

void FFT_GPIO(void){

GPIO_InitStruc.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStruc.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStruc.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStruc.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA,&GPIO_InitStruc);

}

void FFT_NVIC_ADC(void){

NVIC_InitStruc.NVIC_IRQChannel = ADC_IRQn;

NVIC_InitStruc.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruc.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStruc.NVIC_IRQChannelSubPriority = 0;

NVIC_Init(&NVIC_InitStruc);

}

void FFT_TIM2(void){

TIM_DeInit(TIM2);

TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruc);

TIM_TimeBaseInitStruc.TIM_Period = FFT_TIM_PERIOD;

TIM_TimeBaseInitStruc.TIM_Prescaler = FFT_TIM_PRESCALE;

TIM_TimeBaseInitStruc.TIM_ClockDivision = 0;

TIM_TimeBaseInitStruc.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInitStruc.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruc);

TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Update);

TIM_Cmd(TIM2,ENABLE);

}

void FFT_ADC(void){

DMA_DeInit(DMA2_Stream0);

DMA_InitStruc.DMA_Channel = DMA_Channel_0;

DMA_InitStruc.DMA_PeripheralBaseAddr = (uint32_t) &ADC1->DR;

DMA_InitStruc.DMA_Memory0BaseAddr = (uint32_t) &fftAdc[0];

DMA_InitStruc.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStruc.DMA_BufferSize = FFT_SIZE;

DMA_InitStruc.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStruc.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStruc.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

DMA_InitStruc.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

DMA_InitStruc.DMA_Mode = DMA_Mode_Circular;

DMA_InitStruc.DMA_Priority = DMA_Priority_High;

DMA_InitStruc.DMA_FIFOMode = DMA_FIFOMode_Disable;

DMA_InitStruc.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

DMA_InitStruc.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMA_InitStruc.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(DMA2_Stream0,&DMA_InitStruc);

DMA_Cmd(DMA2_Stream0,ENABLE);

ADC_DeInit();

ADC_CommonInitStruc.ADC_Mode = ADC_Mode_Independent;

ADC_CommonInitStruc.ADC_Prescaler = ADC_Prescaler_Div2;

ADC_CommonInitStruc.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

ADC_CommonInitStruc.ADC_TwoSamplingDelay = FFT_SAMPLE_DELAY;

ADC_CommonInit(&ADC_CommonInitStruc);

ADC_InitStruc.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStruc.ADC_ScanConvMode = DISABLE;

ADC_InitStruc.ADC_ContinuousConvMode = DISABLE;

ADC_InitStruc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;

ADC_InitStruc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

ADC_InitStruc.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStruc.ADC_NbrOfConversion = 1;

ADC_Init(ADC1,&ADC_InitStruc);

ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,FFT_SAMPLE_FRQ);

ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);

ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);

ADC_DMACmd(ADC1,ENABLE);

ADC_Cmd(ADC1,ENABLE);

ADC_SoftwareStartConv(ADC1);

}

void ADC_IRQHandler(void){

float32_t *pData;

uint16_t *pConvertedValues;

ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);{

if(fftFlag ==0){

fftFlag = 1;

pData = &(fftInput[0]);

pConvertedValues = & (fftAdc[0]);

for(fftI =0;fftI<FFT_SIZE;fftI++){

*pData = (float32_t) ((float32_t)*pConvertedValues - (float32_t) 2048) / (float32_t) 2048;

pData ++;

*pData = 0;

pData ++;

pConvertedValues ++;

}

}

}

}

Realistically if you're going to use DMA, and perform an FFT on the buffer you are going to need to double the buffer size, and interrupt on the HT (Half Transfer) and TC (Transfer Complete) and process the half of the buffer that's NOT be actively loaded behind the scenes.

The FFT portion you might want to test by providing known data sets and confirming all is well there.