Skip to main content
Senior
May 16, 2025
Solved

HAL_ADC_ConvCpltCallback only gets called once

  • May 16, 2025
  • 3 replies
  • 437 views

I'm setting up the ADC in "manual continuous" mode where hadc1.Init.ContinuousConvMode = DISABLE and then I call HAL_ADC_Start_IT() inside of HAL_ADC_ConvCpltCallback().  I get the first call to HAL_ADC_ConvCpltCallback and calling HAL_ADC_Start_IT() returns HAL_OK but the callback never gets called again.

What am I missing?

Thanks,

Chris

 ADC_MultiModeTypeDef multimode = {0};
 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Common config
 */
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.GainCompensation = 0;
 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.NbrOfConversion = 1;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.DMAContinuousRequests = DISABLE;
 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc1.Init.OversamplingMode = DISABLE;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure the ADC multi-mode
 */
 multimode.Mode = ADC_MODE_INDEPENDENT;
 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_1;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
Best answer by Saket_Om

Hello @cbcooper 

It's better to handle the ADC conversion restart in the main loop, as shown in the example below: 

// Global variable to indicate ADC conversion completion
volatile uint8_t adcConversionComplete = 0;
// ADC handle declaration
ADC_HandleTypeDef hadc1;

// Callback function for ADC conversion complete
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
 // Set the flag to indicate conversion is complete
 adcConversionComplete = 1;
}

int main(void) {
 // HAL initialization
 HAL_Init();

 // ADC configuration (assuming hadc1 is properly configured elsewhere)
 // ...

 // Start ADC conversion in interrupt mode
 HAL_ADC_Start_IT(&hadc1);

 // Main loop
 while (1) {
 // Check if ADC conversion is complete
 if (adcConversionComplete) {
 // Reset the flag
 adcConversionComplete = 0;

 // Process the ADC data
 uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
 // Use adcValue as needed

 // Restart ADC conversion in interrupt mode
 HAL_ADC_Start_IT(&hadc1);
 }

 // Other tasks can be performed here
 }
}

 

3 replies

Saket_OmBest answer
Technical Moderator
May 17, 2025

Hello @cbcooper 

It's better to handle the ADC conversion restart in the main loop, as shown in the example below: 

// Global variable to indicate ADC conversion completion
volatile uint8_t adcConversionComplete = 0;
// ADC handle declaration
ADC_HandleTypeDef hadc1;

// Callback function for ADC conversion complete
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
 // Set the flag to indicate conversion is complete
 adcConversionComplete = 1;
}

int main(void) {
 // HAL initialization
 HAL_Init();

 // ADC configuration (assuming hadc1 is properly configured elsewhere)
 // ...

 // Start ADC conversion in interrupt mode
 HAL_ADC_Start_IT(&hadc1);

 // Main loop
 while (1) {
 // Check if ADC conversion is complete
 if (adcConversionComplete) {
 // Reset the flag
 adcConversionComplete = 0;

 // Process the ADC data
 uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
 // Use adcValue as needed

 // Restart ADC conversion in interrupt mode
 HAL_ADC_Start_IT(&hadc1);
 }

 // Other tasks can be performed here
 }
}

 

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question.Saket_Om"
cbcooperAuthor
Senior
May 19, 2025

That works but why?  I would much rather not have the ISR wait for the main code to get around to looking at the value before it starts acquiring the next. 

 

Karl Yamashita
Principal
May 19, 2025

You don't want to keep calling HAL_ADC_Start_IT directly from the callback as this would cause a lot of overhead and your other interrupts with lower priority will not be able to interrupt. And also your main while loop will not be able to run reliably as well.

So, do as @Saket_Om mentions or use a timer interrupt to start the ADC conversion.

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source