CMSIS real-FFT on 8192 samples in Q15

3.7k views Asked by At

I need to perform an FFT on a block of 8192 samples on an STM32F446 microcontroller. For that I wanted to use the CMSIS DSP library as it's available easily and optimised for the STM32F4.

My 8192 samples of input will ultimately be values from the internal 12-bit ADC (left aligned and converted to q15 by flipping the sign bit)., but for testing purpose I'm feeding the FFT with test-buffers.

With CMSIS's FFT functions, only the Q15 version supports lengths of 8192. Thus I am using arm_rfft_q15().

Because the FFT functions of the CMSIS libraries include by default about 32k of LUTs - to adapt to many FFT lengths, I have "rewritten" them to remove all the tables corresponding to other length than the one I'm interested in. I haven't touched anything except removing the useless code.

My samples are stored on an external SDRAM that I access via DMA.

When using the FFT, I have several problems :

  • Both my source buffer and my destination buffer get modified ;
  • the result is not at all as expected

To make sure I had wrong results I did an IFFT right after the FFT but it just confirmed that the code wasn't working.

Here is my code :

status_codes FSM::fft_state(void)
{
  // Flush the SDRAM section
  si_ovf_buf_clr_u16((uint16_t *)0xC0000000, 8192);
  q15_t* buf = (q15_t*)(0xC0000000);
  for(int i = 0; i<50; i++)
    buf[i] = 0x0FFF; // Fill the buffer with test vector (50 sp gate)

  // initialise FFT
  // ---> Forward, 8192 samples, bitReversed
  arm_rfft_instance_q15 S;
  if(arm_rfft_init_q15(&S, 8192, 0, 1) != ARM_MATH_SUCCESS)
    return state_error;

  // perform FFT
  arm_rfft_q15(&S, (q15_t*)0xC0000000, (q15_t*)0xC0400000);

  // Post-shift by 12, in place (see doc)
  arm_shift_q15((q15_t*)0xC0400000, 12, (q15_t*)0xC0400000, 16384);

  // Init inverse FFT
  if(arm_rfft_init_q15(&S, 8192, 1, 1) != ARM_MATH_SUCCESS)
    return state_error;

  // Perform iFFT
  arm_rfft_q15(&S, (q15_t*)0xC0400000, (q15_t*)0xC0800000);

  // Post shift
  arm_shift_q15((q15_t*)0xC0800000, 12, (q15_t*)0xC0800000, 8192);

  return state_success;
}

And here is the result (from GDB)

GDB result

PS : I'm using ChibiOS - not sure if it is relevant.

0

There are 0 answers