Skip to main content
Graduate
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();
 }
    This topic has been closed for replies.
    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_OmAnswer
    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
     }
    }

     

    cbcooperAuthor
    Graduate
    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. 

     

    Graduate II
    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.