Skip to main content
XPach.1
Visitor II
November 19, 2020
Question

Double buffering with HT and TC interrupts [STM32G0], how to handle them.

  • November 19, 2020
  • 1 reply
  • 889 views

I'm trying to build a double buffer (or ping pong buffer) using the HT (Half transfer) and TC (Transfer complete) interrupts. Also, I'm using DMA with circular array and ADC is triggered by a timer at 6 kHz. I have the algorithm below (I'm not showing all of the initializations). I know I'm doing something wrong so I appreciate any guidance. The problem I'm facing is kind of like a race condition. When checking if (half_complete == 1 && transfer_complete == 0)

both flags are already active so this condition is not going happen. It seems both interrupts happen too quick so both flags are like fighting.

#define ADC_BUF_SIZE 216
volatile uint16_t ADC_buffer[ADC_BUF_SIZE];
volatile int16_t transfer_complete = 0;
volatile int16_t half_complete = 0;
volatile int32_t array_average = 0;
 
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_buffer, ADC_BUF_SIZE);
 
while (1)
 { 
 if (half_complete == 1 && transfer_complete == 0){
 array_average = array_avg (ADC_buffer, 108);
 half_complete = 0;
 }
 else if (transfer_complete == 1 && half_complete == 0){
 array_average = array_avg (ADC_buffer, 216);
 transfer_complete = 0;
 }
}
 
/*Conversion DMA half-transfer callback in non-blocking mode.*/
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc){
 half_complete = 1;
}
 
/*Conversion complete callback in non-blocking mode.*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
 transfer_complete = 1;
}
 
/*Average function */
uint32_t array_avg (volatile uint16_t buffer[], uint16_t size){
 
 uint32_t sum = 0;
 if (half_complete == 1) {
 for (int x = 0; x < size; x++) {
 sum += buffer [x];
 }
 }
 if (transfer_complete == 1){
 for (int x = 108; x < size; x++) {
 sum += buffer [x];
 }
 }
 return sum/(int32_t)size;
 
}

This topic has been closed for replies.

1 reply

KnarfB
Super User
November 19, 2020

just few remarks:

when HAL_ADC_ConvCpltCallback fires, only the 2nd half of the buffer should be processed ( array_avg (ADC_buffer+108, 108); )

if it is only little processing like summing up values, you could do that simply in the callbacks. Using a low priority in the NVIC, processing will not disturb higher prio interrupts.

try debugging by tracing, .i.e. print out what happens when. You might redirect easily printf to ITM_sendChar and use SWO for logging.

it always starts with using volatile variables for sync. If you are planning a more compley app, consider using FreeRTOS with queues and deferred task processing