2020-11-18 08:38 PM
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;
}
2020-11-19 01:16 AM
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