2013-04-15 05:53 AM
Hi there,
I am writing my Bachelorthesis and have to calculate the FFT on the STM32F4. The Input Signal comes from a Radarsensor and is added with quite a lot of noise. My Radarsensor is powered with a triangular Voltage fom 0,5 to 5,0V. At the Output of the Radarsensor I get the difference of the input and output signal. Now I want to measure during the up chirp and during the down chirp. After this is done I want to calculate the FFT of both signals, so I can compare them. My ADC and my DAC are triggered with the same Timer:void TIM2Init() //42 MHz
{ TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure); TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = (20)-1; TIM_TimeBaseInitStructure.TIM_Prescaler = (1)-1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); }void ADCInit()
{ ADC_CommonStructInit(&ADC_CommonInitStructure); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler =ADC_Prescaler_Div4; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_15Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_Init(ADC_I_SIGNAL, &ADC_InitStructure); } void DACInit(uint32_t DAC_Channel) { DAC_DeInit(); DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel, &DAC_InitStructure); } ADC and DAC are connected with a DMA the config follows next:void DMA1Init()
{ DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_Channel = DMA_Channel_7; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) DAC_DHR12R1_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DAC_Signal; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = 1360; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream5, &DMA_InitStructure); } void DMA2Init() //for ADC { DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = NR_OF_CONVERTED_VALUES; //2500, 2048 needed DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_ITConfig(DMA2_Stream4, DMA_IT_TC | DMA_IT_HT, ENABLE); DMA_Init(DMA2_Stream4, &DMA_InitStructure); } Now I want the DMA2 to tell me when it is finished with the first half, so I now know that the up chirp is sampled. Then he should tell me when it is finished with all the conversion so that I know I can now take the samples of the down chirp. All this takes place in the interrupt routine:void DMA2_Stream4_IRQHandler()
{ GPIO_ToggleBits(LED_PORT, LED_GREEN); uint16_t i = 0; float32_t *pData; uint16_t *pConvertedValues; if(DMA_GetFlagStatus(DMA2_Stream4, DMA_FLAG_HTIF4) == SET) { //UP Chirp if(busyflag == 0) { busyflag = 1; pData=&(fdata_up[0]); pConvertedValues=&(ConvertedValue[CUT_OFF_VALUES-1]); for(i=0; i<LENGTH_SAMPLES; i++) { *pData=(float) *pConvertedValues; pData++; *pData=0; pData++; pConvertedValues++; } } } if(DMA_GetFlagStatus(DMA2_Stream4, DMA_FLAG_TCIF4) == SET) { //DOWN Chirp if(busyflag == 1) { pData = &(fdata_down[0]); pConvertedValues = &(ConvertedValue[(CUT_OFF_VALUES-1)+(NR_OF_CONVERTED_VALUES/2)]); for(i=0; i<LENGTH_SAMPLES; i++) { *pData=(float) *pConvertedValues; pData++; *pData=0; pData++; pConvertedValues++; } busyflag = 2; } } DMA_ClearFlag(DMA2_Stream4, DMA_IT_HT | DMA_IT_TC); DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_HTIF4 | DMA_IT_TCIF4); } This seems to work ok, at least I get two arrays (fdata_up and fdata_down) filled with data and 0's. Now in the main loop I check the busyflag and the I calculate the FFT of them. Right now I am just looking at standing objects, so that I should get two identical or almost identical FFT. But the reality looks different as you will see:int
main(
void)
{ INIT_ALL(); Start(); arm_cfft_radix4_instance_f32 S; arm_status status; while(1)
{ if(busyflag == 2)
{ status = arm_cfft_radix4_init_f32(&S, FFTSIZE, ifftFlag, doBitReverse); arm_cfft_radix4_f32(&S, fdata_up); arm_cmplx_mag_f32(fdata_up, fdataOutput_down, FFTSIZE); send_scope_f(4096, (uint8_t*)fdataOutput_down, 0x92, 2); arm_cfft_radix4_f32(&S, fdata_up); arm_cmplx_mag_f32(fdata_up, fdataOutput_up, FFTSIZE); fdataOutput_up[0] = 0; send_scope_f(4096, (uint8_t*)fdataOutput_up, 0x92, 3); busyflag = 0; } } } As you can see I am then sending my solution via UART to the PC. And here you can see the strange solution. Can you maybe tell me what went wrong here? I have seen some videos of the calculation of the FFT on a STM32f4 and they looked really good. I have no idea why it is doing this strange calculation here. Also if I use the 10kHz test array from the FFT example he is calculating it right first, but the second time it calculates strange stuff. The next time it is right again, after 4 or times though it stops showing me anything. Thank you for your help. If you need further information pls let me know Greets Felix2013-04-15 06:05 AM
The graph you posted is probably the real data from sensor+ corruption of whatever has happened (including during your process). I think you should drop the adc/dac part and replace it with KNOWN values that you know into what they should transform. Then check if your functions are doing OK. This will help you pinpoint the location of problem (maybe even 0 padding causes something weird) as well as it will help you determine if functions have some strange behaviour.
2013-04-15 06:38 AM
I tend to agree with crt's recommendation. Separate both tasks, and test them individually.
I hope you made a rough calculation of timing and performance. I measured about 2.5ms for a 2048 point FFT at 168MHz (without interruption), which gives pretty much of headspace for realtime applications. But what makes me suspicious is you debug function send_scope_f(). I'm sure it takes much longer than the transformation itself, and breaks your timing / cycle. You might need to stop everything (ADC, DMA) during data transfer. I had been using semihosted printf() function (with Crossworks) for my project, which took 5 ... 10 seconds for one transfer all those values.2013-07-22 09:04 AM
Did you have any luck with this? I'm working on a similar project myself and so I'd be interested to hear how you've done.