0
\$\begingroup\$

DISCLAIMER : this question is somehow related to this other question of mine, but the latter did not have any satisfying answer.

I'm working on an audio DSP project with the STM32F4xx, using 4 audio inputs and 1 audio output.

I need to - read each input - process each input's signal, - mix the processed signals together - output the result.

The input is obtained via one of the 3 STM32's internal DACs, 1 channel for each input (ie 4 channels to scan in total) and stored to a buffer using DMA.

The output is converted through a codec using an I2S bus, at 48kHz.

Everytime the codec has finished converting a buffer (or more precisely a half-buffer), it triggers a callback function in which I currently have all the DSP code. In the loop, the output samples are computed and sent to the half-buffer to be output using DMA to I2S.

Granted that I sample my input at the same rate as my output (48kHz which means that my DAC must be clocked at 4*48kHz=192kHz), how can I synchronize the ADC and the DAC conversion?

I have thought of a FIFO inbetween the input and the DSP routine, picking a sample in the queue everytime I need to process one. But I am not sure how to do that when working with chunks of data (a buffer has a depth of 64 samples).

Another solution would be to have an input buffer depth of only 1 sample, and to read this sample in the DSP routine but I am not sure weather this would work.

Does anyone knows what is the best way to do that? Or even better, how to synchronize the STM32's ADC to an external codec?

EDIT: I also thought of using the DAC in "one shot" mode ie triggering a conversion of 64 samples for all the channels everytime my codec raises its "I want samples" flag. Would that work?

EDIT2: Upon request of @Neil_UK, here is an illustrative diagram of what's happening : enter image description here

4 inputs are being sampled by the internal ADC of the STM32. Each must have a sampling rate of 48kHz so, given that the conversion of ADC channels is not done in parallel, that gives us a total scanning frequency of 192kHz (correct me if I'm wrong).

Then, each input's converted samples are stored in a circular buffer of 64 samples each and an interrupt flag is raised every time a half buffer has been filled (ie 32*4 samples have been stored).

On the other side there is a codec which continuously converts samples that are being sent to it via I2S, from the STM32's DMA. There is also an interrupt triggered every time the half I2S buffer has been emptied. Between the 2 there is a DSP routine that is supposed to read the input, filter it and put it in the output buffer.

The problem: I have 2 interrupts:

  • The "I'm done converting" raised by the codec (DAC) ;
  • The "I'm done converting" raised by the internal ADC.

If I scan at 192kHz, these interrupts should at least be in sync (except for some jitter maybe) but the phase can be completely different. That means that I can have my DAC noticing me that all the samples are sent while my ADC is still in the middle of converting the inputs. And this phase difference can potentially be different every time I reset the board, so I can't really compensate it with an offset.

EDIT3 : It seems like the SAI module is a good way to do that, if anyone has experience with SAI I'd love to have some tips and help on how to use it to interface the internal DAC with an external codec

\$\endgroup\$
6
  • \$\begingroup\$ Draw a diagram. You have 3 ADCs, four inputs, one DAC output via I2S. They all have a sample rate that might be either 48k or 192k, but it's not clear which. If, as you imply, you are competent to DMA to a device over I2S, and to read ADCs, and your sample rates are integer multiples of each other, then I am not sure where your difficulty lies. Your filter lengths will put a minimum size on your buffers, your target latency a maximum size, all the rest is just housekeeping to not drop samples and make your code run with no 'off by one' errors. \$\endgroup\$
    – Neil_UK
    Aug 23, 2017 at 6:48
  • 2
    \$\begingroup\$ Hint, if you can't draw that diagram, you don't understand your application and resources enough yet. \$\endgroup\$
    – Neil_UK
    Aug 23, 2017 at 6:49
  • \$\begingroup\$ Doing it right now. It seems like I wasn't clear enough in my OP, I use only 1 of the 3 ADC but 4 of this ADC's channels. Considering that I want each channel sampled at 48k, that gives my an ADC scanning rate of 4*48k = 192kHz. My problem is the phase between the conversions, ie the end_of_conversion flags not being raised at the same moment. EDIT : actually I have to go, I'll edit my post asap \$\endgroup\$
    – Florent
    Aug 23, 2017 at 6:52
  • \$\begingroup\$ @Neil_UK Just added the edit to my OP, sorry that it took time and I hope my problem makes more sense now \$\endgroup\$
    – Florent
    Aug 23, 2017 at 23:21
  • \$\begingroup\$ What's the acceptable delay between input and output? Are you processing data byte by byte, or in chunks? \$\endgroup\$
    – Andrés
    Feb 25, 2018 at 20:37

1 Answer 1

0
\$\begingroup\$

There's no good way to do this via the onboard ADC / DAC. You'd have to trigger the DAC conversion in the ADC interrupt, but you wouldn't be able to get the rates set correctly when using DMA so you'd have to go sample by sample. There's a lot of overhead to that and while it could work it wouldn't leave you with a whole lot of CPU left over for the DSP.

The better solution is to use the I2S or SAI interface with a dedicated audio codec. You can either use two codecs or get a codec that has both input and output capability.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for your answer! I ended up putting a FIFO between the ADC and the DSP routine and it worked fine... \$\endgroup\$
    – Florent
    Oct 16, 2017 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.