What is the best method of taking multiple measurements using ADC+DMA interrupts and averaging them? Currently I have an STM32F303 with ADC2 initialized with channels 3 and 18 (Vrefint). My aim is to take 16 measurements and then average the result. I need to take these measurements with a relatively low frequency and for this test I've set up main to trigger the ADC DMA conversion every 250ms. The problems I have are:

• What is the best method of sharing data between the interrupt handler and the main loop
• How to ensure interrupt is not triggered after 16 times

Part of my code is below. The ADC/DMA callback function is supposed to trigger the next conversion 16 times and then signal to the main loop via a flag that the conversion is complete. I can see the callback being called and the ADC conversion performed; measurements are correct.

// ADC Data structure, also accessed by ADC callback
}

int main(void) {

// Initialize peripherals
HAL_Init();
SystemClock_Config();
MX_DMA_Init();
MX_OPAMP2_Init();
MX_GPIO_Init();
MX_USART2_UART_Init();
HAL_OPAMP_Start( & hopamp2);

while (1) {

HAL_Delay(250);

}

}
}

static uint32_t conv_count = 0;
static uint32_t temp_vrefint_value = 0;

if (++conv_count == 16) {
conv_count = 0;
temp_vrefint_value = 0;
} else {
}

}

return (3.3 * data - > adc_value_vrefint_register * data - > adc_value_channel_3) / (data - > adc_value_vrefint_channel * 4095);
}


***********************************EDIT*******************************

I've modified the ADC initialization to allow continuous conversion (for 3 channels) and trigger an interrupt at the end of sequence conversion: static void MX_ADC2_Init(void) { ADC_ChannelConfTypeDef sConfig = {0};

  hadc2.Instance = ADC2;

{
Error_Handler();
}

sConfig.Offset = 0;
{
Error_Handler();
}

sConfig.Offset = 0;
{
Error_Handler();
}

sConfig.Offset = 0;
{
Error_Handler();
}

// Calibration
}


The conversion is started with HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc_buffer, 48);. The interrupt callback is called when the buffer is filled with 48 samples (3 samples from each channel), and it sets a flag, which is then polled and reset from another function:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
}


Then in the polling function I loop through the filled buffer and average its contents for each of the three channels:

adc_data.adc_value_channel_3 = 0;

for (int x = 0; x < 16; x++) {
}

// Averaging by shifting each value to the right by 4 places...

• Well don't do your averaging math in ISR. OTTOMH STM32 family push/pop 4 registers automatically, but you have code that probably requires more than 4, so for 15 of 16 interrupts extra registers are pushed/popped. Use your flag to do calculate average. – StainlessSteelRat Nov 4 at 13:11
• As the answer suggests, use DMA to transfer data from ADC to memory buffer. DMA finishes, generate interrupt. Interrupt, do math, reprogram DMA. – StainlessSteelRat Nov 4 at 16:54
• The best way is to use RTOS. It has all needed sync and inter process communications features built in – P__J__ Nov 5 at 11:55

Since you already have DMA initialized, why don't you use that? Pass in a memory pointer, poll for conversion done or signal from your interrupt:

in main function:

while (data_count-- > 0) {