1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ so you've modified the library code, and now it doesn't run? Hmmmm. Does it run before your modifications? Do you have the storage to run it 'as is' at all, as a test (I know you don't want it to be that big in deployment)? \$\endgroup\$ – Neil_UK Sep 11 '17 at 5:54
  • \$\begingroup\$ No that's the thing, if I don't remove all the tables that I'm not using it doesn't run. So I have just copied the original code, remove every table that was F32 or Q31, and in the init_fft function I have trimmed the switch statement to only the 8192 case. Do you think I might have removed something vital? it compiles fine \$\endgroup\$ – Florent Sep 11 '17 at 5:56
  • \$\begingroup\$ ps: I can provide a link to the trimmed functions if necessary (copying and pasting here would be too big for SE) \$\endgroup\$ – Florent Sep 11 '17 at 5:57
  • \$\begingroup\$ so to clarify, it doesn't run, even if you use it as it was, out of the box? If so, you should first try to understand how to get the code running before your modifications. Once you have a working stable platform, then muck about with it. \$\endgroup\$ – Neil_UK Sep 11 '17 at 5:57
  • \$\begingroup\$ @Neil_UK More precisely : out of the box it doesn't compile because of code size, after modification it runs but gives strange results. \$\endgroup\$ – Florent Sep 11 '17 at 5:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.