cancel
Showing results for 
Search instead for 
Did you mean: 

Best way to sample ADC at 48kHz for buffer manipulations (FFT, etc)?

NNagy.1
Senior

I'm trying to make a guitar pedal using the ADC on my F767ZI. I want to be able to perform an FFT and other functions on a buffer of data sampled at 48kHz.

I wanted to use the ADC DMAs and use the equation Tconv = 12.5cycles + SampleTime, but I have not been able to generate an exact PCLK rate in CubeMX to get the ADC sample rate at 48kHz precisely.

Am I better of using a 48kHz timer interrupt to read a sample from the DMA(?) and using some sort of global FIFO buffer? I worry that that might be overkill but at least I would know the sample rate is accurate.

16 REPLIES 16
MM..1
Chief II

When you not send or store , then 48k isnt critical. DMA is way to store , timer is trigger for sample, this two thinks is independent.

You setup DMA buffer size and on half complete interrupts start calculate FFT for half ready buffer data...

KnarfB
Principal III

So basically HAL_ADC_ConvCpltCallback would get called every 10 Hz in that example?

I see, so when I'm calculating FFT, instead of using fs=48kHz, I would just use whatever sample rate the ADC/DMA is using?

KnarfB
Principal III

The example is not really for audio. If you set the timer trigger event to 48 kHz and convert 1 ADC channel at each event, setup a larger buffer of say 20ms duration which are 9600 samples. Activate both, HAL_ADC_ConvHalfCpltCallback and HAL_ADC_ConvCpltCallback. This gives you 10ms time for (CPU) processing the half of the buffer just completed while the circular DMA writes new data to the other half. You may adjust the buffer size to your needs, e.g. doing a 4096 point FFT etc.

hth

KnarfB

KnarfB
Principal III

here is a nice video on the topic: https://youtu.be/acJ_kSEU0V0

That makes sense - thank you for the help!

in part 2 of the video @22:06 you see glitches in the yellow output waveform. This is because he is calling processDSP() continuously in the main loop. This is wrong. See also the video comments. You better call it excatly once for every (half)buffer. This can be acomplished by setting inbufPtr = NULL; at the end of processDSP() and poll in the main loop for inbufPtr != NULL. This is a crude form of synchronisation by using a global volatile variable. Depending on how complex your overall code is (GUI?,...) you might even use FreeRTOS for multitasking and queues for synchronization...

hth

KnarfB

Hi, KnarfB ,

> This is a crude form of synchronisation by using a global volatile variable.

How would you make it neat and elegant?

JW

@KnarfB​