cancel
Showing results for 
Search instead for 
Did you mean: 

Help needed with Multi-channel DMA on love audio to DAC using DMA

josro09
Associate II

Hello,

I am trying to use the STM32G491RE nucleo to create a DSP for live audio in the voice band range. Right now I'm just focused on trying to get data in at the ADC using timer 7 to pull data from the ADC at an 8Khz sample rate as I don't want to sample for audio above 4Khz. I'm using a double buffer technique to pull data in transferring using the DMA and just simply pass it along to the DAC. I wanted to ensure I'm not losing signal integrity before trying to perform any signal processing. Since I'm using multiple channels on the ADC, the HAL_ADC_ConvCpltCallback() function will only pull one sample at a time for each channel. Currently I am only pulling data from one channel but eventually will scale it to 8 or more once I get it working on one channel. Once scan conversion is complete I store these samples in a buffer, no signal processing at this point, and once I have half the array filled with samples I send it to DAC for output. I tried both double buffering and no buffering method i.e. just fill up the array with 64 samples and send it to DAC, and I get the same result. The result is audio sent be to the sampled by the ADC channel 1 on PA0 and output to the DAC sounds very muffled, static filled, and choppy. So I am getting some data out that comes into the ADC but it appears maybe not all and it's highly distorting the original signal by the time it gets to DAC output. I've tried researching what I may be doing wrong to lose signal integrity, but there are not a lot of resources I can find for my specific case of using multi-channel ADC, with Timer and DMA on live audio. I will attach IOC file and main.c file, if more information is needed to assess the problem, please let me know. There is syntax for a low-pass filter but is commented out for now until I can figure out how to not lose signal integrity. Any assistance would be greatly appreciated. Thanks STM community.

Additional note, here is where most of the work I'm talking about is happening:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    filt_in1[buffCount] = (float32_t)adc_ConvertedVals[0];
    filt_in2[buffCount] = (float32_t)adc_ConvertedVals[1];
    buffCount++;
    if(buffCount == (N/2)){
        //arm_fir_f32(&filter1, filt_in_ptr1, output_arr1, N);
        for(int i = 0; i < buffCount; i++){
            DAC_Buffer[i] = filt_in1[i];
        }
    }
    if(buffCount == N){
        //arm_fir_f32(&filter1, filt_in_ptr1, output_arr1, N);
        for(int i = (N/2); i < buffCount; i++){
            DAC_Buffer[i] = filt_in1[i];
        }
        buffCount = 0;
    }
}



5 REPLIES 5

The .c file you've attached is different from your description.

But try something simpler first: instead of moving ADC samples into DAC buffer, in the ADC interrupt, just fill the DAC buffer with content of a global variable which you increment by an appropriate constant after each sample. You should then see a nice sawtooth output on the DAC pin.

Then try moving raw ADC samples into DAC, without any processing (i.e. without conversion to float). You should see copy of input on output.

Is your ADC and DAC sampling rate identical? How do you ensure that?

JW

Hi,

Sorry about the wrong main.c file, I've attached the correct one to this. Timer 7 triggers the conversions, then fills a temporary buffer I've labeled "filt_in1", aside from pulling the converted data, everything is run off the timing of the 

ConvCpltCallback function. My if statements check how much of the buffer is full, once a certain amount is reached it will push that data into the DAC buffer for processing. So the input from the ADC is on timer 7 but the movement of data is on ConvCpltCallback both from the ADC to DAC.

Have you tried generating sawtooth and other basic experiments, as I recommended above?

Note, that moving data around may take longer time than the conversion itself, resulting in overruns. In fact, using Cube/HAL and low level of optimization in compiler may result in the interrupt service (ISR) including the callback take more than the conversion itself.

JW

 

So after testing using a signal generator and oscilloscope, I'm actually losing half my data due to the onboard ADC not converting any negative values from the analog input wave. This makes sense as the ADC will only convert from positive values. This means I need to add a DC bias of maybe 2.5V. I can do this offboard but the STM32G4 can run the ADC in differential mode which allows me to add the DC offset onboard, although I'm not sure how to set it up correctly and trying to research it for the time being. Thank for your assistance so far.

> STM32G4 can run the ADC in differential mode which allows me to add the DC offset onboard

Not in your case.

You still can't have negative input on any pin, there are protection diodes there (as reflected by the Absolute Maximum values).

Also, the common-mode voltage may be only some +-150mV from VREF+/2.

JW