3
votes

I am using a stm32f3 discovery board and the HAL from CubeMX. I am trying to use 2 ADC channels at ADC4. I configured DMA in circular mode. Befor the main loop in main, I call:

HAL_ADC_Start_DMA(&hadc4, DMA_adc4_buffer, 16);

I implemented the functions HAL_ADC_ConvHalfCpltCallback and HAL_ADC_ConvCpltCallback. Now the strange part: HAL_ADC_ConvHalfCpltCallback is called regularly, HAL_ADC_ConvCpltCallback is NOT.

It tells me, that the ADC with DMA transfer is running fine. But why is transfer compete callback not called? If I start the ADC with HAL_ADC_Start_IT the interrupt function is called, but that is not what I want.

Putting breakpoints in HAL_DMA_IRQHandlerin the ST HAL also shows, that the callback is never called.

For completeness here parts of the ADC4_Init function:

/**Common config 
*/
hadc4.Instance = ADC4;
hadc4.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc4.Init.Resolution = ADC_RESOLUTION_12B;
hadc4.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc4.Init.ContinuousConvMode = ENABLE;
hadc4.Init.DiscontinuousConvMode = DISABLE;
hadc4.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc4.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc4.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc4.Init.NbrOfConversion = 2;
hadc4.Init.DMAContinuousRequests = ENABLE;
hadc4.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc4.Init.LowPowerAutoWait = DISABLE;
hadc4.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Thank your for ideas.

1
No channel configuration & no DMA configuration, so how you think it will work.0___________
I just did something similar with the DMA but in relation to the CRC. When you set the call back for the interrupt you have to choose which event you want the call back for. For me I wanted completed, so in the call back request I used HAL_DMA_XFER_CPLT_CB_ID. Initially I just put a one in there and got called back half way through the DMA!user50619

1 Answers

5
votes

The problem was that the clock of the ADC was 48 MHz, the core clock only 12 MHz. The function HAL_DMA_IRQHandler checks frst for the interrupt flag for half transfer complete, then for transfer complete in the style

if (half transfer complete){
  HAL_ADC_ConvHalfCpltCallback();
} **ELSE** if (transfer complete){
  HAL_ADC_ConvCpltCallback();
}

Since half transfer interrupt flag is always set so fast by the ADC / DMA and the processor is so slow, the core never comes to the seconds ìfbranch and thus never calls the ConvCpltCallback().