cancel
Showing results for 
Search instead for 
Did you mean: 

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

XPach.1
Associate

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;
 
}

1 REPLY 1
KnarfB
Principal III

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